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 }