001: package sisc.util;
002:
003: import java.io.*;
004: import sisc.ser.*;
005:
006: import java.util.Map;
007: import java.util.HashMap;
008: import sisc.data.Value;
009: import sisc.data.Symbol;
010: import sisc.util.Util;
011:
012: /**
013: * This class serves two purposes. Firstly, it contains static members
014: * that maintain a bijective map between symbols and values. Secondly,
015: * instances of this class are used in Java serialisation as wrappers
016: * for interned values.
017: *
018: * Since the bijective map is static it is shared between app contexts
019: * and hence interned values can leak between apps. This is an
020: * unavoidable consequence of wanting to fit in with standard Java
021: * serialisation in, e.g., J2EE containers, which may happen in
022: * threads with no associated app context. In practice this shouldn't
023: * cause much of a problem. Firstly, many J2EE containers have
024: * separate class loaders for separate web apps etc. Secondly, the
025: * main purpose of interned values is to store globally unique types,
026: * for which there is little harm in sharing between apps.
027: *
028: * Access to the bijective map is thread-safe.
029: *
030: * The map is *not* weak - symbols and values of map entries will not
031: * be garbage collected. It would be desirable for map entries to be
032: * removed when they are no longer referenced. However, it is
033: * impossible to do so reliably, so the current set up is the only
034: * safe solution.
035: */
036: public class InternedValue implements Externalizable {
037:
038: private static Object sync = new Object();
039:
040: private static Map byName = new HashMap(0);
041: private static Map byValue = new HashMap(0);
042:
043: private Symbol name;
044: private Value value;
045:
046: public InternedValue() {
047: }
048:
049: private InternedValue(Symbol name, Value value) {
050: this .name = name;
051: this .value = value;
052: }
053:
054: public Symbol getName() {
055: return name;
056: }
057:
058: public Value getValue() {
059: return value;
060: }
061:
062: public static InternedValue lookupByName(Symbol name) {
063: synchronized (sync) {
064: return (InternedValue) byName.get(name);
065: }
066: }
067:
068: public static InternedValue lookupByValue(Value value) {
069: synchronized (sync) {
070: return (InternedValue) byValue.get(value);
071: }
072: }
073:
074: public static InternedValue intern(Symbol name, Value value) {
075: InternedValue res;
076: synchronized (sync) {
077: InternedValue bN = lookupByName(name);
078: InternedValue bV = lookupByValue(value);
079: if (bN != null && bV == null) {
080: res = bN;
081: } else if (bN == null && bV != null) {
082: res = bV;
083: } else if (bN == null && bV == null) {
084: res = new InternedValue(name, value);
085: byName.put(name, res);
086: byValue.put(value, res);
087: } else if (bN == bV) {
088: res = bN; //or bV
089: } else {
090: res = null;
091: }
092: }
093: return res;
094: }
095:
096: public void writeExternal(ObjectOutput out) throws IOException {
097: Serializer s = JavaSerializer.create(out);
098: s.writeInitializedExpression(name);
099: s.writeClass(value.getClass());
100: value.serialize(s);
101: }
102:
103: public static Value deserResolve(Symbol name, Class clazz)
104: throws IOException {
105: Value value;
106: try {
107: value = (Value) clazz.newInstance();
108: } catch (InstantiationException ie) {
109: ie.printStackTrace();
110: throw new IOException(ie.getMessage());
111: } catch (IllegalAccessException iae) {
112: iae.printStackTrace();
113: throw new IOException(iae.getMessage());
114: }
115: value = intern(name, value).getValue();
116: if (value.getClass() != clazz) {
117: throw new IOException(Util.liMessage(Util.SISCB,
118: "interntypemismatch", new Object[] { name,
119: value.getClass(), clazz.getClass() }));
120: }
121: return value;
122: }
123:
124: public void readExternal(ObjectInput in) throws IOException {
125: Deserializer d = JavaDeserializer.create(in);
126: name = (Symbol) d.readInitializedExpression();
127: Class clazz = d.readClass();
128: value = deserResolve(name, clazz);
129: value.deserialize(d);
130: }
131:
132: public Object readResolve() throws ObjectStreamException {
133: return value;
134: }
135:
136: }
137: /*
138: * The contents of this file are subject to the Mozilla Public
139: * License Version 1.1 (the "License"); you may not use this file
140: * except in compliance with the License. You may obtain a copy of
141: * the License at http://www.mozilla.org/MPL/
142: *
143: * Software distributed under the License is distributed on an "AS
144: * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
145: * implied. See the License for the specific language governing
146: * rights and limitations under the License.
147: *
148: * The Original Code is the Second Interpreter of Scheme Code (SISC).
149: *
150: * The Initial Developer of the Original Code is Scott G. Miller.
151: * Portions created by Scott G. Miller are Copyright (C) 2000-2007
152: * Scott G. Miller. All Rights Reserved.
153: *
154: * Contributor(s):
155: * Matthias Radestock
156: *
157: * Alternatively, the contents of this file may be used under the
158: * terms of the GNU General Public License Version 2 or later (the
159: * "GPL"), in which case the provisions of the GPL are applicable
160: * instead of those above. If you wish to allow use of your
161: * version of this file only under the terms of the GPL and not to
162: * allow others to use your version of this file under the MPL,
163: * indicate your decision by deleting the provisions above and
164: * replace them with the notice and other provisions required by
165: * the GPL. If you do not delete the provisions above, a recipient
166: * may use your version of this file under either the MPL or the
167: * GPL.
168: */
|