1//
2//  ========================================================================
3//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
4//  ------------------------------------------------------------------------
5//  All rights reserved. This program and the accompanying materials
6//  are made available under the terms of the Eclipse Public License v1.0
7//  and Apache License v2.0 which accompanies this distribution.
8//
9//      The Eclipse Public License is available at
10//      http://www.eclipse.org/legal/epl-v10.html
11//
12//      The Apache License v2.0 is available at
13//      http://www.opensource.org/licenses/apache2.0.php
14//
15//  You may elect to redistribute this code under either of these licenses.
16//  ========================================================================
17//
18
19package org.eclipse.jetty.server.handler;
20
21import java.io.IOException;
22
23import javax.servlet.ServletException;
24import javax.servlet.http.HttpServletRequest;
25import javax.servlet.http.HttpServletResponse;
26
27import org.eclipse.jetty.server.Request;
28
29
30/* ------------------------------------------------------------ */
31/** ScopedHandler.
32 *
33 * A ScopedHandler is a HandlerWrapper where the wrapped handlers
34 * each define a scope.   When {@link #handle(String, Request, HttpServletRequest, HttpServletResponse)}
35 * is called on the first ScopedHandler in a chain of HandlerWrappers,
36 * the {@link #doScope(String, Request, HttpServletRequest, HttpServletResponse)} method is
37 * called on all contained ScopedHandlers, before the
38 * {@link #doHandle(String, Request, HttpServletRequest, HttpServletResponse)} method
39 * is called on all contained handlers.
40 *
41 * <p>For example if Scoped handlers A, B & C were chained together, then
42 * the calling order would be:<pre>
43 * A.handle(...)
44 *   A.doScope(...)
45 *     B.doScope(...)
46 *       C.doScope(...)
47 *         A.doHandle(...)
48 *           B.doHandle(...)
49 *              C.doHandle(...)
50 * <pre>
51 *
52 * <p>If non scoped handler X was in the chained A, B, X & C, then
53 * the calling order would be:<pre>
54 * A.handle(...)
55 *   A.doScope(...)
56 *     B.doScope(...)
57 *       C.doScope(...)
58 *         A.doHandle(...)
59 *           B.doHandle(...)
60 *             X.handle(...)
61 *               C.handle(...)
62 *                 C.doHandle(...)
63 * <pre>
64 *
65 * <p>A typical usage pattern is:<pre>
66 *     private static class MyHandler extends ScopedHandler
67 *     {
68 *         public void doScope(String target, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
69 *         {
70 *             try
71 *             {
72 *                 setUpMyScope();
73 *                 super.doScope(target,request,response);
74 *             }
75 *             finally
76 *             {
77 *                 tearDownMyScope();
78 *             }
79 *         }
80 *
81 *         public void doHandle(String target, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
82 *         {
83 *             try
84 *             {
85 *                 doMyHandling();
86 *                 super.doHandle(target,request,response);
87 *             }
88 *             finally
89 *             {
90 *                 cleanupMyHandling();
91 *             }
92 *         }
93 *     }
94 * </pre>
95 */
96public abstract class ScopedHandler extends HandlerWrapper
97{
98    private static final ThreadLocal<ScopedHandler> __outerScope= new ThreadLocal<ScopedHandler>();
99    protected ScopedHandler _outerScope;
100    protected ScopedHandler _nextScope;
101
102    /* ------------------------------------------------------------ */
103    /**
104     * @see org.eclipse.jetty.server.handler.HandlerWrapper#doStart()
105     */
106    @Override
107    protected void doStart() throws Exception
108    {
109        try
110        {
111            _outerScope=__outerScope.get();
112            if (_outerScope==null)
113                __outerScope.set(this);
114
115            super.doStart();
116
117            _nextScope= (ScopedHandler)getChildHandlerByClass(ScopedHandler.class);
118
119        }
120        finally
121        {
122            if (_outerScope==null)
123                __outerScope.set(null);
124        }
125    }
126
127
128    /* ------------------------------------------------------------ */
129    /*
130     */
131    @Override
132    public final void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
133    {
134        if (_outerScope==null)
135            doScope(target,baseRequest,request, response);
136        else
137            doHandle(target,baseRequest,request, response);
138    }
139
140    /* ------------------------------------------------------------ */
141    /*
142     * Scope the handler
143     */
144    public abstract void doScope(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response)
145        throws IOException, ServletException;
146
147    /* ------------------------------------------------------------ */
148    /*
149     * Scope the handler
150     */
151    public final void nextScope(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response)
152        throws IOException, ServletException
153    {
154        // this method has been manually inlined in several locations, but
155        // is called protected by an if(never()), so your IDE can find those
156        // locations if this code is changed.
157        if (_nextScope!=null)
158            _nextScope.doScope(target,baseRequest,request, response);
159        else if (_outerScope!=null)
160            _outerScope.doHandle(target,baseRequest,request, response);
161        else
162            doHandle(target,baseRequest,request, response);
163    }
164
165    /* ------------------------------------------------------------ */
166    /*
167     * Do the handler work within the scope.
168     */
169    public abstract void doHandle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response)
170        throws IOException, ServletException;
171
172    /* ------------------------------------------------------------ */
173    /*
174     * Do the handler work within the scope.
175     */
176    public final void nextHandle(String target, final Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
177    {
178        // this method has been manually inlined in several locations, but
179        // is called protected by an if(never()), so your IDE can find those
180        // locations if this code is changed.
181        if (_nextScope!=null && _nextScope==_handler)
182            _nextScope.doHandle(target,baseRequest,request, response);
183        else if (_handler!=null)
184            _handler.handle(target,baseRequest, request, response);
185    }
186
187    /* ------------------------------------------------------------ */
188    protected boolean never()
189    {
190        return false;
191    }
192
193}
194