KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > gnu > mapping > Symbol


1 // Copyright (c) 1996-2000, 2002, 2004, 2006 Per M.A. Bothner.
2
// This is free software; for terms and warranty disclaimer see ./COPYING.
3

4 package gnu.mapping;
5 import java.io.*;
6
7 // Enable JAXP-QName if Symbol should extend javax.xml.namespace.QName.
8
// This is not the default, even when JAXP-1.3 is defined, because it makes
9
// symbols bigger and some operations (such as equals and handling of
10
// uninterned symbols) slower, without much benefit.
11
// This option needs some work.
12
/* #ifdef JAXP-QName */
13 // import javax.xml.namespace.QName;
14
/* #endif */
15
16 /** A Symbol is a name, usually in a specific Namespace.
17  * A Symbol is stateless: Comon Lisp-style "value", "function" and
18  * "property list" bindings are not part of the Symbol itself, but
19  * looked up in the current Environment.
20  * A <code>Symbol</code> may be viewed as an <code>EnvironmentKey</code>
21  * with a <code>null</code> property component.
22  */

23
24 public class Symbol
25   /* #ifdef JAXP-QName */
26   // extends QName
27
/* #endif */
28   implements
29   EnvironmentKey,
30   /* #ifdef JAVA2 */
31   Comparable JavaDoc,
32   /* #endif */
33   Externalizable
34 {
35   /* #ifndef JAXP-QName */
36   protected String JavaDoc name;
37   /* #endif */
38   Namespace namespace;
39
40   public final Symbol getKeySymbol () { return this; }
41   public final Object JavaDoc getKeyProperty () { return null; }
42   public boolean matches (EnvironmentKey key)
43   {
44     return equals(key.getKeySymbol(), this) && key.getKeyProperty() == null;
45   }
46   public boolean matches (Symbol symbol, Object JavaDoc property)
47   {
48     return equals(symbol, this) && property == null;
49   }
50
51   /* #ifndef JAXP-QName */
52   public final String JavaDoc getNamespaceURI()
53   {
54     Namespace ns = getNamespace();
55     return ns == null ? null : ns.getName();
56   }
57
58   public final String JavaDoc getLocalPart()
59   {
60     return name;
61   }
62
63   public final String JavaDoc getPrefix ()
64   {
65     Namespace ns = namespace;
66     return ns == null ? "" : ns.prefix;
67   }
68   /* #endif */
69
70   public final boolean hasEmptyNamespace ()
71   {
72     Namespace ns = getNamespace();
73     String JavaDoc nsname;
74     return (ns == null
75         || (nsname = ns.getName()) == null || nsname.length() == 0);
76   }
77
78   /** Synonym for getName - the "print name" of the symbol without Namespace.
79    * Useful when thinking of a Symbol as an XML QName. */

80   public final String JavaDoc getLocalName()
81   {
82     /* #ifdef JAXP-QName */
83     // return getLocalPart();
84
/* #else */
85     return name;
86     /* #endif */
87   }
88
89   public final String JavaDoc getName()
90   {
91     /* #ifdef JAXP-QName */
92     // return getLocalPart();
93
/* #else */
94     return name;
95     /* #endif */
96   }
97
98   /** Find or create a symbol in a specificed namespace.
99    * @param uri a namespace uri.
100    * @param name The "local name" or "print name" of the desired symbol.
101    * @param prefix namespace prefix, or {@code ""}
102    */

103   public static Symbol make (String JavaDoc uri, String JavaDoc name, String JavaDoc prefix)
104   {
105     return Namespace.make(uri, prefix).getSymbol(name.intern());
106   }
107
108   /** Find or create a symbol in a specificed namespace.
109    * @param namespace can be an Namespace, or a namespace/environment name
110    * (resolved using Namespace.getInstance), or null (in which case
111    * an uninterned symbol is created).
112    * @param name The "local name" or "print name" of the desired symbol.
113    */

114   public static Symbol make (Object JavaDoc namespace, String JavaDoc name)
115   {
116     Namespace ns = namespace instanceof String JavaDoc
117       ? Namespace.getInstance((String JavaDoc) namespace)
118       : (Namespace) namespace;
119     if (ns == null || name == null)
120       return makeUninterned(name);
121     return ns.getSymbol(name.intern());
122   }
123
124   /** Parse a String as a Symbol.
125    * Recognizes:
126    * <ul>
127    * <li>{@code "{namespace-uri}local-name"} - which creates a
128    * symbol with that namespace-uri and an empty prefix;
129    * </li>
130    * <li>{@code "prefix:local-name"}- which creates a symbol with that prefix
131    * and an "unknown" namespace-uri, using {@link #makeWithUnknownNamespace};
132    * </li>
133    * <li>and plain {@code "local-name"} - which creates a symbol in
134    * {@link Namespace#EmptyNamespace}.
135    * </li></ul>
136    */

137   public static Symbol parse (String JavaDoc symbol)
138   {
139     if (symbol.length() > 0 && symbol.charAt(0) == '{')
140       {
141         int rbrace = symbol.lastIndexOf('}');
142         if (rbrace <= 0)
143           {
144             throw new RuntimeException JavaDoc("missing '}' in property name '"+symbol+"'");
145           }
146         return Symbol.make(symbol.substring(1, rbrace), symbol.substring(rbrace+1), "");
147       }
148     int colon = symbol.indexOf(':');
149     if (colon > 0)
150       {
151         return Symbol.makeWithUnknownNamespace(symbol.substring(colon+1),
152                                                symbol.substring(0, colon));
153       }
154     else
155       {
156         return Symbol.make("", symbol, "");
157       }
158   }
159
160   /** Make a placeholder symbol with a known prefix and unknown namespace-uri.
161    * This is convenient for processing definition commands like
162    * {@code "prefix:name=value"} - such as on the Kawa command-line -
163    * where we don't yet know the namespace-uri. Code that later looks
164    * for a value should look both under the true namespace-uri and
165    less LOG.JA * using this method (or {@link Namespace#makeUnknownNamespace}).
166    */

167   public static Symbol makeWithUnknownNamespace (String JavaDoc local, String JavaDoc prefix)
168   {
169     return Namespace.makeUnknownNamespace(prefix).getSymbol(local.intern());
170   }
171
172   public Symbol ()
173   {
174     /* #ifdef JAXP-QName */
175     // super("");
176
/* #endif */
177   }
178
179   public static Symbol makeUninterned (String JavaDoc name)
180   {
181     /* #ifdef JAXP-QName */
182     // Namespace ns = Namespace.getInstance("kawa.gensym");
183
// String sname = name;
184
// int i = 0;
185
// for (;;)
186
// {
187
// int hash = sname.hashCode();
188
// synchronized (ns)
189
// {
190
// Symbol sym = ns.lookup(sname, hash, false);
191
// if (sym == null)
192
// return ns.add(new Symbol(ns, sname.intern()), hash);
193
// }
194
// sname = name + '.' + ++i;
195
// }
196
/* #else */
197     return new Symbol(null, name);
198     /* #endif */
199   }
200
201   /** Create new Symbol in a given namespace.
202    * Does not enter the result in the namespace's symbol table.
203    * @param name an interned String
204    */

205   public Symbol (Namespace ns, String JavaDoc name)
206   {
207     /* #ifdef JAXP-QName */
208     // super(ns == null ? "" : ns.getName(), name, ns == null ? "" : ns.prefix);
209
/* #else */
210     this.name = name;
211     /* #endif */
212     this.namespace = ns;
213   }
214
215   public int compareTo(Object JavaDoc o)
216   {
217     Symbol other = (Symbol) o;
218     if (getNamespaceURI() != other.getNamespaceURI())
219       throw new IllegalArgumentException JavaDoc("comparing Symbols in different namespaces");
220     return getLocalName().compareTo(other.getLocalName());
221   }
222
223   public static boolean equals (Symbol sym1, Symbol sym2)
224   {
225     if (sym1 == sym2)
226       return true;
227     if (sym1 == null || sym2 == null)
228       return false;
229     /* #ifdef JAXP-QName */
230     // if (sym1.getLocalPart() == sym2.getLocalPart())
231
/* #else */
232     if (sym1.name == sym2.name)
233     /* #endif */
234       {
235         Namespace namespace1 = sym1.namespace;
236         Namespace namespace2 = sym2.namespace;
237         return (namespace1 != null && namespace2 != null
238                 && (namespace1 == namespace2
239                     || namespace1.name == namespace2.name));
240       }
241     return false;
242   }
243
244   /* #ifndef JAXP-QName */
245   /** Just tests for identity.
246    * Otherwise hashTables that have Symbols as keys will break. */

247   public final boolean equals (Object JavaDoc o)
248   {
249     return o instanceof Symbol && equals(this, (Symbol) o);
250   }
251
252   public int hashCode ()
253   {
254     return name == null ? 0 : name.hashCode();
255   }
256   /* #endif */
257
258   public final Namespace getNamespace()
259   {
260     return namespace;
261   }
262
263   public final void setNamespace (Namespace ns)
264   {
265     namespace = ns;
266   }
267
268   /** Conventional value used as a property key for function bindings. */
269   public static final Symbol FUNCTION = makeUninterned("(function)");
270
271   /** Conventional value used as a <code>Symbol</code> name to
272    * access an <code>Object</code>'s property list.
273    * A <dfn>property list</dfn> is a list with a even number of
274    * <code>Pair</code>s, containing alternating keys and values.
275    * They are used in Common Lisp and Emacs Lisp.
276    * Kawa (following XEmacs) allows arbitrary objects to have property lists,
277    * thus the PLIST as used as the name and the object as the property.
278    * (In the future we'll do somethingg clever so that get(SYMBOL, KEY)
279    * as the same as getf(get(PLIST, SYMBOL), KEY) - but much faster.)
280    */

281   public static final Symbol PLIST = makeUninterned("(property-list)");
282
283   public String JavaDoc toString()
284   {
285     // String h = "@"+Integer.toHexString(System.identityHashCode(this));
286
String JavaDoc uri = getNamespaceURI();
287     if (uri == null || uri.length() == 0)
288       return getName();
289     StringBuffer JavaDoc sbuf = new StringBuffer JavaDoc();
290     String JavaDoc prefix = getPrefix();
291     if (prefix == null || prefix.length() == 0)
292       {
293         sbuf.append('{');
294         sbuf.append(getNamespaceURI());
295         sbuf.append('}');
296       }
297     else
298       {
299         sbuf.append(prefix);
300         sbuf.append(':');
301       }
302     sbuf.append(getName());
303     return sbuf.toString();
304   }
305
306   public void writeExternal(ObjectOutput out) throws IOException
307   {
308     Namespace ns = getNamespace();
309     out.writeObject(ns);
310     out.writeObject(getName());
311   }
312
313   public void readExternal(ObjectInput in)
314     throws IOException, ClassNotFoundException JavaDoc
315   {
316     /* #ifdef JAXP-QName */
317     // throw new Error("Symbol.readExternal not implemented"); // FIXME!
318
/* #else */
319     namespace = (Namespace) in.readObject();
320     name = (String JavaDoc) in.readObject();
321     /* #endif */
322   }
323
324   public Object JavaDoc readResolve() throws ObjectStreamException
325   {
326     if (namespace == null)
327       return this;
328     return make(namespace, getName());
329   }
330 }
331
Popular Tags