001/* 002 * Copyright (c) 2012-2018 Institut National des Sciences Appliquées de Lyon (INSA Lyon) and others 003 * 004 * This program and the accompanying materials are made available under the 005 * terms of the Eclipse Public License 2.0 which is available at 006 * http://www.eclipse.org/legal/epl-2.0. 007 * 008 * SPDX-License-Identifier: EPL-2.0 009 */ 010 011package gololang; 012 013/** 014 * A dynamic variable has the semantics of an inheritable thread-local reference. 015 * This class is modeled after the eponymous class from the Scala standard library. 016 * 017 * @see java.lang.InheritableThreadLocal 018 */ 019public final class DynamicVariable { 020 021 private final InheritableThreadLocal<Object> threadLocal; 022 023 /** 024 * Creates a new dynamic variable with an initial value. 025 * 026 * @param init the initial value. 027 */ 028 public DynamicVariable(final Object init) { 029 super(); 030 threadLocal = new InheritableThreadLocal<Object>() { 031 @Override 032 protected Object initialValue() { 033 return init; 034 } 035 }; 036 } 037 038 /** 039 * Returns the thread-local value of the dynamic variable. 040 * 041 * @return the value. 042 */ 043 public Object value() { 044 return threadLocal.get(); 045 } 046 047 /** 048 * Changes the dynamic variable value. The new value is only visible from the calling thread, and will be seen by 049 * future child threads. 050 * 051 * @param value the new thread-local value. 052 * @return this dynamic variable. 053 */ 054 public DynamicVariable value(Object value) { 055 threadLocal.set(value); 056 return this; 057 } 058 059 /** 060 * Given a value, calls a function {@code func}. The previous value is put pack as the dynamic variable value 061 * once {@code func} has completed. 062 * 063 * @param value the value for the course of the execution of {@code func}. 064 * @param func a 0-arity function. 065 * @return the result of the call to {@code func}. 066 * @throws Throwable in case an exception occurs. 067 */ 068 public Object withValue(Object value, FunctionReference func) throws Throwable { 069 if (!func.acceptArity(0)) { 070 throw new IllegalArgumentException("withValue requires a function with no parameters"); 071 } 072 Object oldValue = value(); 073 this.value(value); 074 try { 075 return func.invoke(); 076 } finally { 077 this.value(oldValue); 078 } 079 } 080 081 @Override 082 public String toString() { 083 return String.format("DynamicVariable{value=%s}", value()); 084 } 085}