2002/03/21 01:19:33
[org.ibex.core.git] / src / org / mozilla / javascript / NativeJavaPackage.java
1 /* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-\r
2  *\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
7  *\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
12  *\r
13  * The Original Code is Rhino code, released\r
14  * May 6, 1999.\r
15  *\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
19  * Rights Reserved.\r
20  *\r
21  * Contributor(s): \r
22  * Norris Boyd\r
23  * Frank Mitchell\r
24  * Mike Shaver\r
25  *\r
26  * Alternatively, the contents of this file may be used under the\r
27  * terms of the GNU Public License (the "GPL"), in which case the\r
28  * provisions of the GPL are applicable instead of those above.\r
29  * If you wish to allow use of your version of this file only\r
30  * under the terms of the GPL and not to allow others to use your\r
31  * version of this file under the NPL, indicate your decision by\r
32  * deleting the provisions above and replace them with the notice\r
33  * and other provisions required by the GPL.  If you do not delete\r
34  * the provisions above, a recipient may use your version of this\r
35  * file under either the NPL or the GPL.\r
36  */\r
37 \r
38 package org.mozilla.javascript;\r
39 \r
40 import java.lang.reflect.*;\r
41 \r
42 /**\r
43  * This class reflects Java packages into the JavaScript environment.  We \r
44  * lazily reflect classes and subpackages, and use a caching/sharing \r
45  * system to ensure that members reflected into one JavaPackage appear\r
46  * in all other references to the same package (as with Packages.java.lang \r
47  * and java.lang).\r
48  *\r
49  * @author Mike Shaver\r
50  * @see NativeJavaArray\r
51  * @see NativeJavaObject\r
52  * @see NativeJavaClass\r
53  */\r
54 \r
55 public class NativeJavaPackage extends ScriptableObject {\r
56 \r
57     // we know these are packages so we can skip the class check\r
58     // note that this is ok even if the package isn't present.\r
59     static final String[] commonPackages = {\r
60         "java.lang",\r
61         "java.lang.reflect",\r
62         "java.io",\r
63         "java.math",\r
64         "java.util",\r
65         "java.util.zip",\r
66         "java.text",\r
67         "java.text.resources",\r
68         "java.applet",\r
69     };\r
70 \r
71     public static Scriptable init(Scriptable scope) \r
72         throws PropertyException\r
73     {\r
74         NativeJavaPackage packages = new NativeJavaPackage("");\r
75         packages.setPrototype(getObjectPrototype(scope));\r
76         packages.setParentScope(scope);\r
77 \r
78         // We want to get a real alias, and not a distinct JavaPackage\r
79         // with the same packageName, so that we share classes and packages\r
80         // that are underneath.\r
81         NativeJavaPackage javaAlias = (NativeJavaPackage)packages.get("java",\r
82                                                                       packages);\r
83 \r
84         // It's safe to downcast here since initStandardObjects takes\r
85         // a ScriptableObject.\r
86         ScriptableObject global = (ScriptableObject) scope;\r
87 \r
88         global.defineProperty("Packages", packages, ScriptableObject.DONTENUM);\r
89         global.defineProperty("java", javaAlias, ScriptableObject.DONTENUM);\r
90 \r
91         for (int i = 0; i < commonPackages.length; i++)\r
92             packages.forcePackage(commonPackages[i]);\r
93 \r
94         if (Context.useJSObject)\r
95             NativeJavaObject.initJSObject();\r
96         \r
97         Method[] m = FunctionObject.findMethods(NativeJavaPackage.class, \r
98                                                 "jsFunction_getClass");\r
99         FunctionObject f = new FunctionObject("getClass", m[0], global);\r
100         global.defineProperty("getClass", f, ScriptableObject.DONTENUM);\r
101 \r
102         // I think I'm supposed to return the prototype, but I don't have one.\r
103         return packages;\r
104     }\r
105 \r
106     // set up a name which is known to be a package so we don't\r
107     // need to look for a class by that name\r
108     void forcePackage(String name) {\r
109         NativeJavaPackage pkg;\r
110         int end = name.indexOf('.');\r
111         if (end == -1)\r
112             end = name.length();\r
113 \r
114         String id = name.substring(0, end);\r
115         Object cached = super.get(id, this);\r
116         if (cached != null && cached instanceof NativeJavaPackage) {\r
117             pkg = (NativeJavaPackage) cached;\r
118         } else {\r
119             String newPackage = packageName.length() == 0 \r
120                                 ? id \r
121                                 : packageName + "." + id;\r
122             pkg = new NativeJavaPackage(newPackage);\r
123             pkg.setParentScope(this);\r
124             pkg.setPrototype(this.prototype);\r
125             super.put(id, this, pkg);\r
126         }\r
127         if (end < name.length())\r
128             pkg.forcePackage(name.substring(end+1));\r
129     }\r
130 \r
131     public NativeJavaPackage(String packageName) {\r
132         this.packageName = packageName;\r
133     }\r
134 \r
135     public String getClassName() {\r
136         return "JavaPackage";\r
137     }\r
138 \r
139     public boolean has(String id, int index, Scriptable start) {\r
140         return true;\r
141     }\r
142 \r
143     public void put(String id, Scriptable start, Object value) {\r
144         // Can't add properties to Java packages.  Sorry.\r
145     }\r
146 \r
147     public void put(int index, Scriptable start, Object value) {\r
148         throw Context.reportRuntimeError0("msg.pkg.int");\r
149     }\r
150 \r
151     public Object get(String id, Scriptable start) {\r
152         return getPkgProperty(id, start, true);\r
153     }\r
154 \r
155     public Object get(int index, Scriptable start) {\r
156         return NOT_FOUND;\r
157     }\r
158 \r
159     synchronized Object getPkgProperty(String name, Scriptable start,\r
160                                        boolean createPkg) \r
161     {\r
162         Object cached = super.get(name, start);\r
163         if (cached != NOT_FOUND)\r
164             return cached;\r
165         \r
166         String newPackage = packageName.length() == 0\r
167                             ? name \r
168                             : packageName + "." + name;\r
169         Context cx = Context.getContext();\r
170         SecuritySupport ss = cx.getSecuritySupport();\r
171         Scriptable newValue;\r
172         try {\r
173             /*\r
174             if (ss != null && !ss.visibleToScripts(newPackage))\r
175             */\r
176                 throw new ClassNotFoundException();\r
177                 /*\r
178             Class newClass = ScriptRuntime.loadClassName(newPackage);\r
179             newValue =  NativeJavaClass.wrap(getTopLevelScope(this), newClass);\r
180             newValue.setParentScope(this);\r
181             newValue.setPrototype(this.prototype);\r
182                 */\r
183         } catch (ClassNotFoundException ex) {\r
184             if (createPkg) {\r
185                 NativeJavaPackage pkg = new NativeJavaPackage(newPackage);\r
186                 pkg.setParentScope(this);\r
187                 pkg.setPrototype(this.prototype);\r
188                 newValue = pkg;\r
189             } else {\r
190                 newValue = null;\r
191             }\r
192         }\r
193         if (newValue != null) {\r
194             // Make it available for fast lookup and sharing of \r
195             // lazily-reflected constructors and static members.\r
196             super.put(name, start, newValue);\r
197         }\r
198         return newValue;\r
199     }\r
200 \r
201     public Object getDefaultValue(Class ignored) {\r
202         return toString();\r
203     }\r
204 \r
205     public String toString() {\r
206         return "[JavaPackage " + packageName + "]";\r
207     }\r
208     \r
209     public static Scriptable jsFunction_getClass(Context cx, \r
210                                                  Scriptable thisObj,\r
211                                                  Object[] args, \r
212                                                  Function funObj)\r
213     {\r
214         if (args.length > 0  && args[0] instanceof Wrapper) {\r
215             Scriptable result = getTopLevelScope(thisObj);\r
216             Class cl = ((Wrapper) args[0]).unwrap().getClass();\r
217             // Evaluate the class name by getting successive properties of \r
218             // the string to find the appropriate NativeJavaClass object\r
219             String name = "Packages." + cl.getName();\r
220             int offset = 0;\r
221             for (;;) {\r
222                 int index = name.indexOf('.', offset);\r
223                 String propName = index == -1\r
224                                   ? name.substring(offset)\r
225                                   : name.substring(offset, index);\r
226                 Object prop = result.get(propName, result);\r
227                 if (!(prop instanceof Scriptable)) \r
228                     break;  // fall through to error\r
229                 result = (Scriptable) prop;\r
230                 if (index == -1)\r
231                     return result;\r
232                 offset = index+1;\r
233             }\r
234         }\r
235         throw Context.reportRuntimeError(\r
236             Context.getMessage0("msg.not.java.obj"));\r
237     }\r
238 \r
239     private String packageName;\r
240 }\r