001: /*
002: * Javolution - Java(TM) Solution for Real-Time and Embedded Systems
003: * Copyright (C) 2006 - Javolution (http://javolution.org/)
004: * All rights reserved.
005: *
006: * Permission to use, copy, modify, and distribute this software is
007: * freely granted, provided that this notice is preserved.
008: */
009: package javolution.context;
010:
011: import javolution.util.FastMap;
012:
013: /**
014: * <p> This class represents a context to define locally scoped environment
015: * settings. This settings are held by {@link LocalContext.Reference}
016: * and typically wrapped within a static method:[code]
017: * LocalContext.enter();
018: * try {
019: * ModuloInteger.setModulus(m); // Performs integer operations modulo m.
020: * Length.showAs(NonSI.INCH); // Shows length in inches.
021: * RelativisticModel.select(); // Uses relativistic physical model.
022: * ... // Operations performed using local settings.
023: * } finally {
024: * LocalContext.exit(); // Reverts to previous settings.
025: * }[/code]</p>
026: *
027: * <p> Calls to locally scoped methods should be performed either at
028: * start-up (global setting) or within a local context (to avoid
029: * impacting other threads).</p>
030: *
031: * <p> As for any context, local context settings are inherited during
032: * {@link ConcurrentContext concurrent} executions.</p>
033: *
034: * @author <a href="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a>
035: * @version 3.6, September 24, 2005
036: * @see javolution.util.LocalMap
037: */
038: public class LocalContext extends Context {
039:
040: /**
041: * Holds this class (J2ME does not support LocalContext.class).
042: */
043: private static Class CLASS = new LocalContext().getClass();
044:
045: /**
046: * Holds any reference associated to this context (reference to
047: * referent mapping).
048: */
049: final FastMap _references = new FastMap();
050:
051: /**
052: * Default constructor.
053: */
054: public LocalContext() {
055: }
056:
057: /**
058: * Enters a {@link LocalContext} possibly recycled.
059: *
060: * @return the local context being entered.
061: */
062: public static LocalContext enter() {
063: return (LocalContext) Context.enter(CLASS);
064: }
065:
066: /**
067: * Exits the current local context.
068: *
069: * @return the local context being exited.
070: * @throws ClassCastException if the context is not a local context.
071: */
072: public static/*LocalContext*/Context exit() {
073: return (LocalContext) Context.exit();
074: }
075:
076: // Implements Context abstract method.
077: protected void enterAction() {
078: // Do nothing.
079: }
080:
081: // Implements Context abstract method.
082: protected void exitAction() {
083: _references.clear();
084: }
085:
086: /**
087: * <p> This class represents a reference whose setting is local to the current
088: * {@link LocalContext}. Setting outside of any {@link LocalContext} scope
089: * affects the reference default value (equivalent to {@link #setDefault}).
090: * For example:[code]
091: * public class Foo {
092: * public static final LocalContext.Reference<TextFormat<Foo>> FORMAT
093: * = new LocalContext.Reference<TextFormat<Foo>>(DEFAULT_FORMAT);
094: *
095: * public Text toString() {
096: * return FORMAT.get().format(this).toString();
097: * }
098: * }
099: * ...
100: * LocalContext.enter();
101: * try {
102: * Foo.FORMAT.set(localFormat);
103: * ... // This thread displays Foo instances using localFormat.
104: * } finally {
105: * LocalContext.exit(); // Reverts to previous format.
106: * }[/code]</p>
107: */
108: public static class Reference/*<T>*/implements
109: javolution.lang.Reference/*<T>*/{
110:
111: /**
112: * Holds the default value for this reference.
113: */
114: private Object/*{T}*/_defaultValue;
115:
116: /**
117: * Indicates if this reference value has ever been locally overriden
118: * (optimization, most applications use default values).
119: */
120: private boolean _hasBeenLocallyOverriden;
121:
122: /**
123: * Default constructor (default referent is <code>null</code>).
124: */
125: public Reference() {
126: this (null);
127: }
128:
129: /**
130: * Creates a local reference having the specified default value.
131: *
132: * @param defaultValue the default value or root value of this variable.
133: */
134: public Reference(Object/*{T}*/defaultValue) {
135: _defaultValue = defaultValue;
136: }
137:
138: /**
139: * Returns the local value for this reference.
140: * The first outer {@link LocalContext} is searched first, then
141: * all outer {@link LocalContext} are recursively searched up to the
142: * global root context which contains the default value.
143: *
144: * @return the context-local value.
145: */
146: public final Object/*{T}*/get() {
147: return (_hasBeenLocallyOverriden) ? retrieveValue()
148: : _defaultValue;
149: }
150:
151: private Object/*{T}*/retrieveValue() {
152: for (Context ctx = Context.getCurrent(); ctx != null; ctx = ctx
153: .getOuter()) {
154: if (ctx instanceof LocalContext) {
155: LocalContext localContext = (LocalContext) ctx;
156: Object value = localContext._references.get(this );
157: if (value != null) {
158: return (Object/*{T}*/) value;
159: }
160: }
161: }
162: // Not found, returns default value.
163: return _defaultValue;
164: }
165:
166: /**
167: * Sets the local value (referent) for this reference.
168: *
169: * @param value the new local value or <code>null</code> to inherit
170: * the outer value.
171: */
172: public void set(Object/*{T}*/value) {
173: LocalContext ctx = Reference.getLocalContext();
174: if (ctx != null) {
175: FastMap references = ctx._references;
176: references.put(this , value);
177: _hasBeenLocallyOverriden = true;
178: return;
179: }
180: // No local context, sets default value.
181: _defaultValue = value;
182: }
183:
184: /**
185: * Returns the default value for this reference.
186: *
187: * @return the defaultValue.
188: */
189: public Object/*{T}*/getDefault() {
190: return _defaultValue;
191: }
192:
193: /**
194: * Returns the local (non-inherited) value for this reference.
195: *
196: * @return the local value or <code>null</code> if none (value to be
197: * inherited or not set).
198: */
199: public Object/*{T}*/getLocal() {
200: LocalContext ctx = Reference.getLocalContext();
201: return (ctx != null) ? (Object/*{T}*/) ctx._references
202: .get(this ) : _defaultValue;
203: }
204:
205: /**
206: * Sets the default value for this reference.
207: *
208: * @param defaultValue the root value.
209: */
210: public void setDefault(Object/*{T}*/defaultValue) {
211: _defaultValue = defaultValue;
212: }
213:
214: /**
215: * Returns the string representation of the current value of this
216: * reference.
217: *
218: * @return <code>String.valueOf(this.get())</code>
219: */
220: public String toString() {
221: return String.valueOf(this .get());
222: }
223:
224: // Returns the local context if any.
225: private static LocalContext getLocalContext() {
226: for (Context ctx = Context.getCurrent(); ctx != null; ctx = ctx
227: .getOuter()) {
228: if (ctx instanceof LocalContext)
229: return (LocalContext) ctx;
230: }
231: return null;
232: }
233: }
234: }
|