001: /*
002: * EnvironmentProvider.java: A central storage for Environment instances.
003: *
004: * Copyright (C) 2002 Heiko Blau
005: *
006: * This file belongs to the Susebox Java Core Library (Susebox JCL).
007: * The Susebox JCL is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU Lesser General Public License as published by the
009: * Free Software Foundation; either version 2.1 of the License, or (at your
010: * option) any later version.
011: *
012: * This software is distributed in the hope that it will be useful, but WITHOUT
013: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
014: * FITNESS FOR A PARTICULAR PURPOSE.
015: * See the GNU Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public License along
018: * with the Susebox JCL. If not, write to the
019: *
020: * Free Software Foundation, Inc.
021: * 59 Temple Place, Suite 330,
022: * Boston, MA 02111-1307
023: * USA
024: *
025: * or check the Internet: http://www.fsf.org
026: *
027: * Contact:
028: * email: heiko@susebox.de
029: */
030:
031: package de.susebox.java.lang;
032:
033: //-----------------------------------------------------------------------------
034: // Imports
035: //
036: import java.util.Hashtable;
037: import de.susebox.java.lang.ExtNullPointerException;
038:
039: //-----------------------------------------------------------------------------
040: // Class EnvironmentProvider
041: //
042:
043: /**<p>
044: * The <code>EnvironmentProvider</code> is a singleton object to store and provide
045: * {@link Environment} instances. It provides the possibility to register and
046: * retrieve <code>Environment</code> instances on a per object or per class base.
047: *</p><p>
048: * Since an <code>Environment</code> is designed as a substitute for some features
049: * of the JDK {@link java.lang.System} class, the retrieval of the <code>Environment</code>
050: * associated with a class should be possible without additional information about
051: * the context. Class-based <code>Environment</code> objects are also associated with
052: * the thread, that actually registered the instance.
053: *</p>
054: *
055: * @author Heiko Blau
056: */
057: public final class EnvironmentProvider {
058:
059: /**
060: * This method returns an {@link Environment} instance that has been registered
061: * for the given object.
062: *<br>
063: * If there is no specific <code>Environment</code> instance available for the
064: * object then its class name is used to find a more general <code>Environment</code>
065: * instance.
066: *<br>
067: * If still no <code>Environment</code> could be found a default <code>Environment</code>
068: * is returned, usually a {@link DefaultEnvironment} instance.
069: *<br>
070: * The method will always return an <code>Environment</code> instance except
071: * for runtime exceptions.
072: *
073: * @param obj the object thats environment should be retrieved
074: * @return an {@link Environment} instance for the caller
075: * @see Environment
076: * @see DefaultEnvironment
077: */
078: public static Environment getEnvironment(Object obj) {
079: Environment env = null;
080:
081: // try to find an environment going up the class hierarchy
082: if (obj != null && _environmentMap != null) {
083: synchronized (_syncMonitor) {
084: Object iterObj = obj;
085:
086: do {
087: if (iterObj instanceof Class) {
088: env = (Environment) _environmentMap
089: .get(new EnvironmentKey((Class) iterObj));
090: iterObj = ((Class) iterObj).getSuperclass();
091: } else {
092: env = (Environment) _environmentMap
093: .get(iterObj);
094: iterObj = iterObj.getClass();
095: }
096: if (env != null) {
097: break;
098: }
099: } while (iterObj instanceof Class);
100: }
101: }
102:
103: // not found ? Than take the default environment
104: if (env == null) {
105: synchronized (_syncMonitor) {
106: if (_defaultEnvironment == null) {
107: _defaultEnvironment = new DefaultEnvironment();
108: }
109: env = _defaultEnvironment;
110: }
111: }
112: return env;
113: }
114:
115: /**
116: * Registering an {@link Environment} for the given object. If this object
117: * is a {@link java.lang.Class} instance, the <code>Environment</code> is
118: * common for all instances of this class and its subclasses.
119: *
120: * @param obj the object the given {@link Environment} is for
121: * @param env the {@link Environment} to store
122: * @throws NullPointerException if one of the parameters is <code>null</code>
123: */
124: public static void setEnvironment(Object obj, Environment env)
125: throws NullPointerException {
126: // test parameters
127: if (obj == null) {
128: throw new ExtNullPointerException("No object given.");
129: } else if (env == null) {
130: throw new ExtNullPointerException("No environment given.");
131: }
132:
133: // create hashtable for the environments
134: synchronized (_syncMonitor) {
135: if (_environmentMap == null) {
136: _environmentMap = new Hashtable();
137: }
138:
139: // store the environment
140: if (obj instanceof Class) {
141: _environmentMap.put(new EnvironmentKey((Class) obj),
142: env);
143: } else {
144: _environmentMap.put(obj, env);
145: }
146: }
147: }
148:
149: /**
150: * Removing a registered {@link Environment}. If the given object is not known
151: * to the <code>EnvironmentProvider</code> the method does nothing.
152: *
153: * @param obj the object thats {@link Environment} should be removed
154: */
155: public static void removeEnvironment(Object obj) {
156: if (obj != null && _environmentMap != null) {
157: if (obj instanceof Class) {
158: _environmentMap.remove(new EnvironmentKey((Class) obj));
159: } else {
160: _environmentMap.remove(obj);
161: }
162: }
163: }
164:
165: //---------------------------------------------------------------------------
166: // inner class
167: //
168:
169: /**
170: * This class stores a {@link java.lang.Class} object and the current thread
171: * to form a key for class-based environment registration
172: *
173: * @see EnvironmentProvider#setEnvironment
174: * @see EnvironmentProvider#getEnvironment
175: */
176: static final class EnvironmentKey {
177:
178: /**
179: * The constructor takes the {@link java.lang.Class} object that forms the
180: * first part of the key. It automatically adds the calling thread to the
181: * key
182: *
183: * @param cl the <code>Class</code> object that is the first part of the key.
184: */
185: public EnvironmentKey(Class cl) {
186: synchronized (this ) {
187: _class = cl;
188: _thread = Thread.currentThread();
189: }
190: }
191:
192: /**
193: * Checking the equality of this instance to another {@link java.lang.Object}.
194: *
195: * @param obj the reference object with which to compare
196: * @return <code>true</code> if this object is the same as the obj argument;
197: * <code>false</code> otherwise.
198: */
199: public boolean equals(Object obj) {
200: if (obj == this ) {
201: return true;
202: } else if (obj == null) {
203: return false;
204: } else if (!(obj instanceof EnvironmentKey)) {
205: return false;
206: } else {
207: EnvironmentKey key = (EnvironmentKey) obj;
208:
209: if (_thread == key._thread && _class.equals(key._class)) {
210: return true;
211: } else {
212: return false;
213: }
214: }
215: }
216:
217: /**
218: * Providing the has code for this key.
219: *
220: * @return the hash code for this instance
221: */
222: public int hashCode() {
223: return (_thread.hashCode() << 4)
224: + _class.getName().hashCode();
225: }
226:
227: //-------------------------------------------------------------------------
228: // members
229: //
230: private Class _class = null;
231: private Thread _thread = null;
232: }
233:
234: //---------------------------------------------------------------------------
235: // members
236: //
237: private static DefaultEnvironment _defaultEnvironment = null;
238: private static Hashtable _environmentMap = null;
239: private static Object _syncMonitor = new Object();
240: }
|