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