1 //
2 // ========================================================================
3 // Copyright (c) 1995-2013 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 }