001: /* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
002: *
003: * ***** BEGIN LICENSE BLOCK *****
004: * Version: MPL 1.1/GPL 2.0
005: *
006: * The contents of this file are subject to the Mozilla Public License Version
007: * 1.1 (the "License"); you may not use this file except in compliance with
008: * the License. You may obtain a copy of the License at
009: * http://www.mozilla.org/MPL/
010: *
011: * Software distributed under the License is distributed on an "AS IS" basis,
012: * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
013: * for the specific language governing rights and limitations under the
014: * License.
015: *
016: * The Original Code is Rhino code, released
017: * May 6, 1999.
018: *
019: * The Initial Developer of the Original Code is
020: * Netscape Communications Corporation.
021: * Portions created by the Initial Developer are Copyright (C) 1999
022: * the Initial Developer. All Rights Reserved.
023: *
024: * Contributor(s):
025: * Norris Boyd
026: * Igor Bukanov
027: * Matthias Radestock
028: *
029: * Alternatively, the contents of this file may be used under the terms of
030: * the GNU General Public License Version 2 or later (the "GPL"), in which
031: * case the provisions of the GPL are applicable instead of those above. If
032: * you wish to allow use of your version of this file only under the terms of
033: * the GPL and not to allow others to use your version of this file under the
034: * MPL, indicate your decision by deleting the provisions above and replacing
035: * them with the notice and other provisions required by the GPL. If you do
036: * not delete the provisions above, a recipient may use your version of this
037: * file under either the MPL or the GPL.
038: *
039: * ***** END LICENSE BLOCK ***** */
040:
041: // API class
042: package org.mozilla.javascript;
043:
044: /**
045: * Class ImporterTopLevel
046: *
047: * This class defines a ScriptableObject that can be instantiated
048: * as a top-level ("global") object to provide functionality similar
049: * to Java's "import" statement.
050: * <p>
051: * This class can be used to create a top-level scope using the following code:
052: * <pre>
053: * Scriptable scope = new ImporterTopLevel(cx);
054: * </pre>
055: * Then JavaScript code will have access to the following methods:
056: * <ul>
057: * <li>importClass - will "import" a class by making its unqualified name
058: * available as a property of the top-level scope
059: * <li>importPackage - will "import" all the classes of the package by
060: * searching for unqualified names as classes qualified
061: * by the given package.
062: * </ul>
063: * The following code from the shell illustrates this use:
064: * <pre>
065: * js> importClass(java.io.File)
066: * js> f = new File('help.txt')
067: * help.txt
068: * js> importPackage(java.util)
069: * js> v = new Vector()
070: * []
071: *
072: * @author Norris Boyd
073: */
074: public class ImporterTopLevel extends IdScriptableObject {
075: static final long serialVersionUID = -9095380847465315412L;
076:
077: private static final Object IMPORTER_TAG = new Object();
078:
079: public ImporterTopLevel() {
080: }
081:
082: public ImporterTopLevel(Context cx) {
083: this (cx, false);
084: }
085:
086: public ImporterTopLevel(Context cx, boolean sealed) {
087: initStandardObjects(cx, sealed);
088: }
089:
090: public String getClassName() {
091: return (topScopeFlag) ? "global" : "JavaImporter";
092: }
093:
094: public static void init(Context cx, Scriptable scope, boolean sealed) {
095: ImporterTopLevel obj = new ImporterTopLevel();
096: obj.exportAsJSClass(MAX_PROTOTYPE_ID, scope, sealed);
097: }
098:
099: public void initStandardObjects(Context cx, boolean sealed) {
100: // Assume that Context.initStandardObjects initialize JavaImporter
101: // property lazily so the above init call is not yet called
102: cx.initStandardObjects(this , sealed);
103: topScopeFlag = true;
104: // If seal is true then exportAsJSClass(cx, seal) would seal
105: // this obj. Since this is scope as well, it would not allow
106: // to add variables.
107: IdFunctionObject ctor = exportAsJSClass(MAX_PROTOTYPE_ID, this ,
108: false);
109: if (sealed) {
110: ctor.sealObject();
111: }
112: // delete "constructor" defined by exportAsJSClass so "constructor"
113: // name would refer to Object.constructor
114: // and not to JavaImporter.prototype.constructor.
115: delete("constructor");
116: }
117:
118: public boolean has(String name, Scriptable start) {
119: return super .has(name, start)
120: || getPackageProperty(name, start) != NOT_FOUND;
121: }
122:
123: public Object get(String name, Scriptable start) {
124: Object result = super .get(name, start);
125: if (result != NOT_FOUND)
126: return result;
127: result = getPackageProperty(name, start);
128: return result;
129: }
130:
131: private Object getPackageProperty(String name, Scriptable start) {
132: Object result = NOT_FOUND;
133: Object[] elements;
134: synchronized (importedPackages) {
135: elements = importedPackages.toArray();
136: }
137: for (int i = 0; i < elements.length; i++) {
138: NativeJavaPackage p = (NativeJavaPackage) elements[i];
139: Object v = p.getPkgProperty(name, start, false);
140: if (v != null && !(v instanceof NativeJavaPackage)) {
141: if (result == NOT_FOUND) {
142: result = v;
143: } else {
144: throw Context.reportRuntimeError2(
145: "msg.ambig.import", result.toString(), v
146: .toString());
147: }
148: }
149: }
150: return result;
151: }
152:
153: /**
154: * @deprecated Kept only for compatibility.
155: */
156: public void importPackage(Context cx, Scriptable this Obj,
157: Object[] args, Function funObj) {
158: js_importPackage(args);
159: }
160:
161: private Object js_construct(Scriptable scope, Object[] args) {
162: ImporterTopLevel result = new ImporterTopLevel();
163: for (int i = 0; i != args.length; ++i) {
164: Object arg = args[i];
165: if (arg instanceof NativeJavaClass) {
166: result.importClass((NativeJavaClass) arg);
167: } else if (arg instanceof NativeJavaPackage) {
168: result.importPackage((NativeJavaPackage) arg);
169: } else {
170: throw Context.reportRuntimeError1(
171: "msg.not.class.not.pkg", Context.toString(arg));
172: }
173: }
174: // set explicitly prototype and scope
175: // as otherwise in top scope mode BaseFunction.construct
176: // would keep them set to null. It also allow to use
177: // JavaImporter without new and still get properly
178: // initialized object.
179: result.setParentScope(scope);
180: result.setPrototype(this );
181: return result;
182: }
183:
184: private Object js_importClass(Object[] args) {
185: for (int i = 0; i != args.length; i++) {
186: Object arg = args[i];
187: if (!(arg instanceof NativeJavaClass)) {
188: throw Context.reportRuntimeError1("msg.not.class",
189: Context.toString(arg));
190: }
191: importClass((NativeJavaClass) arg);
192: }
193: return Undefined.instance;
194: }
195:
196: private Object js_importPackage(Object[] args) {
197: for (int i = 0; i != args.length; i++) {
198: Object arg = args[i];
199: if (!(arg instanceof NativeJavaPackage)) {
200: throw Context.reportRuntimeError1("msg.not.pkg",
201: Context.toString(arg));
202: }
203: importPackage((NativeJavaPackage) arg);
204: }
205: return Undefined.instance;
206: }
207:
208: private void importPackage(NativeJavaPackage pkg) {
209: if (pkg == null) {
210: return;
211: }
212: synchronized (importedPackages) {
213: for (int j = 0; j != importedPackages.size(); j++) {
214: if (pkg.equals(importedPackages.get(j))) {
215: return;
216: }
217: }
218: importedPackages.add(pkg);
219: }
220: }
221:
222: private void importClass(NativeJavaClass cl) {
223: String s = cl.getClassObject().getName();
224: String n = s.substring(s.lastIndexOf('.') + 1);
225: Object val = get(n, this );
226: if (val != NOT_FOUND && val != cl) {
227: throw Context.reportRuntimeError1("msg.prop.defined", n);
228: }
229: //defineProperty(n, cl, DONTENUM);
230: put(n, this , cl);
231: }
232:
233: protected void initPrototypeId(int id) {
234: String s;
235: int arity;
236: switch (id) {
237: case Id_constructor:
238: arity = 0;
239: s = "constructor";
240: break;
241: case Id_importClass:
242: arity = 1;
243: s = "importClass";
244: break;
245: case Id_importPackage:
246: arity = 1;
247: s = "importPackage";
248: break;
249: default:
250: throw new IllegalArgumentException(String.valueOf(id));
251: }
252: initPrototypeMethod(IMPORTER_TAG, id, s, arity);
253: }
254:
255: public Object execIdCall(IdFunctionObject f, Context cx,
256: Scriptable scope, Scriptable this Obj, Object[] args) {
257: if (!f.hasTag(IMPORTER_TAG)) {
258: return super .execIdCall(f, cx, scope, this Obj, args);
259: }
260: int id = f.methodId();
261: switch (id) {
262: case Id_constructor:
263: return js_construct(scope, args);
264:
265: case Id_importClass:
266: return realThis(this Obj, f).js_importClass(args);
267:
268: case Id_importPackage:
269: return realThis(this Obj, f).js_importPackage(args);
270: }
271: throw new IllegalArgumentException(String.valueOf(id));
272: }
273:
274: private ImporterTopLevel realThis(Scriptable this Obj,
275: IdFunctionObject f) {
276: if (topScopeFlag) {
277: // when used as top scope importPackage and importClass are global
278: // function that ignore thisObj
279: return this ;
280: }
281: if (!(this Obj instanceof ImporterTopLevel))
282: throw incompatibleCallError(f);
283: return (ImporterTopLevel) this Obj;
284: }
285:
286: // #string_id_map#
287:
288: protected int findPrototypeId(String s) {
289: int id;
290: // #generated# Last update: 2007-05-09 08:15:24 EDT
291: L0: {
292: id = 0;
293: String X = null;
294: int c;
295: int s_length = s.length();
296: if (s_length == 11) {
297: c = s.charAt(0);
298: if (c == 'c') {
299: X = "constructor";
300: id = Id_constructor;
301: } else if (c == 'i') {
302: X = "importClass";
303: id = Id_importClass;
304: }
305: } else if (s_length == 13) {
306: X = "importPackage";
307: id = Id_importPackage;
308: }
309: if (X != null && X != s && !X.equals(s))
310: id = 0;
311: break L0;
312: }
313: // #/generated#
314: return id;
315: }
316:
317: private static final int Id_constructor = 1, Id_importClass = 2,
318: Id_importPackage = 3, MAX_PROTOTYPE_ID = 3;
319:
320: // #/string_id_map#
321:
322: private ObjArray importedPackages = new ObjArray();
323: private boolean topScopeFlag;
324: }
|