001: /**
002: * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright notice. All rights reserved.
003: */package com.tc.util.concurrent;
004:
005: /**
006: * An object reference holder class in which the reference can only be set once. This might be useful for a member
007: * variable that you'd like to make final, but that you aren't able to set within a constructor. I suppose this class is
008: * a lot like TCFuture, but this class doesn't offer methods to wait for a value to set. The use case for this class has
009: * nothing to do with communication/synchronization between threads. This class is meant to make sure you can't change a
010: * reference once it's been set (ie. it provides a reference member variable that behaves like it was marked "final" and
011: * won't let anyone read it until it has been set)
012: *
013: * @author teck
014: */
015: public final class SetOnceRef {
016: private Object ref;
017: private boolean set;
018: private final Object lock = new Object();
019: private final boolean allowsNullValue;
020:
021: /**
022: * Create a new <code>set()</code> 'able instance This instance <b>will not </b> permitted to contain a null
023: * reference
024: */
025: public SetOnceRef() {
026: this (null, false, false);
027: }
028:
029: /**
030: * Create and immediately <code>set()</code> to the given reference. This instance <b>will not </b> permitted to
031: * contain a null reference
032: *
033: * @param ref The reference to hold
034: * @throws IllegalArgumentException If the reference to hold is null
035: */
036: public SetOnceRef(Object ref) {
037: this (ref, false, true);
038: }
039:
040: /**
041: * Create and immediately <code>set()</code> to the given refernce
042: *
043: * @param ref the reference to hold
044: * @param allowNull true to allow nulls to be stored in this instance
045: * @throws IllegalArgumentException if allowNull is true and the given reference is null
046: */
047: public SetOnceRef(Object ref, boolean allowNull) {
048: this (ref, allowNull, true);
049: }
050:
051: /**
052: * Create a new <code>set()</code> 'able instance
053: *
054: * @param allowNull true to allow this instance to hold the value null
055: */
056: public SetOnceRef(boolean allowNull) {
057: this (null, allowNull, false);
058: }
059:
060: private SetOnceRef(final Object ref, final boolean allowNull,
061: final boolean init) {
062: this .allowsNullValue = allowNull;
063:
064: if (init) {
065: set(ref);
066: }
067: }
068:
069: /**
070: * Can null ever be the value of this reference
071: *
072: * @return true if null is allowed, false otherwise
073: */
074: public boolean allowsNull() {
075: return this .allowsNullValue;
076: }
077:
078: /**
079: * Attmept to set the reference to the given value
080: *
081: * @param ref the reference to set in this instance
082: * @throws IllegalStateException if the reference has already been set by another thread
083: * @throws IllegalArgumentException if the given reference is null and this instance does not allow the null value
084: */
085: public void set(final Object ref) {
086: synchronized (lock) {
087: if (set) {
088: throw new IllegalStateException(
089: "Reference has already been set");
090: }
091:
092: if ((!allowsNull()) && (ref == null)) {
093: throw new IllegalArgumentException(
094: "This instance cannot hold a null reference value");
095: }
096:
097: set = true;
098: this .ref = ref;
099: }
100: }
101:
102: /**
103: * Get the reference value contained in this instance
104: *
105: * @return the reference, may be null if this instance allow nulls (see <code>allowNull</code>
106: * @throws IllegalStateException if a valid reference value has not yet been set
107: */
108: public Object get() {
109: synchronized (lock) {
110: if (!set) {
111: throw new IllegalStateException(
112: "Reference has not been set");
113: }
114:
115: return ref;
116: }
117: }
118:
119: /**
120: * Has someone set the reference yet
121: *
122: * @return true iff the reference has been set
123: */
124: public boolean isSet() {
125: synchronized (lock) {
126: return set;
127: }
128: }
129: }
|