1/*
2 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23
24/**
25 * This script contains non-standard, Mozilla compatibility functionality on
26 * the standard global objects. Please note that it is incomplete. Only the most
27 * often used functionality is supported.
28 */
29
30// JavaAdapter
31Object.defineProperty(this, "JavaAdapter", {
32    configurable: true, enumerable: false, writable: true,
33    value: function() {
34        if (arguments.length < 2) {
35            throw new TypeError("JavaAdapter requires atleast two arguments");
36        }
37
38        var types = Array.prototype.slice.call(arguments, 0, arguments.length - 1);
39        var NewType = Java.extend.apply(Java, types);
40        return new NewType(arguments[arguments.length - 1]);
41    }
42});
43
44
45// importPackage
46// avoid unnecessary chaining of __noSuchProperty__ again
47// in case user loads this script more than once.
48if (typeof importPackage == 'undefined') {
49
50Object.defineProperty(this, "importPackage", {
51    configurable: true, enumerable: false, writable: true,
52    value: (function() {
53        var _packages = [];
54        var global = this;
55        var oldNoSuchProperty = global.__noSuchProperty__;
56        var __noSuchProperty__ = function(name) {
57            'use strict';
58            for (var i in _packages) {
59                try {
60                    var type = Java.type(_packages[i] + "." + name);
61                    global[name] = type;
62                    return type;
63                } catch (e) {}
64            }
65
66            if (oldNoSuchProperty) {
67                return oldNoSuchProperty.call(this, name);
68            } else {
69                if (this === undefined) {
70                    throw new ReferenceError(name + " is not defined");
71                } else {
72                    return undefined;
73                }
74            }
75        }
76
77        Object.defineProperty(global, "__noSuchProperty__", {
78            writable: true, configurable: true, enumerable: false,
79            value: __noSuchProperty__
80        });
81
82        var prefix = "[JavaPackage ";
83        return function() {
84            for (var i in arguments) {
85                var pkgName = arguments[i];
86                if ((typeof pkgName) != 'string') {
87                    pkgName = String(pkgName);
88                    // extract name from JavaPackage object
89                    if (pkgName.startsWith(prefix)) {
90                        pkgName = pkgName.substring(prefix.length, pkgName.length - 1);
91                    }
92                }
93                _packages.push(pkgName);
94            }
95        }
96    })()
97});
98
99}
100
101// sync
102Object.defineProperty(this, "sync", {
103    configurable: true, enumerable: false, writable: true,
104    value: function(func, syncobj) {
105        if (arguments.length < 1 || arguments.length > 2 ) {
106            throw "sync(function [,object]) parameter count mismatch";
107        }
108        return Java.synchronized(func, syncobj);
109    }
110});
111
112// Object.prototype.__defineGetter__
113Object.defineProperty(Object.prototype, "__defineGetter__", {
114    configurable: true, enumerable: false, writable: true,
115    value: function(name, func) {
116        Object.defineProperty(this, name, {
117            configurable: true, enumerable: true, get: func });
118    }
119});
120
121// Object.prototype.__defineSetter__
122Object.defineProperty(Object.prototype, "__defineSetter__", {
123    configurable: true, enumerable: false, writable: true,
124    value: function(name, func) {
125        Object.defineProperty(this, name, {
126            configurable: true, enumerable: true, set: func });
127    }
128});
129
130// Object.prototype.__lookupGetter__
131Object.defineProperty(Object.prototype, "__lookupGetter__", {
132    configurable: true, enumerable: false, writable: true,
133    value: function(name) {
134        var obj = this;
135        while (obj) {
136            var desc = Object.getOwnPropertyDescriptor(obj, name);
137            if (desc) return desc.get;
138            obj = Object.getPrototypeOf(obj);
139        }
140        return undefined;
141    }
142});
143
144// Object.prototype.__lookupSetter__
145Object.defineProperty(Object.prototype, "__lookupSetter__", {
146    configurable: true, enumerable: false, writable: true,
147    value: function(name) {
148        var obj = this;
149        while (obj) {
150            var desc = Object.getOwnPropertyDescriptor(obj, name);
151            if (desc) return desc.set;
152            obj = Object.getPrototypeOf(obj);
153        }
154        return undefined;
155    }
156});
157
158// Object.prototype.toSource
159Object.defineProperty(Object.prototype, "toSource", {
160    configurable: true, enumerable: false, writable: true,
161    value: function(state) {
162        if (! state) {
163            state = java.util.Collections.newSetFromMap(new java.util.HashMap());
164        }
165        if (state.contains(this)) {
166            return "{}";
167        }
168        state.add(this);
169        var str = new java.lang.StringBuffer('({');
170        for (i in this) {
171            str.append(i);
172            str.append(':');
173            if (this[i] instanceof Object && typeof(this[i].toSource) == 'function') {
174                str.append(this[i].toSource(state));
175            } else {
176                str.append(String(this[i]));
177            }
178            str.append(', ');
179        }
180        // delete last extra command and space
181        str = str.deleteCharAt(str.length() - 1);
182        str = str.deleteCharAt(str.length() - 1);
183        str.append('})');
184        return str.toString();
185    }
186});
187
188// Boolean.prototype.toSource
189Object.defineProperty(Boolean.prototype, "toSource", {
190    configurable: true, enumerable: false, writable: true,
191    value: function() {
192        return '(new Boolean(' + this.toString() + '))';
193    }
194});
195
196// Date.prototype.toSource
197Object.defineProperty(Date.prototype, "toSource", {
198    configurable: true, enumerable: false, writable: true,
199    value: function() {
200        return '(new Date(' + this.valueOf() + '))';
201    }
202});
203
204// Function.prototype.toSource -- already implemented in nashorn
205
206// Number.prototype.toSource
207Object.defineProperty(Number.prototype, "toSource", {
208    configurable: true, enumerable: false, writable: true,
209    value: function() {
210        return '(new Number(' + this.toString() + '))';
211    }
212});
213
214// RegExp.prototype.toSource
215Object.defineProperty(RegExp.prototype, "toSource", {
216    configurable: true, enumerable: false, writable: true,
217    value: function() {
218        return this.toString();
219    }
220});
221
222// String.prototype.toSource
223Object.defineProperty(String.prototype, "toSource", {
224    configurable: true, enumerable: false, writable: true,
225    value: function() {
226        return '(new String(' + this.quote() + '))';
227    }
228});
229
230// Error.prototype.toSource
231Object.defineProperty(Error.prototype, "toSource", {
232    configurable: true, enumerable: false, writable: true,
233    value: function() {
234        var msg = this.message? String(this.message).quote() : "''";
235        return '(new ' + this.name + '(' + msg + '))';
236    }
237});
238
239// Function.prototype.arity
240Object.defineProperty(Function.prototype, "arity", {
241    configurable: true, enumerable: false,
242    get: function() { return this.length; },
243    set: function(x) {
244        throw new TypeError("Function arity can not be modified");
245    }
246});
247
248// String.prototype.quote
249Object.defineProperty(String.prototype, "quote", {
250    configurable: true, enumerable: false, writable: true,
251    value: function() {
252        return JSON.stringify(this);
253    }
254});
255
256// HTML generation methods of String.prototype
257
258// String.prototype.anchor
259Object.defineProperty(String.prototype, "anchor", {
260    configurable: true, enumerable: false, writable: true,
261    value: function(name) {
262        return '<a name="' + name + '">' + this + '</a>';
263    }
264});
265
266// String.prototype.big
267Object.defineProperty(String.prototype, "big", {
268    configurable: true, enumerable: false, writable: true,
269    value: function() {
270        return '<big>' + this + '</big>';
271    }
272});
273
274// String.prototype.blink
275Object.defineProperty(String.prototype, "blink", {
276    configurable: true, enumerable: false, writable: true,
277    value: function() {
278        return '<blink>' + this + '</blink>';
279    }
280});
281
282// String.prototype.bold
283Object.defineProperty(String.prototype, "bold", {
284    configurable: true, enumerable: false, writable: true,
285    value: function() {
286        return '<b>' + this + '</b>';
287    }
288});
289
290// String.prototype.fixed
291Object.defineProperty(String.prototype, "fixed", {
292    configurable: true, enumerable: false, writable: true,
293    value: function() {
294        return '<tt>' + this + '</tt>';
295    }
296});
297
298// String.prototype.fontcolor
299Object.defineProperty(String.prototype, "fontcolor", {
300    configurable: true, enumerable: false, writable: true,
301    value: function(clr) {
302        return '<font color="' + clr + '">' + this + '</font>';
303    }
304});
305
306// String.prototype.fontsize
307Object.defineProperty(String.prototype, "fontsize", {
308    configurable: true, enumerable: false, writable: true,
309    value: function(size) {
310        return '<font size="' + size + '">' + this + '</font>';
311    }
312});
313
314// String.prototype.italics
315Object.defineProperty(String.prototype, "italics", {
316    configurable: true, enumerable: false, writable: true,
317    value: function() {
318        return '<i>' + this + '</i>';
319    }
320});
321
322// String.prototype.link
323Object.defineProperty(String.prototype, "link", {
324    configurable: true, enumerable: false, writable: true,
325    value: function(url) {
326        return '<a href="' + url + '">' + this + '</a>';
327    }
328});
329
330// String.prototype.small
331Object.defineProperty(String.prototype, "small", {
332    configurable: true, enumerable: false, writable: true,
333    value: function() {
334        return '<small>' + this + '</small>';
335    }
336});
337
338// String.prototype.strike
339Object.defineProperty(String.prototype, "strike", {
340    configurable: true, enumerable: false, writable: true,
341    value: function() {
342        return '<strike>' + this + '</strike>';
343    }
344});
345
346// String.prototype.sub
347Object.defineProperty(String.prototype, "sub", {
348    configurable: true, enumerable: false, writable: true,
349    value: function() {
350        return '<sub>' + this + '</sub>';
351    }
352});
353
354// String.prototype.sup
355Object.defineProperty(String.prototype, "sup", {
356    configurable: true, enumerable: false, writable: true,
357    value: function() {
358        return '<sup>' + this + '</sup>';
359    }
360});
361
362// Rhino: global.importClass
363Object.defineProperty(this, "importClass", {
364    configurable: true, enumerable: false, writable: true,
365    value: function() {
366        for (var arg in arguments) {
367            var clazz = arguments[arg];
368            if (Java.isType(clazz)) {
369                var className = Java.typeName(clazz);
370                var simpleName = className.substring(className.lastIndexOf('.') + 1);
371                this[simpleName] = clazz;
372            } else {
373                throw new TypeError(clazz + " is not a Java class");
374            }
375        }
376    }
377});
378