| JavaDoq: Key.java |
001
002 /*
003 * Descripter 1.0 - Java Script Engines
004 * Copyright (C) 2010-2015 Jianjun Liu (J.J.Liu)
005 *
006 * This program is free software: you can redistribute it and/or modify
007 * it under the terms of the GNU Affero General Public License as published by
008 * the Free Software Foundation, either version 3 of the License, or
009 * (at your option) any later version.
010 *
011 * This program is distributed in the hope that it will be useful,
012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
014 * GNU Affero General Public License for more details.
015 *
016 * You should have received a copy of the GNU Affero General Public License
017 * along with this program. If not, see <http://www.gnu.org/licenses/>.
018 */
019
020 package org.descripter.js.api;
021
022 import java.lang.ref.Reference;
023 import java.lang.ref.WeakReference;
024 import java.util.Map;
025 import java.util.WeakHashMap;
026
027 /**
028 * <p>Emulates the object properties of JavaScript.</p>
029 * <p>This class is only used in the emulation of for-in statement.</p>
030 *
031 * @see For
032 *
033 * @author <a href="mailto:jianjunliu@126.com">J.J.Liu (Jianjun Liu)</a> at <a href="http://www.descripter.org" target="_blank">http://www.descripter.org</a>
034 * @since Descripter 1.0
035 */
036 public final class Key implements Value
037 {
038 private static int next = -1;
039 private final static Map<String, Key> map = new WeakHashMap<String, Key>();
040 private final static Map<Key, Key> set = new WeakHashMap<Key, Key>();
041
042 /**
043 * <p>Finds or creates a {@link Key} associated with the specified string name.</p>
044 * <p>Note that a {@link Key} does not strongly reference any objects except that it has a unique hash code.</p>
045 * @param cntx The context invoking this method.
046 * @param name A string name
047 * @return The found or created {@link Key}
048 * @since Descripter 1.0
049 */
050 public static synchronized final Key get(Context<?, ?, ?> cntx, String name) {
051 Key k = map.get(name);
052 if (k == null) {
053 try {
054 int i = Integer.decode(name);
055 if (i >= 0) {
056 return new Key(null, name, i);
057 }
058 } catch (NumberFormatException nfe) {
059 }
060 k = new Key(cntx, name, next--);
061 map.put(name, k);
062 set.put(k, k);
063 }
064 return k;
065 }
066
067 /**
068 * <p>Checks if there is already a {@link Key} associated with the specified string name.</p>
069 * <p>Note that a {@link Key} does not strongly reference any objects except that it has a unique hash code.</p>
070 * @param name A string name
071 * @return <tt>true</tt> if there is already a {@link Key} associated with the specified string name;
072 * <tt>false</tt>, otherwise.
073 * @since Descripter 1.0
074 */
075 public static synchronized final boolean has(String name) {
076 return map.containsKey(name);
077 }
078
079 /**
080 * <p>Finds a {@link Key} that has the specified hash code.</p>
081 * <p>Note that a {@link Key} does not strongly reference any objects except that it has a unique hash code.</p>
082 * @param hash The integer hash code
083 * @return The found {@link Key} or <tt>null</tt> for none.
084 * @since Descripter 1.0
085 */
086 public static synchronized final Key get(int hash) {
087 return set.get(new Key(hash));
088 }
089
090 private final Reference<Context<?, ?, ?>> cntx;
091 private final Reference<String> name;
092 private final int hash;
093
094 private Key(int hash) {
095 this(null, null, hash);
096 }
097
098 private Key(Context<?, ?, ?> cntx, String name, int hash) {
099 this.cntx = new WeakReference<Context<?, ?, ?>>(cntx);
100 this.name = new WeakReference<String>(name);
101 this.hash = hash;
102 }
103
104 /**
105 * <p>Returns the hash code of this {@link Key}.</p>
106 * <p>Note that a {@link Key} does not strongly reference any objects except that it has a unique hash code.</p>
107 * @return The hash code of this {@link Key}.
108 * @since Descripter 1.0
109 */
110 @Override
111 public int hashCode() {
112 return hash;
113 }
114
115 /**
116 * <p>Checks if this {@link Key} is equal to another object.</p>
117 * <p>Two {@link Key}s equal each other if and only if their hash codes are equal.</p>
118 * @param o Another object
119 * @return <tt>true</tt> if this {@link Key} is equal to the specified object.
120 * @since Descripter 1.0
121 */
122 @Override
123 public boolean equals(Object o) {
124 return o instanceof Key && ((Key)o).hash == hash;
125 }
126
127 /**
128 * <p>Returns the context associated with this {@link Key}.</p>
129 * <p>Note that a {@link Key} does not strongly reference any objects except that it has a unique hash code.</p>
130 * @return The context associated with this {@link Key} or <tt>null</tt> for none.
131 * @since Descripter 1.0
132 */
133 public final Context<?, ?, ?> context() {
134 return cntx.get();
135 }
136
137 /**
138 * <p>Returns the string name associated with this {@link Key}.</p>
139 * <p>Note that a {@link Key} does not strongly reference any objects except that it has a unique hash code.</p>
140 * @return The string name associated with this {@link Key} or <tt>null</tt> for none.
141 * @since Descripter 1.0
142 */
143 @Override
144 public String evaluate() {
145 return name.get();
146 }
147
148 /**
149 * <p>Returns the string name associated with this {@link Key}.</p>
150 * <p>Note that a {@link Key} does not strongly reference any objects except that it has a unique hash code.</p>
151 * @return The string name associated with this {@link Key} or <tt>null</tt> for none.
152 * @since Descripter 1.0
153 */
154 @Override
155 public String toString() {
156 return name.get();
157 }
158 }
| JavaDoq: Key.java |