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.
9 // The Eclipse Public License is available at
10 // http://www.eclipse.org/legal/epl-v10.html
12 // The Apache License v2.0 is available at
13 // http://www.opensource.org/licenses/apache2.0.php
15 // You may elect to redistribute this code under either of these licenses.
16 // ========================================================================
19 package org.eclipse.jetty.util;
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)}.
25 * This class prevents {@link StackOverflowError}s in case of methods that end up invoking themselves,
26 * such is common for {@link Callback#succeeded()}.
28 * Typical use case is:
30 * public void reentrantMethod(Object param)
32 * if (condition || tooManyReenters)
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.
41 * The same code using this class becomes:
43 * private final ForkInvoker invoker = ...;
45 * public void reentrantMethod(Object param)
47 * invoker.invoke(param);
52 public abstract class ForkInvoker<T>
54 private static final ThreadLocal<Integer> __invocations = new ThreadLocal<Integer>()
57 protected Integer initialValue()
62 private final int _maxInvocations;
65 * Creates an instance with the given max number of reentrant calls to {@link #invoke(Object)}
67 * If {@code maxInvocations} is zero or negative, it is interpreted
68 * as if the max number of reentrant calls is infinite.
70 * @param maxInvocations the max number of reentrant calls to {@link #invoke(Object)}
72 public ForkInvoker(int maxInvocations)
74 _maxInvocations = maxInvocations;
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.
85 * @return true if {@link #fork(Object)} has been called, false otherwise
87 public boolean invoke(T arg)
89 boolean countInvocations = _maxInvocations > 0;
90 int invocations = __invocations.get();
91 if (condition() || countInvocations && invocations > _maxInvocations)
99 __invocations.set(invocations + 1);
107 if (countInvocations)
108 __invocations.set(invocations);
114 * Subclasses should override this method returning true if they want
115 * {@link #invoke(Object)} to call {@link #fork(Object)}.
117 * @return true if {@link #invoke(Object)} should call {@link #fork(Object)}, false otherwise
119 protected boolean condition()
125 * Executes the forked invocation
128 public abstract void fork(T arg);
131 * Executes the direct, non-forked, invocation
134 public abstract void call(T arg);