]> WPIA git - gigi.git/blob - lib/jetty/org/eclipse/jetty/util/ForkInvoker.java
Update notes about password security
[gigi.git] / lib / jetty / org / eclipse / jetty / util / ForkInvoker.java
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
19 package org.eclipse.jetty.util;
20
21 /**
22  * Utility class that splits calls to {@link #invoke(Object)} into calls to {@link #fork(Object)} or {@link #call(Object)}
23  * depending on the max number of reentrant calls to {@link #invoke(Object)}.
24  * <p/>
25  * This class prevents {@link StackOverflowError}s in case of methods that end up invoking themselves,
26  * such is common for {@link Callback#succeeded()}.
27  * <p/>
28  * Typical use case is:
29  * <pre>
30  * public void reentrantMethod(Object param)
31  * {
32  *     if (condition || tooManyReenters)
33  *         fork(param)
34  *     else
35  *         call(param)
36  * }
37  * </pre>
38  * Calculating {@code tooManyReenters} usually involves using a {@link ThreadLocal} and algebra on the
39  * number of reentrant invocations, which is factored out in this class for convenience.
40  * <p />
41  * The same code using this class becomes:
42  * <pre>
43  * private final ForkInvoker invoker = ...;
44  *
45  * public void reentrantMethod(Object param)
46  * {
47  *     invoker.invoke(param);
48  * }
49  * </pre>
50  *
51  */
52 public abstract class ForkInvoker<T>
53 {
54     private static final ThreadLocal<Integer> __invocations = new ThreadLocal<Integer>()
55     {
56         @Override
57         protected Integer initialValue()
58         {
59             return 0;
60         }
61     };
62     private final int _maxInvocations;
63
64     /**
65      * Creates an instance with the given max number of reentrant calls to {@link #invoke(Object)}
66      * <p/>
67      * If {@code maxInvocations} is zero or negative, it is interpreted
68      * as if the max number of reentrant calls is infinite.
69      *
70      * @param maxInvocations the max number of reentrant calls to {@link #invoke(Object)}
71      */
72     public ForkInvoker(int maxInvocations)
73     {
74         _maxInvocations = maxInvocations;
75     }
76
77     /**
78      * Invokes either {@link #fork(Object)} or {@link #call(Object)}.
79      * If {@link #condition()} returns true, {@link #fork(Object)} is invoked.
80      * Otherwise, if the max number of reentrant calls is positive and the
81      * actual number of reentrant invocations exceeds it, {@link #fork(Object)} is invoked.
82      * Otherwise, {@link #call(Object)} is invoked.
83      * @param arg TODO
84      *
85      * @return true if {@link #fork(Object)} has been called, false otherwise
86      */
87     public boolean invoke(T arg)
88     {
89         boolean countInvocations = _maxInvocations > 0;
90         int invocations = __invocations.get();
91         if (condition() || countInvocations && invocations > _maxInvocations)
92         {
93             fork(arg);
94             return true;
95         }
96         else
97         {
98             if (countInvocations)
99                 __invocations.set(invocations + 1);
100             try
101             {
102                 call(arg);
103                 return false;
104             }
105             finally
106             {
107                 if (countInvocations)
108                     __invocations.set(invocations);
109             }
110         }
111     }
112
113     /**
114      * Subclasses should override this method returning true if they want
115      * {@link #invoke(Object)} to call {@link #fork(Object)}.
116      *
117      * @return true if {@link #invoke(Object)} should call {@link #fork(Object)}, false otherwise
118      */
119     protected boolean condition()
120     {
121         return false;
122     }
123
124     /**
125      * Executes the forked invocation
126      * @param arg TODO
127      */
128     public abstract void fork(T arg);
129
130     /**
131      * Executes the direct, non-forked, invocation
132      * @param arg TODO
133      */
134     public abstract void call(T arg);
135 }