1 /* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
\r
3 * The contents of this file are subject to the Netscape Public
\r
4 * License Version 1.1 (the "License"); you may not use this file
\r
5 * except in compliance with the License. You may obtain a copy of
\r
6 * the License at http://www.mozilla.org/NPL/
\r
8 * Software distributed under the License is distributed on an "AS
\r
9 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
\r
10 * implied. See the License for the specific language governing
\r
11 * rights and limitations under the License.
\r
13 * The Original Code is Rhino code, released
\r
16 * The Initial Developer of the Original Code is Netscape
\r
17 * Communications Corporation. Portions created by Netscape are
\r
18 * Copyright (C) 1997-1999 Netscape Communications Corporation. All
\r
25 * Alternatively, the contents of this file may be used under the
\r
26 * terms of the GNU Public License (the "GPL"), in which case the
\r
27 * provisions of the GPL are applicable instead of those above.
\r
28 * If you wish to allow use of your version of this file only
\r
29 * under the terms of the GPL and not to allow others to use your
\r
30 * version of this file under the NPL, indicate your decision by
\r
31 * deleting the provisions above and replace them with the notice
\r
32 * and other provisions required by the GPL. If you do not delete
\r
33 * the provisions above, a recipient may use your version of this
\r
34 * file under either the NPL or the GPL.
\r
37 package org.mozilla.javascript;
\r
39 import java.util.Hashtable;
\r
40 import java.util.Enumeration;
\r
43 * Manipulate a Scriptable object as if its prototype chain were flattened.
\r
45 * This class has been deprecated in favor of the static methods
\r
46 * <code>getProperty</code>, <code>putProperty</code>, and
\r
47 * <code>deleteProperty</code> of ScripableObject. Those methods provide the
\r
48 * same functionality without the confusing and inefficient need to construct
\r
49 * a new object instance.
\r
51 * @see org.mozilla.javascript.ScriptableObject
\r
53 * @author Norris Boyd
\r
56 public class FlattenedObject {
\r
59 * Construct a new FlattenedObject.
\r
61 * @param object the object to be viewed with flattened properties
\r
64 public FlattenedObject(Scriptable object) {
\r
69 * Get the associated Scriptable object.
\r
72 public Scriptable getObject() {
\r
77 * Determine if a property exists in an object.
\r
79 * This is a more convenient (and less efficient) form than
\r
80 * <code>Scriptable.has()</code>.
\r
81 * It returns true if and only if the property
\r
82 * exists in this object or any of the objects in its prototype
\r
85 * @param id the property index, which may be either a String or a
\r
87 * @return true if and only if the property exists in the prototype
\r
89 * @see org.mozilla.javascript.Scriptable#has
\r
90 * @deprecated As of 1.5R2, replaced by ScriptableObject.getProperty
\r
92 public boolean hasProperty(Object id) {
\r
93 String stringId = ScriptRuntime.toString(id);
\r
94 String s = ScriptRuntime.getStringId(stringId);
\r
96 return getBase(obj, ScriptRuntime.getIntId(stringId)) != null;
\r
97 return getBase(obj, s) != null;
\r
101 * Get a property of an object.
\r
103 * This is a more convenient (and less efficient) form than
\r
104 * <code>Scriptable.get()</code>. It corresponds exactly to the
\r
105 * expression <code>obj[id]</code> in JavaScript. This method
\r
106 * will traverse the prototype chain of an object to find the
\r
109 * If the property does not exist in the object or its prototype
\r
110 * chain, the undefined value will be returned.
\r
112 * @param id the property index; can be a String or a Number; the
\r
113 * String may contain characters representing a number
\r
114 * @return the value of the property or the undefined value
\r
115 * @see org.mozilla.javascript.Scriptable#get
\r
116 * @see org.mozilla.javascript.Context#getUndefinedValue
\r
117 * @deprecated As of 1.5R2, replaced by ScriptableObject.getProperty
\r
119 public Object getProperty(Object id) {
\r
120 String s = ScriptRuntime.getStringId(id);
\r
121 int index = s == null ? ScriptRuntime.getIntId(id) : 0;
\r
122 Scriptable m = obj;
\r
125 result = s == null ? m.get(index, obj) : m.get(s, obj);
\r
126 if (result != Scriptable.NOT_FOUND)
\r
128 m = m.getPrototype();
\r
130 return Undefined.instance;
\r
132 if (result instanceof Scriptable)
\r
133 return new FlattenedObject((Scriptable) result);
\r
138 * Set a property of an object.
\r
140 * This is a more convenient (and less efficient) form than that
\r
141 * provided in Scriptable. It corresponds exactly to the
\r
142 * expression <code>obj[id] = val</code> in JavaScript.<p>
\r
144 * @param id the property index, which may be either a String or
\r
146 * @param value the value of the property
\r
147 * @see org.mozilla.javascript.Scriptable#put
\r
148 * @deprecated As of 1.5R2, replaced by ScriptableObject.putProperty
\r
150 public void putProperty(Object id, Object value) {
\r
151 String s = ScriptRuntime.getStringId(id);
\r
152 if (value instanceof FlattenedObject)
\r
153 value = ((FlattenedObject) value).getObject();
\r
156 int index = ScriptRuntime.getIntId(id);
\r
157 x = getBase(obj, index);
\r
160 x.put(index, obj, value);
\r
163 x = getBase(obj, s);
\r
166 x.put(s, obj, value);
\r
170 * Remove a property.
\r
172 * This method provides the functionality of the <code>delete</code>
\r
173 * operator in JavaScript.
\r
175 * @param id the property index, which may be either a String or
\r
177 * @return true if the property didn't exist, or existed and was removed
\r
178 * @see org.mozilla.javascript.Scriptable#delete
\r
179 * @deprecated as of 1.5R2, replaced by ScriptableObject.deleteProperty
\r
181 public boolean deleteProperty(Object id) {
\r
182 String s = ScriptRuntime.getStringId(id);
\r
184 int index = ScriptRuntime.getIntId(id);
\r
185 Scriptable base = getBase(obj, index);
\r
188 base.delete(index);
\r
189 return !base.has(index, base);
\r
191 Scriptable base = getBase(obj, s);
\r
195 return !base.has(s, base);
\r
199 * Return an array that contains the ids of the properties.
\r
201 * <p>This method will walk the prototype chain and collect the
\r
202 * ids of all objects in the prototype chain.<p>
\r
204 * If an id appears in more than one object in the prototype chain,
\r
205 * it will only be in the array once. (So all the entries in the
\r
206 * array will be unique respective to equals().)
\r
208 * @see org.mozilla.javascript.Scriptable#getIds
\r
211 public Object[] getIds() {
\r
212 Hashtable h = new Hashtable(11);
\r
213 Scriptable m = obj;
\r
214 while (m != null) {
\r
215 Object[] e = m.getIds();
\r
216 for (int i=0; i < e.length; i++) {
\r
217 h.put(e[i], Boolean.TRUE);
\r
219 m = m.getPrototype();
\r
221 Enumeration keys = h.keys();
\r
223 Object[] result = new Object[h.size()];
\r
225 while (keys.hasMoreElements()) {
\r
226 elem = keys.nextElement();
\r
227 result[index++] = elem;
\r
233 * Consider this object to be a function, and call it.
\r
235 * @param cx the current Context for this thread
\r
236 * @param thisObj the JavaScript 'this' for the call
\r
237 * @param args the arguments for the call
\r
238 * @return the result of the JavaScript function call
\r
239 * @exception NotAFunctionException if this object is not a function
\r
240 * @exception JavaScriptException if an uncaught JavaScript exception
\r
241 * occurred while executing the function
\r
242 * @see org.mozilla.javascript.Function#call
\r
245 public Object call(Context cx, Scriptable thisObj, Object[] args)
\r
246 throws NotAFunctionException,
\r
247 JavaScriptException
\r
249 if (!(obj instanceof Function)) {
\r
250 throw new NotAFunctionException();
\r
252 return ScriptRuntime.call(cx, obj, thisObj, args, (Function) obj);
\r
256 * Consider this object to be a function, and invoke it as a
\r
257 * constructor call.
\r
259 * @param cx the current Context for this thread
\r
260 * @param args the arguments for the constructor call
\r
261 * @return the allocated object
\r
262 * @exception NotAFunctionException if this object is not a function
\r
263 * @exception JavaScriptException if an uncaught JavaScript exception
\r
264 * occurred while executing the constructor
\r
265 * @see org.mozilla.javascript.Function#construct
\r
268 public Scriptable construct(Context cx, Object[] args)
\r
269 throws NotAFunctionException,
\r
270 JavaScriptException
\r
272 if (!(obj instanceof Function)) {
\r
273 throw new NotAFunctionException();
\r
275 return ScriptRuntime.newObject(cx, obj, args, null);
\r
279 * Get the property indicated by the id, and invoke it with the
\r
280 * specified arguments.
\r
282 * For example, for a FlattenedObject <code>obj</code>,
\r
283 * and a Java array <code>a</code> consisting of a single string
\r
284 * <code>"hi"</code>, the call <pre>
\r
285 * obj.callMethod("m", a)</pre>
\r
286 * is equivalent to the JavaScript code <code>obj.m("hi")</code>.<p>
\r
288 * If the property is not found or is not a function, an
\r
289 * exception will be thrown.
\r
291 * @param id the Number or String to use to find the function property
\r
293 * @param args the arguments for the constructor call
\r
294 * @return the result of the call
\r
295 * @exception PropertyException if the designated property
\r
297 * @exception NotAFunctionException if this object is not a function
\r
298 * @exception JavaScriptException if an uncaught JavaScript exception
\r
299 * occurred while executing the method
\r
300 * @see org.mozilla.javascript.Function#call
\r
303 public Object callMethod(Object id, Object[] args)
\r
304 throws PropertyException,
\r
305 NotAFunctionException,
\r
306 JavaScriptException
\r
308 if (!hasProperty(id)) {
\r
309 throw PropertyException.withMessage0("msg.prop.not.found");
\r
311 Object o = getProperty(id);
\r
312 if (o instanceof FlattenedObject)
\r
313 return ((FlattenedObject) o).call(Context.getContext(), obj, args);
\r
314 throw new NotAFunctionException();
\r
317 /****** End of API *******/
\r
319 private static Scriptable getBase(Scriptable obj, String s) {
\r
320 Scriptable m = obj;
\r
321 while (m != null) {
\r
324 m = m.getPrototype();
\r
329 private static Scriptable getBase(Scriptable obj, int index) {
\r
330 Scriptable m = obj;
\r
331 while (m != null) {
\r
332 if (m.has(index, obj))
\r
334 m = m.getPrototype();
\r
339 private Scriptable obj;
\r