aboutsummaryrefslogtreecommitdiffstats
path: root/plugin/icedteanp/java
diff options
context:
space:
mode:
Diffstat (limited to 'plugin/icedteanp/java')
-rw-r--r--plugin/icedteanp/java/netscape/javascript/JSException.java140
-rw-r--r--plugin/icedteanp/java/netscape/javascript/JSObject.java297
-rw-r--r--plugin/icedteanp/java/netscape/javascript/JSObjectCreatePermission.java47
-rw-r--r--plugin/icedteanp/java/netscape/javascript/JSProxy.java58
-rw-r--r--plugin/icedteanp/java/netscape/javascript/JSRunnable.java72
-rw-r--r--plugin/icedteanp/java/netscape/javascript/JSUtil.java59
-rw-r--r--plugin/icedteanp/java/netscape/security/ForbiddenTargetException.java52
-rw-r--r--plugin/icedteanp/java/sun/applet/AppletSecurityContextManager.java71
-rw-r--r--plugin/icedteanp/java/sun/applet/GetMemberPluginCallRequest.java63
-rw-r--r--plugin/icedteanp/java/sun/applet/GetWindowPluginCallRequest.java65
-rw-r--r--plugin/icedteanp/java/sun/applet/JavaConsole.java365
-rw-r--r--plugin/icedteanp/java/sun/applet/MethodOverloadResolver.java696
-rw-r--r--plugin/icedteanp/java/sun/applet/PasswordAuthenticationDialog.java241
-rw-r--r--plugin/icedteanp/java/sun/applet/PluginAppletSecurityContext.java1505
-rw-r--r--plugin/icedteanp/java/sun/applet/PluginAppletViewer.java2056
-rw-r--r--plugin/icedteanp/java/sun/applet/PluginCallRequest.java89
-rw-r--r--plugin/icedteanp/java/sun/applet/PluginCallRequestFactory.java61
-rw-r--r--plugin/icedteanp/java/sun/applet/PluginClassLoader.java51
-rw-r--r--plugin/icedteanp/java/sun/applet/PluginCookieInfoRequest.java74
-rw-r--r--plugin/icedteanp/java/sun/applet/PluginCookieManager.java88
-rw-r--r--plugin/icedteanp/java/sun/applet/PluginDebug.java51
-rw-r--r--plugin/icedteanp/java/sun/applet/PluginException.java53
-rw-r--r--plugin/icedteanp/java/sun/applet/PluginMain.java319
-rw-r--r--plugin/icedteanp/java/sun/applet/PluginMessageConsumer.java268
-rw-r--r--plugin/icedteanp/java/sun/applet/PluginMessageHandlerWorker.java147
-rw-r--r--plugin/icedteanp/java/sun/applet/PluginObjectStore.java132
-rw-r--r--plugin/icedteanp/java/sun/applet/PluginProxyInfoRequest.java81
-rw-r--r--plugin/icedteanp/java/sun/applet/PluginProxySelector.java195
-rw-r--r--plugin/icedteanp/java/sun/applet/PluginStreamHandler.java454
-rw-r--r--plugin/icedteanp/java/sun/applet/RequestQueue.java77
-rw-r--r--plugin/icedteanp/java/sun/applet/TestEnv.java172
-rw-r--r--plugin/icedteanp/java/sun/applet/VoidPluginCallRequest.java54
32 files changed, 8153 insertions, 0 deletions
diff --git a/plugin/icedteanp/java/netscape/javascript/JSException.java b/plugin/icedteanp/java/netscape/javascript/JSException.java
new file mode 100644
index 0000000..96ba310
--- /dev/null
+++ b/plugin/icedteanp/java/netscape/javascript/JSException.java
@@ -0,0 +1,140 @@
+/* -*- Mode: Java; tab-width: 8; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+package netscape.javascript;
+
+/**
+ * JSException is an exception which is thrown when JavaScript code
+ * returns an error.
+ */
+
+public
+class JSException extends RuntimeException {
+ public static final int EXCEPTION_TYPE_EMPTY = -1;
+ public static final int EXCEPTION_TYPE_VOID = 0;
+ public static final int EXCEPTION_TYPE_OBJECT = 1;
+ public static final int EXCEPTION_TYPE_FUNCTION = 2;
+ public static final int EXCEPTION_TYPE_STRING = 3;
+ public static final int EXCEPTION_TYPE_NUMBER = 4;
+ public static final int EXCEPTION_TYPE_BOOLEAN = 5;
+ public static final int EXCEPTION_TYPE_ERROR = 6;
+
+ public String filename;
+ public int lineno;
+ public String source;
+ public int tokenIndex;
+ public int wrappedExceptionType;
+ public Object wrappedException;
+
+ /**
+ * Constructs a JSException without a detail message.
+ * A detail message is a String that describes this particular exception.
+ *
+ * @deprecated Not for public use in future versions.
+ */
+ public JSException() {
+ super();
+ filename = "unknown";
+ lineno = 0;
+ source = "";
+ tokenIndex = 0;
+ wrappedExceptionType = EXCEPTION_TYPE_EMPTY;
+ }
+
+ /**
+ * Constructs a JSException with a detail message.
+ * A detail message is a String that describes this particular exception.
+ * @param s the detail message
+ *
+ * @deprecated Not for public use in future versions.
+ */
+ public JSException(String s) {
+ super(s);
+ filename = "unknown";
+ lineno = 0;
+ source = "";
+ tokenIndex = 0;
+ wrappedExceptionType = EXCEPTION_TYPE_EMPTY;
+ }
+
+ /**
+ * Constructs a JSException with a wrapped JavaScript exception object.
+ * This constructor needs to be public so that Java users can throw
+ * exceptions to JS cleanly.
+ */
+ public JSException(int wrappedExceptionType, Object wrappedException) {
+ super();
+ this.wrappedExceptionType = wrappedExceptionType;
+ this.wrappedException = wrappedException;
+ }
+
+ /**
+ * Constructs a JSException with a detail message and all the
+ * other info that usually comes with a JavaScript error.
+ * @param s the detail message
+ *
+ * @deprecated Not for public use in future versions.
+ */
+ public JSException(String s, String filename, int lineno,
+ String source, int tokenIndex) {
+ super(s);
+ this.filename = filename;
+ this.lineno = lineno;
+ this.source = source;
+ this.tokenIndex = tokenIndex;
+ wrappedExceptionType = EXCEPTION_TYPE_EMPTY;
+ }
+
+ /**
+ * Instance method getWrappedExceptionType returns the int mapping of the
+ * type of the wrappedException Object.
+ */
+ public int getWrappedExceptionType() {
+ return wrappedExceptionType;
+ }
+
+ /**
+ * Instance method getWrappedException.
+ */
+ public Object getWrappedException() {
+ return wrappedException;
+ }
+
+}
+
diff --git a/plugin/icedteanp/java/netscape/javascript/JSObject.java b/plugin/icedteanp/java/netscape/javascript/JSObject.java
new file mode 100644
index 0000000..74158c2
--- /dev/null
+++ b/plugin/icedteanp/java/netscape/javascript/JSObject.java
@@ -0,0 +1,297 @@
+/* -*- Mode: Java; tab-width: 8; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* more doc todo:
+ * threads
+ * gc
+ *
+ *
+ */
+
+package netscape.javascript;
+
+import java.applet.Applet;
+import java.security.AccessControlContext;
+import java.security.AccessControlException;
+import java.security.AccessController;
+import java.security.BasicPermission;
+
+import sun.applet.PluginAppletViewer;
+import sun.applet.PluginDebug;
+
+
+
+/**
+ * JSObject allows Java to manipulate objects that are
+ * defined in JavaScript.
+ * Values passed from Java to JavaScript are converted as
+ * follows:<ul>
+ * <li>JSObject is converted to the original JavaScript object
+ * <li>Any other Java object is converted to a JavaScript wrapper,
+ * which can be used to access methods and fields of the java object.
+ * Converting this wrapper to a string will call the toString method
+ * on the original object, converting to a number will call the
+ * doubleValue method if possible and fail otherwise. Converting
+ * to a boolean will try to call the booleanValue method in the
+ * same way.
+ * <li>Java arrays are wrapped with a JavaScript object that understands
+ * array.length and array[index]
+ * <li>A Java boolean is converted to a JavaScript boolean
+ * <li>Java byte, char, short, int, long, float, and double are converted
+ * to JavaScript numbers
+ * </ul>
+ * Values passed from JavaScript to Java are converted as follows:<ul>
+ * <li>objects which are wrappers around java objects are unwrapped
+ * <li>other objects are wrapped with a JSObject
+ * <li>strings, numbers and booleans are converted to String, Double,
+ * and Boolean objects respectively
+ * </ul>
+ * This means that all JavaScript values show up as some kind
+ * of java.lang.Object in Java. In order to make much use of them,
+ * you will have to cast them to the appropriate subclass of Object,
+ * e.g. <code>(String) window.getMember("name");</code> or
+ * <code>(JSObject) window.getMember("document");</code>.
+ */
+public final class JSObject {
+ /* the internal object data */
+ private long internal;
+
+ /**
+ * initialize
+ */
+ private static void initClass() {
+ PluginDebug.debug ("JSObject.initClass");
+ }
+
+ static {
+ PluginDebug.debug ("JSObject INITIALIZER");
+ }
+
+ /**
+ * it is illegal to construct a JSObject manually
+ */
+ public JSObject(int jsobj_addr) {
+ this((long) jsobj_addr);
+ }
+
+ /**
+ * it is illegal to construct a JSObject manually
+ */
+ public JSObject(String jsobj_addr) {
+ this((long) Long.parseLong(jsobj_addr));
+ }
+
+ public JSObject(long jsobj_addr) {
+
+ // See if the caller has permission
+
+ try {
+ AccessController.getContext().checkPermission(new JSObjectCreatePermission());
+ } catch (AccessControlException ace) {
+
+ // If not, only caller with JSObject.getWindow on the stack may
+ // make this call unprivileged.
+
+ // Although this check is inefficient, it should happen only once
+ // during applet init, so we look the other way
+
+ StackTraceElement[] stack = Thread.currentThread().getStackTrace();
+ boolean mayProceed = false;
+
+ for (int i=0; i < stack.length; i++) {
+ if (stack[i].getClassName().equals("netscape.javascript.JSObject") &&
+ stack[i].getMethodName().equals("getWindow")) {
+ mayProceed = true;
+ }
+ }
+
+ if (!mayProceed) throw ace;
+ }
+
+ PluginDebug.debug ("JSObject long CONSTRUCTOR");
+ internal = jsobj_addr;
+ }
+
+ /**
+ * Retrieves a named member of a JavaScript object.
+ * Equivalent to "this.<i>name</i>" in JavaScript.
+ */
+ public Object getMember(String name)
+ {
+ PluginDebug.debug ("JSObject.getMember " + name);
+
+ Object o = PluginAppletViewer.getMember(internal, name);
+ PluginDebug.debug ("JSObject.getMember GOT " + o);
+ return o;
+ }
+
+
+ /**
+ * Retrieves an indexed member of a JavaScript object.
+ * Equivalent to "this[<i>index</i>]" in JavaScript.
+ */
+ // public Object getMember(int index) { return getSlot(index); }
+ public Object getSlot(int index)
+ {
+ PluginDebug.debug ("JSObject.getSlot " + index);
+
+ return PluginAppletViewer.getSlot(internal, index);
+ }
+
+
+ /**
+ * Sets a named member of a JavaScript object.
+ * Equivalent to "this.<i>name</i> = <i>value</i>" in JavaScript.
+ */
+ public void setMember(String name, Object value)
+ {
+ PluginDebug.debug ("JSObject.setMember " + name + " " + value);
+
+ PluginAppletViewer.setMember(internal, name, value);
+ }
+
+ /**
+ * Sets an indexed member of a JavaScript object.
+ * Equivalent to "this[<i>index</i>] = <i>value</i>" in JavaScript.
+ */
+ // public void setMember(int index, Object value) {
+ // setSlot(index, value);
+ // }
+ public void setSlot(int index, Object value)
+ {
+ PluginDebug.debug ("JSObject.setSlot " + index + " " + value);
+
+ PluginAppletViewer.setSlot(internal, index, value);
+ }
+
+
+ // TODO: toString, finalize.
+
+ /**
+ * Removes a named member of a JavaScript object.
+ */
+ public void removeMember(String name)
+ {
+ PluginDebug.debug ("JSObject.removeMember " + name);
+
+ PluginAppletViewer.removeMember(internal, name);
+ }
+
+
+ /**
+ * Calls a JavaScript method.
+ * Equivalent to "this.<i>methodName</i>(<i>args</i>[0], <i>args</i>[1], ...)" in JavaScript.
+ */
+ public Object call(String methodName, Object args[])
+ {
+ if (args == null)
+ args = new Object[0];
+
+ PluginDebug.debug ("JSObject.call " + methodName);
+ for (int i = 0; i < args.length; i++)
+ PluginDebug.debug (" " + args[i]);
+ PluginDebug.debug("");
+ return PluginAppletViewer.call(internal, methodName, args);
+ }
+
+
+ /**
+ * Evaluates a JavaScript expression. The expression is a string
+ * of JavaScript source code which will be evaluated in the context
+ * given by "this".
+ */
+ public Object eval(String s)
+ {
+ PluginDebug.debug("JSObject.eval " + s);
+ return PluginAppletViewer.eval(internal, s);
+ }
+
+
+ /**
+ * Converts a JSObject to a String.
+ */
+ public String toString()
+ {
+ PluginDebug.debug("JSObject.toString");
+ return PluginAppletViewer.javascriptToString(internal);
+ }
+
+
+ // should use some sort of identifier rather than String
+ // is "property" the right word?
+ // native String[] listProperties();
+
+
+ /**
+ * get a JSObject for the window containing the given applet
+ */
+ public static JSObject getWindow(Applet applet)
+ {
+ PluginDebug.debug("JSObject.getWindow");
+ // FIXME: handle long case as well.
+ long internal = 0;
+ internal = ((PluginAppletViewer)
+ applet.getAppletContext()).getWindow();
+ PluginDebug.debug ("GOT IT: " + internal);
+ return new JSObject((long) internal);
+ }
+
+
+ /**
+ * Finalization decrements the reference count on the corresponding
+ * JavaScript object.
+ */
+ protected void finalize()
+ {
+ PluginDebug.debug("JSObject.finalize ");
+ PluginAppletViewer.JavaScriptFinalize(internal);
+ }
+
+
+ /**
+ * Override java.lang.Object.equals() because identity is not preserved
+ * with instances of JSObject.
+ */
+ public boolean equals(Object obj)
+ {
+ PluginDebug.debug("JSObject.equals " + obj);
+
+ return false;
+ }
+}
diff --git a/plugin/icedteanp/java/netscape/javascript/JSObjectCreatePermission.java b/plugin/icedteanp/java/netscape/javascript/JSObjectCreatePermission.java
new file mode 100644
index 0000000..f8e510f
--- /dev/null
+++ b/plugin/icedteanp/java/netscape/javascript/JSObjectCreatePermission.java
@@ -0,0 +1,47 @@
+/* JSObjectCreatePermission.java
+ Copyright (C) 2009 Red Hat
+
+This file is part of IcedTea.
+
+IcedTea is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+IcedTea is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with IcedTea; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package netscape.javascript;
+
+import java.security.BasicPermission;
+
+
+public class JSObjectCreatePermission extends BasicPermission {
+ public JSObjectCreatePermission() {
+ super("JSObjectCreate");
+ }
+}
diff --git a/plugin/icedteanp/java/netscape/javascript/JSProxy.java b/plugin/icedteanp/java/netscape/javascript/JSProxy.java
new file mode 100644
index 0000000..e4f1f6e
--- /dev/null
+++ b/plugin/icedteanp/java/netscape/javascript/JSProxy.java
@@ -0,0 +1,58 @@
+/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/**
+ * The JSProxy interface allows applets and plugins to
+ * share javascript contexts.
+ */
+
+package netscape.javascript;
+import java.applet.Applet;
+
+public interface JSProxy {
+ Object getMember(JSObject jso, String name);
+ Object getSlot(JSObject jso, int index);
+ void setMember(JSObject jso, String name, Object value);
+ void setSlot(JSObject jso, int index, Object value);
+ void removeMember(JSObject jso, String name);
+ Object call(JSObject jso, String methodName, Object args[]);
+ Object eval(JSObject jso, String s);
+ String toString(JSObject jso);
+ JSObject getWindow(Applet applet);
+}
diff --git a/plugin/icedteanp/java/netscape/javascript/JSRunnable.java b/plugin/icedteanp/java/netscape/javascript/JSRunnable.java
new file mode 100644
index 0000000..8f1cf72
--- /dev/null
+++ b/plugin/icedteanp/java/netscape/javascript/JSRunnable.java
@@ -0,0 +1,72 @@
+/* -*- Mode: Java; tab-width: 8; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+package netscape.javascript;
+
+import sun.applet.PluginDebug;
+
+/**
+ * Runs a JavaScript object with a run() method in a separate thread.
+ */
+public class JSRunnable implements Runnable {
+ private JSObject runnable;
+
+ public JSRunnable(JSObject runnable) {
+ this.runnable = runnable;
+ synchronized(this) {
+ new Thread(this).start();
+ try {
+ this.wait();
+ } catch (InterruptedException ie) {
+ }
+ }
+ }
+
+ public void run() {
+ try {
+ runnable.call("run", null);
+ synchronized(this) {
+ notifyAll();
+ }
+ } catch (Throwable t) {
+ PluginDebug.debug(t.toString());
+ t.printStackTrace(System.err);
+ }
+ }
+}
diff --git a/plugin/icedteanp/java/netscape/javascript/JSUtil.java b/plugin/icedteanp/java/netscape/javascript/JSUtil.java
new file mode 100644
index 0000000..47bc6e6
--- /dev/null
+++ b/plugin/icedteanp/java/netscape/javascript/JSUtil.java
@@ -0,0 +1,59 @@
+/* -*- Mode: Java; tab-width: 8; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+/* ** */
+
+package netscape.javascript;
+import java.io.*;
+
+public class JSUtil {
+
+ /* Return the stack trace of an exception or error as a String */
+ public static String getStackTrace(Throwable t) {
+ ByteArrayOutputStream captureStream;
+ PrintWriter p;
+
+ captureStream = new ByteArrayOutputStream();
+ p = new PrintWriter(captureStream);
+
+ t.printStackTrace(p);
+ p.flush();
+
+ return captureStream.toString();
+ }
+}
diff --git a/plugin/icedteanp/java/netscape/security/ForbiddenTargetException.java b/plugin/icedteanp/java/netscape/security/ForbiddenTargetException.java
new file mode 100644
index 0000000..c7ce827
--- /dev/null
+++ b/plugin/icedteanp/java/netscape/security/ForbiddenTargetException.java
@@ -0,0 +1,52 @@
+/* ForbiddenTargetException.java
+ Copyright (C) 2010 Red Hat
+
+This file is part of IcedTea.
+
+IcedTea is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+IcedTea is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with IcedTea; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package netscape.security;
+
+public class ForbiddenTargetException extends RuntimeException{
+
+ private static final long serialVersionUID = 1271219852541058396L;
+
+ public ForbiddenTargetException() {
+ super();
+ }
+
+ public ForbiddenTargetException(String s) {
+ super(s);
+ }
+
+}
diff --git a/plugin/icedteanp/java/sun/applet/AppletSecurityContextManager.java b/plugin/icedteanp/java/sun/applet/AppletSecurityContextManager.java
new file mode 100644
index 0000000..3820aa4
--- /dev/null
+++ b/plugin/icedteanp/java/sun/applet/AppletSecurityContextManager.java
@@ -0,0 +1,71 @@
+/* VoidPluginCallRequest -- represent Java-to-JavaScript requests
+ Copyright (C) 2008 Red Hat
+
+This file is part of IcedTea.
+
+IcedTea is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+IcedTea is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with IcedTea; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package sun.applet;
+
+import java.security.AccessControlContext;
+import java.util.HashMap;
+
+public class AppletSecurityContextManager {
+
+ // Context identifier -> PluginAppletSecurityContext object.
+ // FIXME: make private
+ private static HashMap<Integer, PluginAppletSecurityContext> contexts = new HashMap();
+
+ public static void addContext(int identifier, PluginAppletSecurityContext context) {
+ contexts.put(identifier, context);
+ }
+
+ public static PluginAppletSecurityContext getSecurityContext(int identifier) {
+ return contexts.get(identifier);
+ }
+
+ public static void dumpStore(int identifier) {
+ contexts.get(identifier).dumpStore();
+ }
+
+ public static void handleMessage(int identifier, int reference, String src, String[] privileges, String message) {
+ PluginDebug.debug(identifier + " -- " + src + " -- " + reference + " -- " + message + " CONTEXT= " + contexts.get(identifier));
+ AccessControlContext callContext = null;
+
+ privileges = privileges != null ? privileges : new String[0];
+ callContext = contexts.get(identifier).getAccessControlContext(privileges, src);
+
+ contexts.get(identifier).handleMessage(reference, src, callContext, message);
+ }
+}
diff --git a/plugin/icedteanp/java/sun/applet/GetMemberPluginCallRequest.java b/plugin/icedteanp/java/sun/applet/GetMemberPluginCallRequest.java
new file mode 100644
index 0000000..7a0a623
--- /dev/null
+++ b/plugin/icedteanp/java/sun/applet/GetMemberPluginCallRequest.java
@@ -0,0 +1,63 @@
+/* GetMemberPluginCallRequest -- represent Java-to-JavaScript requests
+ Copyright (C) 2008 Red Hat
+
+This file is part of IcedTea.
+
+IcedTea is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+IcedTea is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with IcedTea; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package sun.applet;
+
+
+public class GetMemberPluginCallRequest extends PluginCallRequest {
+ Object object = null;
+
+ public GetMemberPluginCallRequest(String message, Long reference) {
+ super(message, reference);
+ PluginDebug.debug ("GetMemberPluginCall " + message);
+ }
+
+ public void parseReturn(String message) {
+ PluginDebug.debug ("GetMemberParseReturn GOT: " + message);
+ String[] args = message.split(" ");
+ // FIXME: Is it even possible to distinguish between null and void
+ // here?
+ if (args[3] != "null" && args[3] != "void")
+ object = AppletSecurityContextManager.getSecurityContext(0).getObject(Integer.parseInt(args[3]));
+ setDone(true);
+ }
+
+ public Object getObject() {
+ return this.object;
+ }
+}
+
diff --git a/plugin/icedteanp/java/sun/applet/GetWindowPluginCallRequest.java b/plugin/icedteanp/java/sun/applet/GetWindowPluginCallRequest.java
new file mode 100644
index 0000000..9c13726
--- /dev/null
+++ b/plugin/icedteanp/java/sun/applet/GetWindowPluginCallRequest.java
@@ -0,0 +1,65 @@
+/* GetWindowPluginCallRequest -- represent Java-to-JavaScript requests
+ Copyright (C) 2008 Red Hat
+
+This file is part of IcedTea.
+
+IcedTea is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+IcedTea is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with IcedTea; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package sun.applet;
+
+import java.security.AccessControlContext;
+import java.security.ProtectionDomain;
+
+
+
+public class GetWindowPluginCallRequest extends PluginCallRequest {
+ // FIXME: look into int vs long JavaScript internal values.
+ long internal;
+
+ public GetWindowPluginCallRequest(String message, Long reference) {
+ super(message, reference);
+ }
+
+ public void parseReturn(String message) {
+ PluginDebug.debug ("GetWindowParseReturn GOT: " + message);
+ String[] args = message.split(" ");
+ // FIXME: add thread ID to messages to support multiple
+ // threads using the netscape.javascript package.
+ internal = Long.parseLong(args[3]);
+ setDone(true);
+ }
+
+ public Long getObject() {
+ return this.internal;
+ }
+}
diff --git a/plugin/icedteanp/java/sun/applet/JavaConsole.java b/plugin/icedteanp/java/sun/applet/JavaConsole.java
new file mode 100644
index 0000000..768be7b
--- /dev/null
+++ b/plugin/icedteanp/java/sun/applet/JavaConsole.java
@@ -0,0 +1,365 @@
+/* JavaConsole -- A java console for the plugin
+ Copyright (C) 2009 Red Hat
+
+This file is part of IcedTea.
+
+IcedTea is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+IcedTea is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with IcedTea; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package sun.applet;
+
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+import javax.swing.JButton;
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JSplitPane;
+import javax.swing.JTextArea;
+import javax.swing.SwingUtilities;
+import javax.swing.UIManager;
+import javax.swing.border.EmptyBorder;
+import javax.swing.border.TitledBorder;
+
+/**
+ * A simple Java console for IcedTeaPlugin
+ *
+ */
+public class JavaConsole {
+
+ private boolean initialized = false;
+
+ JFrame consoleWindow;
+ JTextArea stdErrText;
+ JTextArea stdOutText;
+
+ /**
+ * Initialize the console
+ */
+ public void initialize() {
+
+ try {
+ UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ consoleWindow = new JFrame("Java Console");
+
+ JPanel contentPanel = new JPanel();
+ contentPanel.setLayout(new GridBagLayout());
+
+ GridBagConstraints c;
+
+ Font monoSpace = new Font("Monospaced", Font.PLAIN, 12);
+
+ /* std out */
+
+ stdOutText = new JTextArea();
+ JScrollPane stdOutScrollPane = new JScrollPane(stdOutText);
+ stdOutScrollPane.setBorder(new TitledBorder(
+ new EmptyBorder(5, 5, 5, 5), "System.out"));
+ stdOutText.setEditable(false);
+ stdOutText.setFont(monoSpace);
+
+ TextAreaUpdater stdOutUpdater = new TextAreaUpdater(new File(
+ PluginMain.PLUGIN_STDOUT_FILE), stdOutText);
+ stdOutUpdater.setName("IcedteaPlugin Console Thread(System.out)");
+
+ /* std err */
+
+ stdErrText = new JTextArea();
+ JScrollPane stdErrScrollPane = new JScrollPane(stdErrText);
+ stdErrScrollPane.setBorder(new TitledBorder(
+ new EmptyBorder(5, 5, 5, 5), "System.err"));
+ stdErrText.setEditable(false);
+ stdErrText.setFont(monoSpace);
+
+ TextAreaUpdater stdErrUpdater = new TextAreaUpdater(new File(
+ PluginMain.PLUGIN_STDERR_FILE), stdErrText);
+ stdErrUpdater.setName("IcedteaPlugin Console Thread(System.err)");
+
+ JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
+ stdOutScrollPane, stdErrScrollPane);
+
+ c = new GridBagConstraints();
+ c.fill = GridBagConstraints.BOTH;
+ c.gridheight = 10;
+ c.weighty = 1;
+
+ contentPanel.add(splitPane, c);
+
+ /* buttons */
+
+ c = new GridBagConstraints();
+ c.gridy = 10;
+ c.gridheight = 1;
+ c.weightx = 0.5;
+ c.weighty = 0;
+
+ JPanel buttonPanel = new JPanel();
+ contentPanel.add(buttonPanel, c);
+
+ JButton gcButton = new JButton("Run GC");
+ buttonPanel.add(gcButton);
+ gcButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ printMemoryInfo();
+ System.out.print("Performing Garbage Collection....");
+ System.gc();
+ System.out.println("Done");
+ printMemoryInfo();
+ }
+
+ });
+
+ JButton finalizersButton = new JButton("Run Finalizers");
+ buttonPanel.add(finalizersButton);
+ finalizersButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ printMemoryInfo();
+ System.out.print("Running finalization....");
+ Runtime.getRuntime().runFinalization();
+ System.out.println("Done");
+ printMemoryInfo();
+ }
+ });
+
+ JButton memoryButton = new JButton("Memory Info");
+ buttonPanel.add(memoryButton);
+ memoryButton.addActionListener(new ActionListener() {
+
+ public void actionPerformed(ActionEvent e) {
+ printMemoryInfo();
+ }
+
+ });
+
+ JButton systemPropertiesButton = new JButton("System Properties");
+ buttonPanel.add(systemPropertiesButton);
+ systemPropertiesButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ printSystemProperties();
+ }
+
+ });
+
+ JButton classloadersButton = new JButton("Classloaders");
+ buttonPanel.add(classloadersButton);
+ classloadersButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ printClassLoaders();
+ }
+
+ });
+
+ JButton threadListButton = new JButton("Thread List");
+ buttonPanel.add(threadListButton);
+ threadListButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ printThreadInfo();
+ }
+
+ });
+
+ JButton closeButton = new JButton("Close");
+ buttonPanel.add(closeButton);
+ closeButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ SwingUtilities.invokeLater(new Runnable() {
+ public void run() {
+ hideConsole();
+ }
+ });
+ }
+ });
+
+ stdOutUpdater.start();
+ stdErrUpdater.start();
+
+ consoleWindow.add(contentPanel);
+ consoleWindow.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
+ consoleWindow.pack();
+ consoleWindow.setSize(new Dimension(900, 600));
+ consoleWindow.setMinimumSize(new Dimension(900, 300));
+
+ initialized = true;
+
+ splitPane.setDividerLocation(0.5);
+ splitPane.setResizeWeight(0.5);
+ }
+
+ public void showConsole() {
+
+ if (!initialized) {
+ initialize();
+ }
+
+ consoleWindow.setVisible(true);
+ }
+
+ public void hideConsole() {
+ consoleWindow.setVisible(false);
+ }
+
+ protected void printSystemProperties() {
+
+ System.out.println(" ----");
+ System.out.println("System Properties:");
+ System.out.println();
+ Properties p = System.getProperties();
+ Set<Object> keys = p.keySet();
+ for (Object key : keys) {
+ System.out.println(key.toString() + ": " + p.get(key));
+ }
+
+ System.out.println(" ----");
+ }
+
+ private void printClassLoaders() {
+ System.out.println(" ----");
+ System.out.println("Available Classloaders: ");
+ Set<String> loaders = PluginAppletSecurityContext.getLoaderInfo().keySet();
+ for (String loader: loaders) {
+ System.out.println(loader + "\n"
+ + " codebase = "
+ + PluginAppletSecurityContext.getLoaderInfo().get(loader));
+ }
+ System.out.println(" ----");
+ }
+
+ private void printMemoryInfo() {
+ System.out.println(" ----- ");
+ System.out.println(" Memory Info:");
+ System.out.println(" Max Memory: "
+ + String.format("%1$10d", Runtime.getRuntime().maxMemory()));
+ System.out.println(" Total Memory: "
+ + String.format("%1$10d", Runtime.getRuntime().totalMemory()));
+ System.out.println(" Free Memory: "
+ + String.format("%1$10d", Runtime.getRuntime().freeMemory()));
+ System.out.println(" ----");
+
+ }
+
+ private void printThreadInfo() {
+ Map<Thread, StackTraceElement[]> map = Thread.getAllStackTraces();
+ Set<Thread> keys = map.keySet();
+ for (Thread key : keys) {
+ System.out.println("Thread " + key.getId() + ": " + key.getName());
+ for (StackTraceElement element : map.get(key)) {
+ System.out.println(" " + element);
+ }
+
+ }
+ }
+
+ public static void main(String[] args) {
+
+ final JavaConsole console = new JavaConsole();
+
+ boolean toShowConsole = false;
+
+ for (int i = 0; i < args.length; i++) {
+ if (args[i] == "--show-console") {
+ toShowConsole = true;
+ }
+ }
+
+ if (toShowConsole) {
+ SwingUtilities.invokeLater(new Runnable() {
+ public void run() {
+ console.showConsole();
+ }
+ });
+ }
+
+ }
+
+ /**
+ * This thread updates the text on a JTextArea based on the text in a file
+ */
+ class TextAreaUpdater extends Thread {
+
+ File fileToRead;
+ JTextArea outputTextArea;
+
+ public TextAreaUpdater(File file, JTextArea textArea) {
+ fileToRead = file;
+ outputTextArea = textArea;
+ setDaemon(true);
+ }
+
+ public void run() {
+
+ try {
+ BufferedReader reader = new BufferedReader(new FileReader(
+ fileToRead));
+ String line;
+ while (true) {
+ while ((line = reader.readLine()) != null) {
+ outputTextArea.insert(line + "\n", outputTextArea
+ .getDocument().getLength());
+ outputTextArea.setCaretPosition(outputTextArea
+ .getText().length());
+ }
+ Thread.sleep(1000);
+ }
+
+ } catch (FileNotFoundException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ Thread.currentThread().interrupt();
+ }
+
+ }
+
+ }
+
+}
diff --git a/plugin/icedteanp/java/sun/applet/MethodOverloadResolver.java b/plugin/icedteanp/java/sun/applet/MethodOverloadResolver.java
new file mode 100644
index 0000000..bb41e27
--- /dev/null
+++ b/plugin/icedteanp/java/sun/applet/MethodOverloadResolver.java
@@ -0,0 +1,696 @@
+/* MethodOverloadResolver -- Resolves overloaded methods
+ Copyright (C) 2009 Red Hat
+
+This file is part of IcedTea.
+
+IcedTea is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+IcedTea is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with IcedTea; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package sun.applet;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+
+/*
+ * This class resolved overloaded methods in Java objects using a cost
+ * based-approach as described here:
+ *
+ * http://java.sun.com/javase/6/webnotes/6u10/plugin2/liveconnect/#OVERLOADED_METHODS
+ */
+
+public class MethodOverloadResolver {
+
+ private static boolean debugging = false;
+
+ public static void main(String[] args) {
+ testMethodResolver();
+ }
+
+ public static void testMethodResolver() {
+ debugging = true;
+
+ ArrayList<Object[]> list = new ArrayList<Object[]>(20);
+ FooClass fc = new FooClass();
+
+ // Numeric to java primitive
+ // foo_i has Integer and int params
+ String s1 = "foo_string_int(S,I)";
+ String s1a = "foo_string_int(S,S)";
+ Object[] o1 = { fc.getClass(), "foo_string_int", "blah", 42 };
+ list.add(o1);
+ Object[] o1a = { fc.getClass(), "foo_string_int", "blah", "42.42" };
+ list.add(o1a);
+
+ // Null to non-primitive type
+ // foo_i is overloaded with Integer and int
+ String s2 = "foo_string_int(N)";
+ Object[] o2 = { fc.getClass(), "foo_string_int", "blah", null };
+ list.add(o2);
+
+ // foo_jsobj is overloaded with JSObject and String params
+ String s3 = "foo_jsobj(LLowCostSignatureComputer/JSObject;)";
+ Object[] o3 = { fc.getClass(), "foo_jsobj", new JSObject() };
+ list.add(o3);
+
+ // foo_classtype is overloaded with Number and Integer
+ String s4 = "foo_classtype(Ljava/lang/Integer;)";
+ Object[] o4 = { fc.getClass(), "foo_classtype", 42 };
+ list.add(o4);
+
+ // foo_multiprim is overloaded with int, long and float types
+ String s5 = "foo_multiprim(I)";
+ String s6 = "foo_multiprim(F)";
+ String s6a = "foo_multiprim(D)";
+
+ Object[] o5 = { fc.getClass(), "foo_multiprim", new Integer(42) };
+ Object[] o6 = { fc.getClass(), "foo_multiprim", new Float(42.42) };
+ Object[] o6a = { fc.getClass(), "foo_multiprim", new Double(42.42) };
+ list.add(o5);
+ list.add(o6);
+ list.add(o6a);
+
+ // foo_float has float, String and JSObject type
+ String s7 = "foo_float(I)";
+ Object[] o7 = { fc.getClass(), "foo_float", new Integer(42) };
+ list.add(o7);
+
+ // foo_multiprim(float) is what this should convert
+ String s8 = "foo_float(S)";
+ Object[] o8 = { fc.getClass(), "foo_float", "42" };
+ list.add(o8);
+
+ // foo_class is overloaded with BarClass 2 and 3
+ String s9 = "foo_class(LLowCostSignatureComputer/BarClass3;)";
+ Object[] o9 = { fc.getClass(), "foo_class", new BarClass3() };
+ list.add(o9);
+
+ // foo_strandbyteonly takes string and byte
+ String s10 = "foo_strandbyteonly(I)";
+ Object[] o10 = { fc.getClass(), "foo_strandbyteonly", 42 };
+ list.add(o10);
+
+ // JSOBject to string
+ String s11 = "foo_strandbyteonly(LLowCostSignatureComputer/JSObject;)";
+ Object[] o11 = { fc.getClass(), "foo_strandbyteonly", new JSObject() };
+ list.add(o11);
+
+ // jsobject to string and int to float
+ String s12 = "foo_str_and_float(S,I)";
+ Object[] o12 = { fc.getClass(), "foo_str_and_float", new JSObject(), new Integer(42) };
+ list.add(o12);
+
+ // call for which no match will be found
+ String s13 = "foo_int_only(JSObject)";
+ Object[] o13 = { fc.getClass(), "foo_int_only", new JSObject() };
+ list.add(o13);
+
+ // method with no args
+ String s14 = "foo_noargs()";
+ Object[] o14 = { fc.getClass(), "foo_noargs" };
+ list.add(o14);
+
+ // method which takes a primitive bool, given a Boolean
+ String s15 = "foo_boolonly()";
+ Object[] o15 = { fc.getClass(), "foo_boolonly", new Boolean(true) };
+ list.add(o15);
+
+ for (Object[] o : list) {
+ Object[] methodAndArgs = getMatchingMethod(o);
+ if (debugging)
+ if (methodAndArgs != null)
+ System.out.println("Best match: " + methodAndArgs[0] + "\n");
+ else
+ System.out.println("No match found.\n");
+
+ }
+
+ }
+
+ /*
+ * Cost based overload resolution algorithm based on cost rules specified here:
+ *
+ * http://java.sun.com/javase/6/webnotes/6u10/plugin2/liveconnect/#OVERLOADED_METHODS
+ */
+
+ public static Object[] getMatchingMethod(Object[] callList) {
+ Object[] ret = null;
+ Class c = (Class) callList[0];
+ String methodName = (String) callList[1];
+
+ Method[] matchingMethods = getMatchingMethods(c, methodName, callList.length - 2);
+
+ if (debugging)
+ System.out.println("getMatchingMethod called with: " + printList(callList));
+
+ int lowestCost = Integer.MAX_VALUE;
+
+ ArrayList<Object> paramList = new ArrayList<Object>();
+
+ for (Method matchingMethod : matchingMethods) {
+
+ int methodCost = 0;
+ Class[] paramTypes = matchingMethod.getParameterTypes();
+ Object[] methodAndArgs = new Object[paramTypes.length + 1];
+ methodAndArgs[0] = matchingMethod;
+
+ // Figure out which of the matched methods best represents what we
+ // want
+ for (int i = 0; i < paramTypes.length; i++) {
+ Class paramTypeClass = paramTypes[i];
+ Object suppliedParam = callList[i + 2];
+ Class suppliedParamClass = suppliedParam != null ? suppliedParam
+ .getClass()
+ : null;
+
+ Object[] costAndCastedObj = getCostAndCastedObject(
+ suppliedParam, paramTypeClass);
+ methodCost += (Integer) costAndCastedObj[0];
+
+ if ((Integer) costAndCastedObj[0] < 0) break;
+
+ Object castedObj = paramTypeClass.isPrimitive() ? costAndCastedObj[1]
+ : paramTypeClass.cast(costAndCastedObj[1]);
+ methodAndArgs[i + 1] = castedObj;
+
+ Class castedObjClass = castedObj == null ? null : castedObj
+ .getClass();
+ Boolean castedObjIsPrim = castedObj == null ? null : castedObj
+ .getClass().isPrimitive();
+
+ if (debugging)
+ System.out.println("Param " + i + " of method "
+ + matchingMethod + " has cost "
+ + (Integer) costAndCastedObj[0]
+ + " original param type " + suppliedParamClass
+ + " casted to " + castedObjClass + " isPrimitive="
+ + castedObjIsPrim + " value " + castedObj);
+ }
+
+ if ((methodCost > 0 && methodCost < lowestCost) ||
+ paramTypes.length == 0) {
+ ret = methodAndArgs;
+ lowestCost = methodCost;
+ }
+
+ }
+
+ return ret;
+ }
+
+ public static Object[] getMatchingConstructor(Object[] callList) {
+ Object[] ret = null;
+ Class c = (Class) callList[0];
+
+ Constructor[] matchingConstructors = getMatchingConstructors(c, callList.length - 1);
+
+ if (debugging)
+ System.out.println("getMatchingConstructor called with: " + printList(callList));
+
+ int lowestCost = Integer.MAX_VALUE;
+
+ ArrayList<Object> paramList = new ArrayList<Object>();
+
+ for (Constructor matchingConstructor : matchingConstructors) {
+
+ int constructorCost = 0;
+ Class[] paramTypes = matchingConstructor.getParameterTypes();
+ Object[] constructorAndArgs = new Object[paramTypes.length + 1];
+ constructorAndArgs[0] = matchingConstructor;
+
+ // Figure out which of the matched methods best represents what we
+ // want
+ for (int i = 0; i < paramTypes.length; i++) {
+ Class paramTypeClass = paramTypes[i];
+ Object suppliedParam = callList[i + 1];
+ Class suppliedParamClass = suppliedParam != null ? suppliedParam
+ .getClass()
+ : null;
+
+ Object[] costAndCastedObj = getCostAndCastedObject(
+ suppliedParam, paramTypeClass);
+ constructorCost += (Integer) costAndCastedObj[0];
+
+ if ((Integer) costAndCastedObj[0] < 0) break;
+
+ Object castedObj = paramTypeClass.isPrimitive() ? costAndCastedObj[1]
+ : paramTypeClass.cast(costAndCastedObj[1]);
+ constructorAndArgs[i + 1] = castedObj;
+
+ Class castedObjClass = castedObj == null ? null : castedObj
+ .getClass();
+ Boolean castedObjIsPrim = castedObj == null ? null : castedObj
+ .getClass().isPrimitive();
+
+ if (debugging)
+ System.out.println("Param " + i + " of constructor "
+ + matchingConstructor + " has cost "
+ + (Integer) costAndCastedObj[0]
+ + " original param type " + suppliedParamClass
+ + " casted to " + castedObjClass + " isPrimitive="
+ + castedObjIsPrim + " value " + castedObj);
+ }
+
+ if ((constructorCost > 0 && constructorCost < lowestCost) ||
+ paramTypes.length == 0) {
+ ret = constructorAndArgs;
+ lowestCost = constructorCost;
+ }
+ }
+
+ return ret;
+ }
+
+ public static Object[] getCostAndCastedObject(Object suppliedParam, Class paramTypeClass) {
+
+ Object[] ret = new Object[2];
+ Integer cost = new Integer(0);
+ Object castedObj;
+
+ Class suppliedParamClass = suppliedParam != null ? suppliedParam.getClass() : null ;
+
+ // Either both are an array, or neither are
+ boolean suppliedParamIsArray = suppliedParamClass != null && suppliedParamClass.isArray();
+ if (paramTypeClass.isArray() != suppliedParamIsArray &&
+ !paramTypeClass.equals(Object.class) &&
+ !paramTypeClass.equals(String.class)) {
+ ret[0] = Integer.MIN_VALUE; // Not allowed
+ ret[1] = suppliedParam;
+ return ret;
+ }
+
+ // If param type is an array, supplied obj must be an array, Object or String (guaranteed by checks above)
+ // If it is an array, we need to copy/cast as we scan the array
+ // If it an object, we return "as is" [Everything can be narrowed to an object, cost=6]
+ // If it is a string, we need to convert according to the JS engine rules
+
+ if (paramTypeClass.isArray()) {
+
+ Object newArray = Array.newInstance(paramTypeClass.getComponentType(), Array.getLength(suppliedParam));
+ for (int i=0; i < Array.getLength(suppliedParam); i++) {
+ Object original = Array.get(suppliedParam, i);
+
+ // When dealing with arrays, we represent empty slots with
+ // null. We need to convert this to 0 before recursive
+ // calling, since normal transformation does not allow
+ // null -> primitive
+
+ if (original == null && paramTypeClass.getComponentType().isPrimitive())
+ original = 0;
+
+ Object[] costAndCastedObject = getCostAndCastedObject(original, paramTypeClass.getComponentType());
+
+ if ((Integer) costAndCastedObject[0] < 0) {
+ ret[0] = Integer.MIN_VALUE; // Not allowed
+ ret[1] = suppliedParam;
+ return ret;
+ }
+
+ Array.set(newArray, i, costAndCastedObject[1]);
+ }
+
+ ret[0] = 9;
+ ret[1] = newArray;
+ return ret;
+ }
+
+ if (suppliedParamIsArray && paramTypeClass.equals(String.class)) {
+
+ ret[0] = 9;
+ ret[1] = getArrayAsString(suppliedParam);
+ return ret;
+ }
+
+ // If this is null, there are only 2 possible cases
+ if (suppliedParamClass == null) {
+ castedObj = null; // if value is null.. well, it is null
+
+ if (!paramTypeClass.isPrimitive()) {
+ cost += 2; // Null to any non-primitive type
+ } else {
+ cost = Integer.MIN_VALUE; // Null to primitive not allowed
+ }
+ } else if (paramTypeClass.isPrimitive() && paramTypeClass.equals(getPrimitive(suppliedParam))) {
+ cost += 1; // Numeric type to the analogous Java primitive type
+ castedObj = suppliedParam; // Let auto-boxing handle it
+ } else if (suppliedParamClass.equals(paramTypeClass)) {
+ cost += 3; // Class type to Class type where the types are equal
+ castedObj = suppliedParam;
+ } else if (isNum(suppliedParam) &&
+ (paramTypeClass.isPrimitive() ||
+ java.lang.Number.class.isAssignableFrom(paramTypeClass) ||
+ java.lang.Character.class.isAssignableFrom(paramTypeClass) ||
+ java.lang.Byte.class.isAssignableFrom(paramTypeClass)
+ )
+ ) {
+ cost += 4; // Numeric type to a different primitive type
+
+ if (suppliedParam.toString().equals("true"))
+ suppliedParam = "1";
+ else if (suppliedParam.toString().equals("false"))
+ suppliedParam = "0";
+
+ if (paramTypeClass.equals(Boolean.TYPE))
+ castedObj = getNum(suppliedParam.toString(), paramTypeClass).doubleValue() != 0D;
+ else if (paramTypeClass.equals(Character.TYPE))
+ castedObj = (char) Short.decode(suppliedParam.toString()).shortValue();
+ else
+ castedObj = getNum(suppliedParam.toString(), paramTypeClass);
+ } else if (suppliedParam instanceof java.lang.String &&
+ isNum(suppliedParam) &&
+ (paramTypeClass.isInstance(java.lang.Number.class) ||
+ paramTypeClass.isInstance(java.lang.Character.class) ||
+ paramTypeClass.isInstance(java.lang.Byte.class) ||
+ paramTypeClass.isPrimitive())
+ ) {
+ cost += 5; // String to numeric type
+
+ if (suppliedParam.toString().equals("true"))
+ suppliedParam = "1";
+ else if (suppliedParam.toString().equals("false"))
+ suppliedParam = "0";
+
+ if (paramTypeClass.equals(Character.TYPE))
+ castedObj = (char) Short.decode(suppliedParam.toString()).shortValue();
+ else
+ castedObj = getNum(suppliedParam.toString(), paramTypeClass);
+ } else if (suppliedParam instanceof java.lang.String &&
+ (paramTypeClass.equals(java.lang.Boolean.class) ||
+ paramTypeClass.equals(java.lang.Boolean.TYPE))
+ ){
+
+ cost += 5; // Same cost as above
+ castedObj = new Boolean(suppliedParam.toString().length() > 0);
+ } else if (paramTypeClass.isAssignableFrom(suppliedParamClass)) {
+ cost += 6; // Class type to superclass type;
+ castedObj = paramTypeClass.cast(suppliedParam);
+ } else if (paramTypeClass.equals(String.class)) {
+ cost += 7; // Any Java value to String
+ castedObj = suppliedParam.toString();
+ } else if (suppliedParam instanceof JSObject &&
+ paramTypeClass.isArray()) {
+ cost += 8; // JSObject to Java array
+ castedObj = (JSObject) suppliedParam;
+ } else {
+ cost = Integer.MIN_VALUE; // Not allowed
+ castedObj = suppliedParam;
+ }
+
+ ret[0] = cost;
+ ret[1] = castedObj;
+
+ return ret;
+
+ }
+
+ private static Method[] getMatchingMethods(Class c, String name, int paramCount) {
+ Method[] allMethods = c.getMethods();
+ ArrayList<Method> matchingMethods = new ArrayList(5);
+
+ for (Method m: allMethods) {
+ if (m.getName().equals(name) && m.getParameterTypes().length == paramCount)
+ matchingMethods.add(m);
+ }
+
+ return matchingMethods.toArray(new Method[0]);
+ }
+
+ private static Constructor[] getMatchingConstructors(Class c, int paramCount) {
+ Constructor[] allConstructors = c.getConstructors();
+ ArrayList<Constructor> matchingConstructors = new ArrayList<Constructor>(5);
+
+ for (Constructor cs: allConstructors) {
+ if (cs.getParameterTypes().length == paramCount)
+ matchingConstructors.add(cs);
+ }
+
+ return matchingConstructors.toArray(new Constructor[0]);
+ }
+
+ private static Class getPrimitive(Object o) {
+
+ if (o instanceof java.lang.Byte) {
+ return java.lang.Byte.TYPE;
+ } else if (o instanceof java.lang.Character) {
+ return java.lang.Character.TYPE;
+ } else if (o instanceof java.lang.Short) {
+ return java.lang.Short.TYPE;
+ } else if (o instanceof java.lang.Integer) {
+ return java.lang.Integer.TYPE;
+ } else if (o instanceof java.lang.Long) {
+ return java.lang.Long.TYPE;
+ } else if (o instanceof java.lang.Float) {
+ return java.lang.Float.TYPE;
+ } else if (o instanceof java.lang.Double) {
+ return java.lang.Double.TYPE;
+ } else if (o instanceof java.lang.Boolean) {
+ return java.lang.Boolean.TYPE;
+ }
+
+ return o.getClass();
+ }
+
+ private static boolean isNum (Object o) {
+
+ if (o instanceof java.lang.Number)
+ return true;
+
+ // Boolean is changeable to number as well
+ if (o instanceof java.lang.Boolean)
+ return true;
+
+ // At this point, it _has_ to be a string else automatically
+ // return false
+ if (!(o instanceof java.lang.String))
+ return false;
+
+ try {
+ Long.parseLong((String) o); // whole number test
+ return true;
+ } catch (NumberFormatException nfe) {}
+
+ try {
+ Float.parseFloat((String) o); // decimal
+ return true;
+ } catch (NumberFormatException nfe) {}
+
+
+ return false;
+ }
+
+ private static Number getNum (String s, Class c) throws NumberFormatException {
+
+ Number n;
+ if (s.contains("."))
+ n = new Double(s);
+ else
+ n = new Long(s);
+
+ // See if we need to collapse first
+ if (c.equals(java.lang.Integer.class) ||
+ c.equals(java.lang.Integer.TYPE)) {
+ return n.intValue();
+ }
+
+ if (c.equals(java.lang.Long.class) ||
+ c.equals(java.lang.Long.TYPE)) {
+ return n.longValue();
+ }
+
+ if (c.equals(java.lang.Short.class) ||
+ c.equals(java.lang.Short.TYPE)) {
+ return n.shortValue();
+ }
+
+ if (c.equals(java.lang.Float.class) ||
+ c.equals(java.lang.Float.TYPE)) {
+ return n.floatValue();
+ }
+
+ if (c.equals(java.lang.Double.class) ||
+ c.equals(java.lang.Double.TYPE)) {
+ return n.doubleValue();
+ }
+
+ if (c.equals(java.lang.Byte.class) ||
+ c.equals(java.lang.Byte.TYPE)) {
+ return n.byteValue();
+ }
+
+ return n;
+ }
+
+ private static String printList (Object[] oList) {
+
+ String ret = "";
+
+ ret += "{ ";
+ for (Object o : oList) {
+
+ String oStr = o != null ? o.toString() + " [" + o.getClass() + "]" : "null";
+
+ ret += oStr;
+ ret += ", ";
+ }
+ ret = ret.substring(0, ret.length()-2); // remove last ", "
+ ret += " }";
+
+ return ret;
+ }
+
+ private static String getArrayAsString(Object array) {
+ // We are guaranteed that supplied object is a String
+
+ String ret = new String();
+
+ for (int i=0; i < Array.getLength(array); i++) {
+ Object element = Array.get(array, i);
+
+ if (element != null) {
+ if (element.getClass().isArray()) {
+ ret += getArrayAsString(element);
+ } else {
+ ret += element;
+ }
+ }
+
+ ret += ",";
+ }
+
+ // Trim the final ","
+ if (ret.length() > 0) {
+ ret = ret.substring(0, ret.length() - 1);
+ }
+
+ return ret;
+ }
+}
+
+/** Begin test classes **/
+
+class FooClass {
+
+ public FooClass() {}
+
+ public FooClass(Boolean b, int i) {}
+
+ public FooClass(Boolean b, Integer i) {}
+
+ public FooClass(Boolean b, short s) {}
+
+ public FooClass(String s, int i) {}
+
+ public FooClass(String s, Integer i) {}
+
+ public FooClass(java.lang.Number num) {}
+
+ public FooClass(java.lang.Integer integer) {}
+
+ public FooClass(long l) {}
+
+ public FooClass(double d) {}
+
+ public FooClass(float f) {}
+
+ public FooClass(JSObject j) {}
+
+ public FooClass(BarClass1 b) {}
+
+ public FooClass(BarClass2 b) {}
+
+ public FooClass(String s) {}
+
+ public FooClass(byte b) {}
+
+ public FooClass(String s, Float f) {}
+
+ public FooClass (int i) {}
+
+ public void FooClass() {}
+
+ public void FooClass(boolean b) {}
+
+
+ public void foo(Boolean b, int i) {}
+
+ public void foo(Boolean b, Integer i) {}
+
+ public void foo(Boolean b, short s) {}
+
+ public void foo_string_int(String s, int i) {}
+
+ public void foo_string_int(String s, Integer i) {}
+
+ public void foo_jsobj(JSObject j) {}
+
+ public void foo_jsobj(String s) {}
+
+ public void foo_classtype(java.lang.Number num) {}
+
+ public void foo_classtype(java.lang.Integer integer) {}
+
+ public void foo_multiprim(int i) {}
+
+ public void foo_multiprim(long l) {}
+
+ public void foo_multiprim(float f) {}
+
+ public void foo_multiprim(double d) {}
+
+ public void foo_float(float f) {}
+
+ public void foo_float(String s) {}
+
+ public void foo_float(JSObject j) {}
+
+ public void foo_class(BarClass1 b) {}
+
+ public void foo_class(BarClass2 b) {}
+
+ public void foo_strandbyteonly(String s) {}
+
+ public void foo_strandbyteonly(byte b) {}
+
+ public void foo_str_and_float(String s, Float f) {}
+
+ public void foo_int_only (int i) {}
+
+ public void foo_noargs() {}
+
+ public void foo_boolonly(boolean b) {}
+}
+
+class BarClass1 {}
+class BarClass2 extends BarClass1 {}
+class BarClass3 extends BarClass2 {}
+class JSObject {}
diff --git a/plugin/icedteanp/java/sun/applet/PasswordAuthenticationDialog.java b/plugin/icedteanp/java/sun/applet/PasswordAuthenticationDialog.java
new file mode 100644
index 0000000..843603e
--- /dev/null
+++ b/plugin/icedteanp/java/sun/applet/PasswordAuthenticationDialog.java
@@ -0,0 +1,241 @@
+/* PasswordAuthenticationDialog -- requests authentication information from users
+ Copyright (C) 2009 Red Hat
+
+This file is part of IcedTea.
+
+IcedTea is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+IcedTea is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with IcedTea; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package sun.applet;
+
+import java.awt.Dimension;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.net.PasswordAuthentication;
+
+import javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JLabel;
+import javax.swing.JPasswordField;
+import javax.swing.JTextField;
+import javax.swing.SwingUtilities;
+
+/**
+ * Modal non-minimizable dialog to request http authentication credentials
+ */
+
+public class PasswordAuthenticationDialog extends JDialog {
+
+ private JLabel jlInfo = new JLabel("");
+ private JTextField jtfUserName = new JTextField();
+ private JPasswordField jpfPassword = new JPasswordField();
+ private boolean userCancelled;
+
+ public PasswordAuthenticationDialog() {
+ initialize();
+ }
+
+ /**
+ * Initialized the dialog components
+ */
+
+ public void initialize() {
+
+ setTitle("IcedTea Java Plugin - Authorization needed to proceed");
+
+ setLayout(new GridBagLayout());
+
+ JLabel jlUserName = new JLabel("Username: ");
+ JLabel jlPassword = new JLabel("Password: ");
+ JButton jbOK = new JButton("OK");
+ JButton jbCancel = new JButton("Cancel");
+
+ jtfUserName.setSize(20, 10);
+ jpfPassword.setSize(20, 10);
+
+ GridBagConstraints c;
+
+ c = new GridBagConstraints();
+ c.fill = c.HORIZONTAL;
+ c.gridx = 0;
+ c.gridy = 0;
+ c.gridwidth = 2;
+ c.insets = new Insets(10, 5, 3, 3);
+ add(jlInfo, c);
+
+ c = new GridBagConstraints();
+ c.gridx = 0;
+ c.gridy = 1;
+ c.insets = new Insets(10, 5, 3, 3);
+ add(jlUserName, c);
+
+ c = new GridBagConstraints();
+ c.fill = c.HORIZONTAL;
+ c.gridx = 1;
+ c.gridy = 1;
+ c.insets = new Insets(10, 5, 3, 3);
+ c.weightx = 1.0;
+ add(jtfUserName, c);
+
+
+ c = new GridBagConstraints();
+ c.gridx = 0;
+ c.gridy = 2;
+ c.insets = new Insets(5, 5, 3, 3);
+ add(jlPassword, c);
+
+ c = new GridBagConstraints();
+ c.fill = c.HORIZONTAL;
+ c.gridx = 1;
+ c.gridy = 2;
+ c.insets = new Insets(5, 5, 3, 3);
+ c.weightx = 1.0;
+ add(jpfPassword, c);
+
+ c = new GridBagConstraints();
+ c.anchor = c.SOUTHEAST;
+ c.gridx = 1;
+ c.gridy = 3;
+ c.insets = new Insets(5, 5, 3, 70);
+ c.weightx = 0.0;
+ add(jbCancel, c);
+
+ c = new GridBagConstraints();
+ c.anchor = c.SOUTHEAST;
+ c.gridx = 1;
+ c.gridy = 3;
+ c.insets = new Insets(5, 5, 3, 3);
+ c.weightx = 0.0;
+ add(jbOK, c);
+
+ setMinimumSize(new Dimension(400,150));
+ setMaximumSize(new Dimension(1024,150));
+ setAlwaysOnTop(true);
+
+ setSize(400,150);
+ setLocationRelativeTo(null);
+
+ // OK => read supplied info and pass it on
+ jbOK.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ userCancelled = false;
+ dispose();
+ }
+ });
+
+ // Cancel => discard supplied info and pass on an empty auth
+ jbCancel.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ userCancelled = true;
+ dispose();
+ }
+ });
+
+ // "return" key in either user or password field => OK
+
+ jtfUserName.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ userCancelled = false;
+ dispose();
+ }
+ });
+
+ jpfPassword.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ userCancelled = false;
+ dispose();
+ }
+ });
+ }
+
+ /**
+ * Present a dialog to the user asking them for authentication information
+ *
+ * @param hostThe host for with authentication is needed
+ * @param port The port being accessed
+ * @param prompt The prompt (realm) as presented by the server
+ * @param type The type of server (proxy/web)
+ * @return PasswordAuthentication containing the credentials (empty credentials if user cancelled)
+ */
+ protected PasswordAuthentication askUser(String host, int port, String prompt, String type) {
+ PasswordAuthentication auth = null;
+
+ host += port != -1 ? ":" + port : "";
+
+ // This frame is reusable. So reset everything first.
+ userCancelled = true;
+ jlInfo.setText("<html>The " + type + " server at " + host + " is requesting authentication. It says \"" + prompt + "\"</html>");
+
+ try {
+ SwingUtilities.invokeAndWait( new Runnable() {
+ public void run() {
+ // show dialog to user
+ setVisible(true);
+ }
+ });
+
+ PluginDebug.debug("password dialog shown");
+
+ // wait until dialog is gone
+ while (this.isShowing()) {
+ try {
+ Thread.sleep(200);
+ } catch (InterruptedException ie) {
+ }
+ }
+
+ PluginDebug.debug("password dialog closed");
+
+ if (!userCancelled) {
+ auth = new PasswordAuthentication(jtfUserName.getText(), jpfPassword.getText().toCharArray());
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+
+ // Nothing else we can do. Empty auth will be returned
+ }
+
+ return auth;
+ }
+
+ public static void main(String[] args) {
+ PasswordAuthenticationDialog frame = new PasswordAuthenticationDialog();
+
+ PasswordAuthentication auth = frame.askUser("127.0.0.1", 3128, "Password for local proxy", "proxy");
+
+ System.err.println("Auth info: " + auth.getUserName() + ":" + new String(auth.getPassword()));
+ System.exit(0);
+ }
+}
diff --git a/plugin/icedteanp/java/sun/applet/PluginAppletSecurityContext.java b/plugin/icedteanp/java/sun/applet/PluginAppletSecurityContext.java
new file mode 100644
index 0000000..bef2bd8
--- /dev/null
+++ b/plugin/icedteanp/java/sun/applet/PluginAppletSecurityContext.java
@@ -0,0 +1,1505 @@
+/* PluginAppletSecurityContext -- execute plugin JNI messages
+ Copyright (C) 2008 Red Hat
+
+This file is part of IcedTea.
+
+IcedTea is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+IcedTea is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with IcedTea; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package sun.applet;
+
+import java.io.File;
+import java.lang.reflect.Array;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.security.AccessControlContext;
+import java.security.AccessControlException;
+import java.security.AccessController;
+import java.security.AllPermission;
+import java.security.BasicPermission;
+import java.security.CodeSource;
+import java.security.Permissions;
+import java.security.PrivilegedAction;
+import java.security.ProtectionDomain;
+import java.text.DecimalFormat;
+import java.util.ArrayList;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Map;
+
+import javax.swing.text.html.HTMLDocument.HTMLReader.IsindexAction;
+
+import net.sourceforge.jnlp.runtime.JNLPRuntime;
+import netscape.javascript.JSObjectCreatePermission;
+
+
+
+class Signature {
+ private String signature;
+ private int currentIndex;
+ private List<Class> typeList;
+ private static final char ARRAY = '[';
+ private static final char OBJECT = 'L';
+ private static final char SIGNATURE_ENDCLASS = ';';
+ private static final char SIGNATURE_FUNC = '(';
+ private static final char SIGNATURE_ENDFUNC = ')';
+ private static final char VOID = 'V';
+ private static final char BOOLEAN = 'Z';
+ private static final char BYTE = 'B';
+ private static final char CHARACTER = 'C';
+ private static final char SHORT = 'S';
+ private static final char INTEGER = 'I';
+ private static final char LONG = 'J';
+ private static final char FLOAT = 'F';
+ private static final char DOUBLE = 'D';
+
+ private String nextTypeName() {
+ char key = signature.charAt(currentIndex++);
+
+ switch (key) {
+ case ARRAY:
+ return nextTypeName() + "[]";
+
+ case OBJECT:
+ int endClass = signature.indexOf(SIGNATURE_ENDCLASS, currentIndex);
+ String retVal = signature.substring(currentIndex, endClass);
+ retVal = retVal.replace('/', '.');
+ currentIndex = endClass + 1;
+ return retVal;
+
+ // FIXME: generated bytecode with classes named after
+ // primitives will not work in this scheme -- those
+ // classes will be incorrectly treated as primitive
+ // types.
+ case VOID:
+ return "void";
+ case BOOLEAN:
+ return "boolean";
+ case BYTE:
+ return "byte";
+ case CHARACTER:
+ return "char";
+ case SHORT:
+ return "short";
+ case INTEGER:
+ return "int";
+ case LONG:
+ return "long";
+ case FLOAT:
+ return "float";
+ case DOUBLE:
+ return "double";
+
+ case SIGNATURE_ENDFUNC:
+ return null;
+
+ case SIGNATURE_FUNC:
+ return nextTypeName();
+
+ default:
+ throw new IllegalArgumentException(
+ "Invalid JNI signature character '" + key + "'");
+ }
+ }
+
+ public Signature(String signature, ClassLoader cl) {
+ this.signature = signature;
+ currentIndex = 0;
+ typeList = new ArrayList<Class>(10);
+
+ String elem;
+ while (currentIndex < signature.length()) {
+ elem = nextTypeName();
+
+ if (elem == null) // end of signature
+ continue;
+
+ // System.out.println ("NEXT TYPE: " + elem);
+ Class primitive = primitiveNameToType(elem);
+ if (primitive != null)
+ typeList.add(primitive);
+ else {
+ // System.out.println ("HERE1");
+ int dimsize = 0;
+ int n = elem.indexOf('[');
+ if (n != -1) {
+ // System.out.println ("HERE2");
+ String arrayType = elem.substring(0, n);
+ dimsize++;
+ n = elem.indexOf('[', n + 1);
+ // System.out.println ("HERE2.5");
+ while (n != -1) {
+ dimsize++;
+ n = elem.indexOf('[', n + 1);
+ // System.out.println ("HERE2.8");
+ }
+ int[] dims = new int[dimsize];
+ primitive = primitiveNameToType(arrayType);
+ // System.out.println ("HERE3");
+ if (primitive != null) {
+ typeList.add(Array.newInstance(primitive, dims)
+ .getClass());
+ // System.out.println ("HERE4");
+ } else
+ typeList.add(Array.newInstance(
+ getClass(arrayType, cl), dims).getClass());
+ } else {
+ typeList.add(getClass(elem, cl));
+ }
+ }
+ }
+ if (signature.length() < 2) {
+ throw new IllegalArgumentException("Invalid JNI signature '"
+ + signature + "'");
+ }
+ }
+
+ public static Class getClass(String name, ClassLoader cl) {
+
+ Class c = null;
+
+ try {
+ c = Class.forName(name);
+ } catch (ClassNotFoundException cnfe) {
+
+ PluginDebug.debug("Class " + name + " not found in primordial loader. Looking in " + cl);
+ try {
+ c = cl.loadClass(name);
+ } catch (ClassNotFoundException e) {
+ throw (new RuntimeException(new ClassNotFoundException("Unable to find class " + name)));
+ }
+ }
+
+ return c;
+ }
+
+ public static Class primitiveNameToType(String name) {
+ if (name.equals("void"))
+ return Void.TYPE;
+ else if (name.equals("boolean"))
+ return Boolean.TYPE;
+ else if (name.equals("byte"))
+ return Byte.TYPE;
+ else if (name.equals("char"))
+ return Character.TYPE;
+ else if (name.equals("short"))
+ return Short.TYPE;
+ else if (name.equals("int"))
+ return Integer.TYPE;
+ else if (name.equals("long"))
+ return Long.TYPE;
+ else if (name.equals("float"))
+ return Float.TYPE;
+ else if (name.equals("double"))
+ return Double.TYPE;
+ else
+ return null;
+ }
+
+ public Class[] getClassArray() {
+ return typeList.subList(0, typeList.size()).toArray(new Class[] {});
+ }
+}
+
+public class PluginAppletSecurityContext {
+
+ private static Hashtable<ClassLoader, URL> classLoaders = new Hashtable<ClassLoader, URL>();
+ private static Hashtable<Integer, ClassLoader> instanceClassLoaders = new Hashtable<Integer, ClassLoader>();
+
+ // FIXME: make private
+ public PluginObjectStore store = new PluginObjectStore();
+ private Throwable throwable = null;
+ private ClassLoader liveconnectLoader = ClassLoader.getSystemClassLoader();
+ int identifier = 0;
+
+ public static PluginStreamHandler streamhandler;
+
+ long startTime = 0;
+
+ public PluginAppletSecurityContext(int identifier) {
+ this.identifier = identifier;
+
+ // also, override the basedir, use a different one for the plugin
+ File f = new File(System.getProperty("user.home") + "/.icedteaplugin/");
+ f.mkdir();
+ JNLPRuntime.setBaseDir(f);
+
+ // We need a security manager.. and since there is a good chance that
+ // an applet will be loaded at some point, we should make it the SM
+ // that JNLPRuntime will try to install
+ if (System.getSecurityManager() == null) {
+ JNLPRuntime.initialize(/* isApplication */ false);
+ }
+
+ JNLPRuntime.disableExit();
+
+ URL u = null;
+ try {
+ u = new URL("file://");
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+
+ this.classLoaders.put(liveconnectLoader, u);
+ }
+
+ private static <V> V parseCall(String s, ClassLoader cl, Class<V> c) {
+ if (c == Integer.class)
+ return (V) new Integer(s);
+ else if (c == String.class)
+ return (V) new String(s);
+ else if (c == Signature.class)
+ return (V) new Signature(s, cl);
+ else
+ throw new RuntimeException("Unexpected call value.");
+ }
+
+ private Object parseArgs(String s, Class c) {
+ if (c == Boolean.TYPE || c == Boolean.class)
+ return new Boolean(s);
+ else if (c == Byte.TYPE || c == Byte.class)
+ return new Byte(s);
+ else if (c == Character.TYPE || c == Character.class) {
+ String[] bytes = s.split("_");
+ int low = Integer.parseInt(bytes[0]);
+ int high = Integer.parseInt(bytes[1]);
+ int full = ((high << 8) & 0x0ff00) | (low & 0x0ff);
+ return new Character((char) full);
+ } else if (c == Short.TYPE || c == Short.class)
+ return new Short(s);
+ else if (c == Integer.TYPE || c == Integer.class)
+ return new Integer(s);
+ else if (c == Long.TYPE || c == Long.class)
+ return new Long(s);
+ else if (c == Float.TYPE || c == Float.class)
+ return new Float(s);
+ else if (c == Double.TYPE || c == Double.class)
+ return new Double(s);
+ else
+ return store.getObject(new Integer(s));
+ }
+
+ public void associateSrc(ClassLoader cl, URL src) {
+ PluginDebug.debug("Associating " + cl + " with " + src);
+ this.classLoaders.put(cl, src);
+ }
+
+ public void associateInstance(Integer i, ClassLoader cl) {
+ PluginDebug.debug("Associating " + cl + " with instance " + i);
+ this.instanceClassLoaders.put(i, cl);
+ }
+
+ public static void setStreamhandler(PluginStreamHandler sh) {
+ streamhandler = sh;
+ }
+
+ public static Map<String, String> getLoaderInfo() {
+ Hashtable<String, String> map = new Hashtable<String, String>();
+
+ for (ClassLoader loader : PluginAppletSecurityContext.classLoaders.keySet()) {
+ map.put(loader.getClass().getName(), classLoaders.get(loader).toString());
+ }
+
+ return map;
+ }
+
+ public void handleMessage(int reference, String src, AccessControlContext callContext, String message) {
+
+ startTime = new java.util.Date().getTime();
+
+ try {
+ if (message.startsWith("FindClass")) {
+ ClassLoader cl = null;
+ Class c = null;
+ cl = liveconnectLoader;
+ String[] args = message.split(" ");
+ Integer instance = new Integer(args[1]);
+ String className = args[2].replace('/', '.');
+ PluginDebug.debug("Searching for class " + className + " in " + cl);
+
+ try {
+ c = cl.loadClass(className);
+ store.reference(c);
+ write(reference, "FindClass " + store.getIdentifier(c));
+ } catch (ClassNotFoundException cnfe) {
+
+ cl = this.instanceClassLoaders.get(instance);
+ PluginDebug.debug("Not found. Looking in " + cl);
+
+ if (instance != 0 && cl != null) {
+ try {
+ c = cl.loadClass(className);
+ store.reference(c);
+ write(reference, "FindClass " + store.getIdentifier(c));
+ } catch (ClassNotFoundException cnfe2) {
+ write(reference, "FindClass 0");
+ }
+ } else {
+ write(reference, "FindClass 0");
+ }
+ }
+
+ } else if (message.startsWith("GetStaticMethodID")
+ || message.startsWith("GetMethodID")) {
+ String[] args = message.split(" ");
+ Integer classID = parseCall(args[1], null, Integer.class);
+ String methodName = parseCall(args[2], null, String.class);
+ Signature signature = parseCall(args[3], ((Class) store.getObject(classID)).getClassLoader(), Signature.class);
+ Object[] a = signature.getClassArray();
+
+ Class c;
+
+ if (message.startsWith("GetStaticMethodID") ||
+ methodName.equals("<init>") ||
+ methodName.equals("<clinit>"))
+ c = (Class) store.getObject(classID);
+ else
+ c = store.getObject(classID).getClass();
+
+ Method m = null;
+ Constructor cs = null;
+ Object o = null;
+ if (methodName.equals("<init>")
+ || methodName.equals("<clinit>")) {
+ o = cs = c.getConstructor(signature.getClassArray());
+ store.reference(cs);
+ } else {
+ o = m = c.getMethod(methodName, signature.getClassArray());
+ store.reference(m);
+ }
+ PluginDebug.debug(o + " has id " + store.getIdentifier(o));
+ write(reference, args[0] + " " + store.getIdentifier(o));
+ } else if (message.startsWith("GetStaticFieldID")
+ || message.startsWith("GetFieldID")) {
+ String[] args = message.split(" ");
+ Integer classID = parseCall(args[1], null, Integer.class);
+ Integer fieldID = parseCall(args[2], null, Integer.class);
+ String fieldName = (String) store.getObject(fieldID);
+
+ Class c = (Class) store.getObject(classID);
+
+ PluginDebug.debug("GetStaticFieldID/GetFieldID got class=" + c.getName());
+
+ Field f = null;
+ f = c.getField(fieldName);
+
+ store.reference(f);
+
+ write(reference, "GetStaticFieldID " + store.getIdentifier(f));
+ } else if (message.startsWith("GetStaticField")) {
+ String[] args = message.split(" ");
+ String type = parseCall(args[1], null, String.class);
+ Integer classID = parseCall(args[1], null, Integer.class);
+ Integer fieldID = parseCall(args[2], null, Integer.class);
+
+ final Class c = (Class) store.getObject(classID);
+ final Field f = (Field) store.getObject(fieldID);
+
+ AccessControlContext acc = callContext != null ? callContext : getClosedAccessControlContext();
+ checkPermission(src, c, acc);
+
+ Object ret = AccessController.doPrivileged(new PrivilegedAction<Object> () {
+ public Object run() {
+ try {
+ return f.get(c);
+ } catch (Throwable t) {
+ return t;
+ }
+ }
+ }, acc);
+
+ if (ret instanceof Throwable)
+ throw (Throwable) ret;
+
+ if (ret == null) {
+ write(reference, "GetStaticField literalreturn null");
+ } else if (f.getType() == Boolean.TYPE
+ || f.getType() == Byte.TYPE
+ || f.getType() == Short.TYPE
+ || f.getType() == Integer.TYPE
+ || f.getType() == Long.TYPE) {
+ write(reference, "GetStaticField literalreturn " + ret);
+ } else if (f.getType() == Float.TYPE
+ || f.getType() == Double.TYPE) {
+ write(reference, "GetStaticField literalreturn " + String.format("%308.308e", ret));
+ } else if (f.getType() == Character.TYPE) {
+ write(reference, "GetStaticField literalreturn " + (int) (Character) ret);
+ } else {
+ // Track returned object.
+ store.reference(ret);
+ write(reference, "GetStaticField " + store.getIdentifier(ret));
+ }
+ } else if (message.startsWith("GetValue")) {
+ String[] args = message.split(" ");
+ Integer index = parseCall(args[1], null, Integer.class);
+
+ Object ret = store.getObject(index);
+
+ if (ret == null) {
+ write(reference, "GetValue literalreturn null");
+ } else if (ret.getClass() == Boolean.TYPE
+ || ret.getClass() == Boolean.class
+ || ret.getClass() == Byte.TYPE
+ || ret.getClass() == Byte.class
+ || ret.getClass() == Short.TYPE
+ || ret.getClass() == Short.class
+ || ret.getClass() == Integer.TYPE
+ || ret.getClass() == Integer.class
+ || ret.getClass() == Long.TYPE
+ || ret.getClass() == Long.class) {
+ write(reference, "GetValue literalreturn " + ret);
+ } else if (ret.getClass() == Float.TYPE
+ || ret.getClass() == Float.class
+ || ret.getClass() == Double.TYPE
+ || ret.getClass() == Double.class) {
+ write(reference, "GetValue literalreturn " + String.format("%308.308e", ret));
+ } else if (ret.getClass() == Character.TYPE
+ || ret.getClass() == Character.class) {
+ write(reference, "GetValue literalreturn " + (int) (Character) ret);
+ } else {
+ // Track returned object.
+ store.reference(ret);
+ write(reference, "GetValue " + store.getIdentifier(ret));
+ }
+ } else if (message.startsWith("SetStaticField") ||
+ message.startsWith("SetField")) {
+ String[] args = message.split(" ");
+ Integer classOrObjectID = parseCall(args[1], null, Integer.class);
+ Integer fieldID = parseCall(args[2], null, Integer.class);
+ Object value = store.getObject(parseCall(args[3], null, Integer.class));
+
+ final Object o = store.getObject(classOrObjectID);
+ final Field f = (Field) store.getObject(fieldID);
+
+ final Object fValue = MethodOverloadResolver.getCostAndCastedObject(value, f.getType())[1];
+
+ AccessControlContext acc = callContext != null ? callContext : getClosedAccessControlContext();
+ checkPermission(src,
+ message.startsWith("SetStaticField") ? (Class) o : o.getClass(),
+ acc);
+
+ Object ret = AccessController.doPrivileged(new PrivilegedAction<Object> () {
+ public Object run() {
+ try {
+ f.set(o, fValue);
+ } catch (Throwable t) {
+ return t;
+ }
+
+ return null;
+ }
+ }, acc);
+
+ if (ret instanceof Throwable)
+ throw (Throwable) ret;
+
+ write(reference, "SetField");
+ } else if (message.startsWith("GetObjectArrayElement")) {
+ String[] args = message.split(" ");
+ Integer arrayID = parseCall(args[1], null, Integer.class);
+ Integer index = parseCall(args[2], null, Integer.class);
+
+ Object ret = Array.get(store.getObject(arrayID), index);
+ Class retClass = store.getObject(arrayID).getClass().getComponentType(); // prevent auto-boxing influence
+
+ if (ret == null) {
+ write(reference, "GetObjectArrayElement literalreturn null");
+ } else if (retClass == Boolean.TYPE
+ || retClass == Byte.TYPE
+ || retClass == Short.TYPE
+ || retClass== Integer.TYPE
+ || retClass== Long.TYPE) {
+ write(reference, "GetObjectArrayElement literalreturn " + ret);
+ } else if (retClass == Float.TYPE
+ || retClass == Double.TYPE) {
+ write(reference, "GetObjectArrayElement literalreturn " + String.format("%308.308e", ret));
+ } else if (retClass == Character.TYPE) {
+ write(reference, "GetObjectArrayElement literalreturn " + (int) (Character) ret);
+ } else {
+ // Track returned object.
+ store.reference(ret);
+ write(reference, "GetObjectArrayElement " + store.getIdentifier(ret));
+ }
+
+ } else if (message.startsWith("SetObjectArrayElement")) {
+ String[] args = message.split(" ");
+ Integer arrayID = parseCall(args[1], null, Integer.class);
+ Integer index = parseCall(args[2], null, Integer.class);
+ Integer objectID = parseCall(args[3], null, Integer.class);
+
+ Object value = store.getObject(objectID);
+
+ // Cast the object to appropriate type before insertion
+ value = MethodOverloadResolver.getCostAndCastedObject(value, store.getObject(arrayID).getClass().getComponentType())[1];
+
+ //if (value == null &&
+ // store.getObject(arrayID).getClass().getComponentType().isPrimitive()) {
+ // value = 0;
+ //}
+
+ Array.set(store.getObject(arrayID), index, value);
+
+ write(reference, "SetObjectArrayElement");
+ } else if (message.startsWith("GetArrayLength")) {
+ String[] args = message.split(" ");
+ Integer arrayID = parseCall(args[1], null, Integer.class);
+
+ //System.out.println("ARRAYID: " + arrayID);
+ Object o = (Object) store.getObject(arrayID);
+ int len = 0;
+ len = Array.getLength(o);
+ // System.out.println ("Returning array length: " + len);
+
+ // System.out.println ("array length: " + o + " " + len);
+ write(reference, "GetArrayLength " + Array.getLength(o));
+ } else if (message.startsWith("GetField")) {
+ String[] args = message.split(" ");
+ String type = parseCall(args[1], null, String.class);
+ Integer objectID = parseCall(args[1], null, Integer.class);
+ Integer fieldID = parseCall(args[2], null, Integer.class);
+
+ final Object o = (Object) store.getObject(objectID);
+ final Field f = (Field) store.getObject(fieldID);
+
+ AccessControlContext acc = callContext != null ? callContext : getClosedAccessControlContext();
+ checkPermission(src, o.getClass(), acc);
+
+ Object ret = AccessController.doPrivileged(new PrivilegedAction<Object> () {
+ public Object run() {
+ try {
+ return f.get(o);
+ } catch (Throwable t) {
+ return t;
+ }
+ }
+ }, acc);
+
+ if (ret instanceof Throwable)
+ throw (Throwable) ret;
+
+ if (ret == null) {
+ write(reference, "GetField literalreturn null");
+ } else if (f.getType() == Boolean.TYPE
+ || f.getType() == Byte.TYPE
+ || f.getType() == Short.TYPE
+ || f.getType() == Integer.TYPE
+ || f.getType() == Long.TYPE) {
+ write(reference, "GetField literalreturn " + ret);
+ } else if (f.getType() == Float.TYPE
+ || f.getType() == Double.TYPE) {
+ write(reference, "GetField literalreturn " + String.format("%308.308e", ret));
+ } else if (f.getType() == Character.TYPE) {
+ write(reference, "GetField literalreturn " + (int) (Character) ret);
+ } else {
+ // Track returned object.
+ store.reference(ret);
+ write(reference, "GetField " + store.getIdentifier(ret));
+ }
+
+ } else if (message.startsWith("GetObjectClass")) {
+ int oid = Integer.parseInt(message.substring("GetObjectClass"
+ .length() + 1));
+ // System.out.println ("GETTING CLASS FOR: " + oid);
+ Class c = store.getObject(oid).getClass();
+ // System.out.println (" OBJ: " + store.getObject(oid));
+ // System.out.println (" CLS: " + c);
+ store.reference(c);
+
+ write(reference, "GetObjectClass " + store.getIdentifier(c));
+ } else if (message.startsWith("CallMethod") ||
+ message.startsWith("CallStaticMethod")) {
+ String[] args = message.split(" ");
+ Integer objectID = parseCall(args[1], null, Integer.class);
+ String methodName = parseCall(args[2], null, String.class);
+ Object o = null;
+ Class c;
+
+ if (message.startsWith("CallMethod")) {
+ o = (Object) store.getObject(objectID);
+ c = o.getClass();
+ } else {
+ c = (Class) store.getObject(objectID);
+ }
+
+ // length -3 to discard first 3, + 2 for holding object
+ // and method name
+ Object[] arguments = new Object[args.length - 1];
+ arguments[0] = c;
+ arguments[1] = methodName;
+ for (int i = 0; i < args.length - 3; i++) {
+ arguments[i+2] = store.getObject(parseCall(args[3 + i], null, Integer.class));
+ PluginDebug.debug("GOT ARG: " + arguments[i+2]);
+ }
+
+ Object[] matchingMethodAndArgs = MethodOverloadResolver.getMatchingMethod(arguments);
+
+ if (matchingMethodAndArgs == null) {
+ write(reference, "Error: No suitable method named " + methodName + " with matching args found");
+ return;
+ }
+
+ final Method m = (Method) matchingMethodAndArgs[0];
+ Object[] castedArgs = new Object[matchingMethodAndArgs.length - 1];
+ for (int i=0; i < castedArgs.length; i++) {
+ castedArgs[i] = matchingMethodAndArgs[i+1];
+ }
+
+ String collapsedArgs = "";
+ for (Object arg : castedArgs) {
+ collapsedArgs += " " + arg;
+ }
+
+ PluginDebug.debug("Calling method " + m + " on object " + o
+ + " (" + c + ") with " + collapsedArgs);
+
+ AccessControlContext acc = callContext != null ? callContext : getClosedAccessControlContext();
+ checkPermission(src, c, acc);
+
+ final Object[] fArguments = castedArgs;
+ final Object callableObject = o;
+ // Set the method accessible prior to calling. See:
+ // http://forums.sun.com/thread.jspa?threadID=332001&start=15&tstart=0
+ m.setAccessible(true);
+ Object ret = AccessController.doPrivileged(new PrivilegedAction<Object> () {
+ public Object run() {
+ try {
+ return m.invoke(callableObject, fArguments);
+ } catch (Throwable t) {
+ return t;
+ }
+ }
+ }, acc);
+
+ if (ret instanceof Throwable)
+ throw (Throwable) ret;
+
+ String retO;
+ if (ret == null) {
+ retO = "null";
+ } else {
+ retO = m.getReturnType().toString();
+ }
+
+ PluginDebug.debug("Calling " + m + " on " + o + " with "
+ + collapsedArgs + " and that returned: " + ret
+ + " of type " + retO);
+
+ if (m.getReturnType().equals(java.lang.Void.class) ||
+ m.getReturnType().equals(java.lang.Void.TYPE)) {
+ write(reference, "CallMethod literalreturn void");
+ } else if (ret == null) {
+ write(reference, "CallMethod literalreturn null");
+ } else if (m.getReturnType() == Boolean.TYPE
+ || m.getReturnType() == Byte.TYPE
+ || m.getReturnType() == Short.TYPE
+ || m.getReturnType() == Integer.TYPE
+ || m.getReturnType() == Long.TYPE) {
+ write(reference, "CallMethod literalreturn " + ret);
+ } else if (m.getReturnType() == Float.TYPE
+ || m.getReturnType() == Double.TYPE) {
+ write(reference, "CallMethod literalreturn " + String.format("%308.308e", ret));
+ } else if (m.getReturnType() == Character.TYPE) {
+ write(reference, "CallMethod literalreturn " + (int) (Character) ret);
+ } else {
+ // Track returned object.
+ store.reference(ret);
+ write(reference, "CallMethod " + store.getIdentifier(ret));
+ }
+ } else if (message.startsWith("GetSuperclass")) {
+ String[] args = message.split(" ");
+ Integer classID = parseCall(args[1], null, Integer.class);
+ Class c = null;
+ Class ret = null;
+
+ c = (Class) store.getObject(classID);
+ ret = c.getSuperclass();
+ store.reference(ret);
+
+ write(reference, "GetSuperclass " + store.getIdentifier(ret));
+ } else if (message.startsWith("IsAssignableFrom")) {
+ String[] args = message.split(" ");
+ Integer classID = parseCall(args[1], null, Integer.class);
+ Integer superclassID = parseCall(args[2], null, Integer.class);
+
+ boolean result = false;
+ Class clz = (Class) store.getObject(classID);
+ Class sup = (Class) store.getObject(superclassID);
+
+ result = sup.isAssignableFrom(clz);
+
+ write(reference, "IsAssignableFrom " + (result ? "1" : "0"));
+ } else if (message.startsWith("IsInstanceOf")) {
+ String[] args = message.split(" ");
+ Integer objectID = parseCall(args[1], null, Integer.class);
+ Integer classID = parseCall(args[2], null, Integer.class);
+
+ boolean result = false;
+ Object o = (Object) store.getObject(objectID);
+ Class c = (Class) store.getObject(classID);
+
+ result = c.isInstance(o);
+
+ write(reference, "IsInstanceOf " + (result ? "1" : "0"));
+ } else if (message.startsWith("GetStringUTFLength")) {
+ String[] args = message.split(" ");
+ Integer stringID = parseCall(args[1], null, Integer.class);
+
+ String o = null;
+ byte[] b = null;
+ o = (String) store.getObject(stringID);
+ b = o.getBytes("UTF-8");
+ // System.out.println ("STRING UTF-8 LENGTH: " + o + " " +
+ // b.length);
+
+ write(reference, "GetStringUTFLength " + o.length());
+ } else if (message.startsWith("GetStringLength")) {
+ String[] args = message.split(" ");
+ Integer stringID = parseCall(args[1], null, Integer.class);
+
+ String o = null;
+ byte[] b = null;
+ o = (String) store.getObject(stringID);
+ b = o.getBytes("UTF-16LE");
+ // System.out.println ("STRING UTF-16 LENGTH: " + o + " " +
+ // b.length);
+
+ // System.out.println ("Java: GetStringLength " + b.length);
+ write(reference, "GetStringLength " + o.length());
+ } else if (message.startsWith("GetStringUTFChars")) {
+ String[] args = message.split(" ");
+ Integer stringID = parseCall(args[1], null, Integer.class);
+
+ String o = null;
+ byte[] b = null;
+ StringBuffer buf = null;
+ o = (String) store.getObject(stringID);
+ b = o.getBytes("UTF-8");
+ buf = new StringBuffer(b.length * 2);
+ buf.append(b.length);
+ for (int i = 0; i < b.length; i++)
+ buf
+ .append(" "
+ + Integer
+ .toString(((int) b[i]) & 0x0ff, 16));
+
+ // System.out.println ("Java: GetStringUTFChars: " + o);
+ // //System.out.println ("String UTF BYTES: " + buf);
+ write(reference, "GetStringUTFChars " + buf);
+ } else if (message.startsWith("GetStringChars")) {
+ String[] args = message.split(" ");
+ Integer stringID = parseCall(args[1], null, Integer.class);
+
+ String o = null;
+ byte[] b = null;
+ StringBuffer buf = null;
+ o = (String) store.getObject(stringID);
+ // FIXME: LiveConnect uses UCS-2.
+ b = o.getBytes("UTF-16LE");
+ buf = new StringBuffer(b.length * 2);
+ buf.append(b.length);
+ for (int i = 0; i < b.length; i++)
+ buf
+ .append(" "
+ + Integer
+ .toString(((int) b[i]) & 0x0ff, 16));
+
+ PluginDebug.debug("Java: GetStringChars: " + o);
+ PluginDebug.debug(" String BYTES: " + buf);
+ write(reference, "GetStringChars " + buf);
+ } else if (message.startsWith("GetToStringValue")) {
+ String[] args = message.split(" ");
+ Integer objectID = parseCall(args[1], null, Integer.class);
+
+ String o = null;
+ byte[] b = null;
+ StringBuffer buf = null;
+ o = store.getObject(objectID).toString();
+ b = o.getBytes("UTF-8");
+ buf = new StringBuffer(b.length * 2);
+ buf.append(b.length);
+ for (int i = 0; i < b.length; i++)
+ buf
+ .append(" "
+ + Integer
+ .toString(((int) b[i]) & 0x0ff, 16));
+
+ write(reference, "GetToStringValue " + buf);
+ } else if (message.startsWith("NewArray")) {
+ String[] args = message.split(" ");
+ String type = parseCall(args[1], null, String.class);
+ Integer length = parseCall(args[2], null, Integer.class);
+
+ // System.out.println ("CALLING: NewArray: " + type + " " +
+ // length + " "
+ // + Signature.primitiveNameToType(type));
+
+ Object newArray = null;
+
+ Class c;
+ if (type.equals("bool")) {
+ c = Boolean.class;
+ } else if (type.equals("double")) {
+ c = Double.class;
+ } else if (type.equals("int")) {
+ c = Integer.class;
+ } else if (type.equals("string")) {
+ c = String.class;
+ } else if (isInt(type)) {
+ c = (Class) store.getObject(Integer.parseInt(type));
+ } else {
+ c = JSObject.class;
+ }
+
+ if (args.length > 3)
+ newArray = Array.newInstance(c, new int[] { length, parseCall(args[3], null, Integer.class)});
+ else
+ newArray = Array.newInstance(c, length);
+
+ store.reference(newArray);
+ write(reference, "NewArray " + store.getIdentifier(newArray));
+ } else if (message.startsWith("HasMethod")) {
+ String[] args = message.split(" ");
+ Integer classNameID = parseCall(args[1], null, Integer.class);
+ Integer methodNameID = parseCall(args[2], null, Integer.class);
+
+ Class c = (Class) store.getObject(classNameID);
+ String methodName = (String) store.getObject(methodNameID);
+
+ Method method = null;
+ Method[] classMethods = c.getMethods();
+ for (Method m: classMethods) {
+ if (m.getName().equals(methodName)) {
+ method = m;
+ break;
+ }
+ }
+
+ int hasMethod = (method != null) ? 1 : 0;
+
+ write(reference, "HasMethod " + hasMethod);
+ } else if (message.startsWith("HasPackage")) {
+ String[] args = message.split(" ");
+ Integer instance = parseCall(args[1], null, Integer.class);
+ Integer nameID = parseCall(args[2], null, Integer.class);
+ String pkgName = (String) store.getObject(nameID);
+
+ Package pkg = Package.getPackage(pkgName);
+ int hasPkg = (pkg != null) ? 1 : 0;
+
+ write(reference, "HasPackage " + hasPkg);
+
+ } else if (message.startsWith("HasField")) {
+ String[] args = message.split(" ");
+ Integer classNameID = parseCall(args[1], null, Integer.class);
+ Integer fieldNameID = parseCall(args[2], null, Integer.class);
+
+ Class c = (Class) store.getObject(classNameID);
+ String fieldName = (String) store.getObject(fieldNameID);
+
+ Field field = null;
+ Field[] classFields = c.getFields();
+ for (Field f: classFields) {
+ if (f.getName().equals(fieldName)) {
+ field = f;
+ break;
+ }
+ }
+
+ int hasField = (field != null) ? 1 : 0;
+
+ write(reference, "HasField " + hasField);
+ } else if (message.startsWith("NewObjectArray")) {
+ String[] args = message.split(" ");
+ Integer length = parseCall(args[1], null, Integer.class);
+ Integer classID = parseCall(args[2], null, Integer.class);
+ Integer objectID = parseCall(args[3], null, Integer.class);
+
+ // System.out.println ("CALLING: NewObjectArray: " +
+ // classID + " " + length + " "
+ // + objectID);
+
+ Object newArray = null;
+ newArray = Array.newInstance((Class) store.getObject(classID),
+ length);
+
+ Object[] array = (Object[]) newArray;
+ for (int i = 0; i < array.length; i++)
+ array[i] = store.getObject(objectID);
+ store.reference(newArray);
+ write(reference, "NewObjectArray "
+ + store.getIdentifier(newArray));
+ } else if (message.startsWith("NewObjectWithConstructor")) {
+
+ String[] args = message.split(" ");
+ Integer classID = parseCall(args[1], null, Integer.class);
+ Integer methodID = parseCall(args[2], null, Integer.class);
+
+ final Constructor m = (Constructor) store.getObject(methodID);
+ Class[] argTypes = m.getParameterTypes();
+
+ // System.out.println ("NEWOBJ: HERE1");
+ Object[] arguments = new Object[argTypes.length];
+ // System.out.println ("NEWOBJ: HERE2");
+ for (int i = 0; i < argTypes.length; i++) {
+ arguments[i] = parseArgs(args[3 + i], argTypes[i]);
+ // System.out.println ("NEWOBJ: GOT ARG: " + arguments[i]);
+ }
+
+ final Object[] fArguments = arguments;
+ AccessControlContext acc = callContext != null ? callContext : getClosedAccessControlContext();
+
+ Class c = (Class) store.getObject(classID);
+ checkPermission(src, c, acc);
+
+ Object ret = AccessController.doPrivileged(new PrivilegedAction<Object> () {
+ public Object run() {
+ try {
+ return m.newInstance(fArguments);
+ } catch (Throwable t) {
+ return t;
+ }
+ }
+ }, acc);
+
+ if (ret instanceof Throwable)
+ throw (Throwable) ret;
+
+ store.reference(ret);
+
+ write(reference, "NewObject " + store.getIdentifier(ret));
+
+ } else if (message.startsWith("NewObject")) {
+ String[] args = message.split(" ");
+ Integer classID = parseCall(args[1], null, Integer.class);
+ Class c = (Class) store.getObject(classID);
+ final Constructor cons;
+ final Object[] fArguments;
+
+ Object[] arguments = new Object[args.length - 1];
+ arguments[0] = c;
+ for (int i = 0; i < args.length - 2; i++) {
+ arguments[i + 1] = store.getObject(parseCall(args[2 + i],
+ null, Integer.class));
+ PluginDebug.debug("GOT ARG: " + arguments[i + 1]);
+ }
+
+ Object[] matchingConstructorAndArgs = MethodOverloadResolver
+ .getMatchingConstructor(arguments);
+
+ if (matchingConstructorAndArgs == null) {
+ write(reference,
+ "Error: No suitable constructor with matching args found");
+ return;
+ }
+
+ Object[] castedArgs = new Object[matchingConstructorAndArgs.length - 1];
+ for (int i = 0; i < castedArgs.length; i++) {
+ castedArgs[i] = matchingConstructorAndArgs[i + 1];
+ }
+
+ cons = (Constructor) matchingConstructorAndArgs[0];
+ fArguments = castedArgs;
+
+ String collapsedArgs = "";
+ for (Object arg : fArguments) {
+ collapsedArgs += " " + arg.toString();
+ }
+
+ PluginDebug.debug("Calling constructor on class " + c +
+ " with " + collapsedArgs);
+
+ AccessControlContext acc = callContext != null ? callContext : getClosedAccessControlContext();
+ checkPermission(src, c, acc);
+
+ Object ret = AccessController.doPrivileged(new PrivilegedAction<Object> () {
+ public Object run() {
+ try {
+ return cons.newInstance(fArguments);
+ } catch (Throwable t) {
+ return t;
+ }
+ }
+ }, acc);
+
+ if (ret instanceof Throwable)
+ throw (Throwable) ret;
+
+ store.reference(ret);
+
+ write(reference, "NewObject " + store.getIdentifier(ret));
+
+ } else if (message.startsWith("NewStringUTF")) {
+ PluginDebug.debug("MESSAGE: " + message);
+ String[] args = message.split(" ");
+ int length = new Integer(args[1]);
+ byte[] byteArray = new byte[length];
+ String ret = null;
+ int i = 0;
+ int j = 2;
+ int c;
+ while (i < length) {
+ c = Integer.parseInt(args[j++], 16);
+ byteArray[i++] = (byte) c;
+ }
+
+ ret = new String(byteArray, "UTF-8");
+ PluginDebug.debug("NEWSTRINGUTF: " + ret);
+
+ store.reference(ret);
+ write(reference, "NewStringUTF " + store.getIdentifier(ret));
+ } else if (message.startsWith("NewString")) {
+ PluginDebug.debug("MESSAGE: " + message);
+ String[] args = message.split(" ");
+ Integer strlength = parseCall(args[1], null, Integer.class);
+ int bytelength = 2 * strlength;
+ byte[] byteArray = new byte[bytelength];
+ String ret = null;
+ for (int i = 0; i < strlength; i++) {
+ int c = parseCall(args[2 + i], null, Integer.class);
+ PluginDebug.debug("char " + i + " " + c);
+ // Low.
+ byteArray[2 * i] = (byte) (c & 0x0ff);
+ // High.
+ byteArray[2 * i + 1] = (byte) ((c >> 8) & 0x0ff);
+ }
+ ret = new String(byteArray, 0, bytelength, "UTF-16LE");
+ PluginDebug.debug("NEWSTRING: " + ret);
+
+ // System.out.println ("NEWOBJ: CALLED: " + ret);
+ // System.out.println ("NEWOBJ: CALLED: " +
+ // store.getObject(ret));
+ store.reference(ret);
+ write(reference, "NewString " + store.getIdentifier(ret));
+
+ } else if (message.startsWith("ExceptionOccurred")) {
+ PluginDebug.debug("EXCEPTION: " + throwable);
+ if (throwable != null)
+ store.reference(throwable);
+ write(reference, "ExceptionOccurred "
+ + store.getIdentifier(throwable));
+ } else if (message.startsWith("ExceptionClear")) {
+ if (throwable != null && store.contains(throwable))
+ store.unreference(store.getIdentifier(throwable));
+ throwable = null;
+ write(reference, "ExceptionClear");
+ } else if (message.startsWith("DeleteGlobalRef")) {
+ String[] args = message.split(" ");
+ Integer id = parseCall(args[1], null, Integer.class);
+ store.unreference(id);
+ write(reference, "DeleteGlobalRef");
+ } else if (message.startsWith("DeleteLocalRef")) {
+ String[] args = message.split(" ");
+ Integer id = parseCall(args[1], null, Integer.class);
+ store.unreference(id);
+ write(reference, "DeleteLocalRef");
+ } else if (message.startsWith("NewGlobalRef")) {
+ String[] args = message.split(" ");
+ Integer id = parseCall(args[1], null, Integer.class);
+ store.reference(store.getObject(id));
+ write(reference, "NewGlobalRef " + id);
+ } else if (message.startsWith("GetClassName")) {
+ String[] args = message.split(" ");
+ Integer objectID = parseCall(args[1], null, Integer.class);
+ Object o = (Object) store.getObject(objectID);
+ write(reference, "GetClassName " + o.getClass().getName());
+ } else if (message.startsWith("GetClassID")) {
+ String[] args = message.split(" ");
+ Integer objectID = parseCall(args[1], null, Integer.class);
+ store.reference(store.getObject(objectID).getClass());
+ write(reference, "GetClassID " + store.getIdentifier(store.getObject(objectID).getClass()));
+ }
+ } catch (Throwable t) {
+ t.printStackTrace();
+ String msg = t.getCause() != null ? t.getCause().getMessage() : t.getMessage();
+
+ // add an identifier string to let javaside know of the type of error
+ // check for cause as well, since the top level exception will be InvocationTargetException in most cases
+ if (t instanceof AccessControlException || t.getCause() instanceof AccessControlException) {
+ msg = "LiveConnectPermissionNeeded " + msg;
+ }
+
+ write(reference, " Error " + msg);
+
+ // ExceptionOccured is only called after Callmethod() by mozilla. So
+ // for exceptions that are not related to CallMethod, we need a way
+ // to log them. This is how we do it.. send an error message to the
+ // c++ side to let it know that something went wrong, and it will do
+ // the right thing to let mozilla know
+
+ // Store the cause as the actual exception. This is needed because
+ // the exception we get here will always be an
+ // "InvocationTargetException" due to the use of reflection above
+ if (message.startsWith("CallMethod") || message.startsWith("CallStaticMethod"))
+ throwable = t.getCause();
+ }
+
+ }
+
+ /**
+ * Checks if the calling script is allowed to access the specified class
+ *
+ * @param jsSrc The source of the script
+ * @param target The target class that the script is trying to access
+ * @param acc AccessControlContext for this execution
+ * @throws AccessControlException If the script has insufficient permissions
+ */
+ public void checkPermission(String jsSrc, Class target, AccessControlContext acc) throws AccessControlException {
+ // NPRuntime does not allow cross-site calling. We therefore always
+ // allow this, for the time being
+ return;
+ }
+
+ private void write(int reference, String message) {
+ PluginDebug.debug("appletviewer writing " + message);
+ streamhandler.write("context " + identifier + " reference " + reference
+ + " " + message);
+ }
+
+ public void prePopulateLCClasses() {
+
+ int classID;
+
+ prepopulateClass("netscape/javascript/JSObject");
+ classID = prepopulateClass("netscape/javascript/JSException");
+ prepopulateMethod(classID, "<init>", "(Ljava/lang/String;Ljava/lang/String;ILjava/lang/String;I)");
+ prepopulateMethod(classID, "<init>", "(ILjava/lang/Object;)");
+ prepopulateField(classID, "lineno");
+ prepopulateField(classID, "tokenIndex");
+ prepopulateField(classID, "source");
+ prepopulateField(classID, "filename");
+ prepopulateField(classID, "wrappedExceptionType");
+ prepopulateField(classID, "wrappedException");
+
+ classID = prepopulateClass("netscape/javascript/JSUtil");
+ prepopulateMethod(classID, "getStackTrace", "(Ljava/lang/Throwable;)");
+
+ prepopulateClass("java/lang/Object");
+ classID = prepopulateClass("java/lang/Class");
+ prepopulateMethod(classID, "getMethods", "()");
+ prepopulateMethod(classID, "getConstructors", "()");
+ prepopulateMethod(classID, "getFields", "()");
+ prepopulateMethod(classID, "getName", "()");
+ prepopulateMethod(classID, "isArray", "()");
+ prepopulateMethod(classID, "getComponentType", "()");
+ prepopulateMethod(classID, "getModifiers", "()");
+
+
+ classID = prepopulateClass("java/lang/reflect/Method");
+ prepopulateMethod(classID, "getName", "()");
+ prepopulateMethod(classID, "getParameterTypes", "()");
+ prepopulateMethod(classID, "getReturnType", "()");
+ prepopulateMethod(classID, "getModifiers", "()");
+
+ classID = prepopulateClass("java/lang/reflect/Constructor");
+ prepopulateMethod(classID, "getParameterTypes", "()");
+ prepopulateMethod(classID, "getModifiers", "()");
+
+ classID = prepopulateClass("java/lang/reflect/Field");
+ prepopulateMethod(classID, "getName", "()");
+ prepopulateMethod(classID, "getType", "()");
+ prepopulateMethod(classID, "getModifiers", "()");
+
+ classID = prepopulateClass("java/lang/reflect/Array");
+ prepopulateMethod(classID, "newInstance", "(Ljava/lang/Class;I)");
+
+ classID = prepopulateClass("java/lang/Throwable");
+ prepopulateMethod(classID, "toString", "()");
+ prepopulateMethod(classID, "getMessage", "()");
+
+ classID = prepopulateClass("java/lang/System");
+ prepopulateMethod(classID, "identityHashCode", "(Ljava/lang/Object;)");
+
+ classID = prepopulateClass("java/lang/Boolean");
+ prepopulateMethod(classID, "booleanValue", "()");
+ prepopulateMethod(classID, "<init>", "(Z)");
+
+ classID = prepopulateClass("java/lang/Double");
+ prepopulateMethod(classID, "doubleValue", "()");
+ prepopulateMethod(classID, "<init>", "(D)");
+
+ classID = prepopulateClass("java/lang/Void");
+ prepopulateField(classID, "TYPE");
+
+ prepopulateClass("java/lang/String");
+ prepopulateClass("java/applet/Applet");
+ }
+
+ private int prepopulateClass(String name) {
+ name = name.replace('/', '.');
+ ClassLoader cl = liveconnectLoader;
+ Class c = null;
+
+ try {
+ c = cl.loadClass(name);
+ store.reference(c);
+ } catch (ClassNotFoundException cnfe) {
+ // do nothing ... this should never happen
+ cnfe.printStackTrace();
+ }
+
+ return store.getIdentifier(c);
+ }
+
+ private int prepopulateMethod(int classID, String methodName, String signatureStr) {
+ Signature signature = parseCall(signatureStr, ((Class) store.getObject(classID)).getClassLoader(), Signature.class);
+ Object[] a = signature.getClassArray();
+
+ Class c = (Class) store.getObject(classID);
+ Method m = null;
+ Constructor cs = null;
+ Object o = null;
+
+ try {
+ if (methodName.equals("<init>")
+ || methodName.equals("<clinit>")) {
+ o = cs = c.getConstructor(signature.getClassArray());
+ store.reference(cs);
+ } else {
+ o = m = c.getMethod(methodName, signature.getClassArray());
+ store.reference(m);
+ }
+ } catch (NoSuchMethodException e) {
+ // should never happen
+ e.printStackTrace();
+ }
+
+ return store.getIdentifier(m);
+ }
+
+ private int prepopulateField(int classID, String fieldName) {
+
+ Class c = (Class) store.getObject(classID);
+ Field f = null;
+ try {
+ f = c.getField(fieldName);
+ } catch (SecurityException e) {
+ // should never happen
+ e.printStackTrace();
+ } catch (NoSuchFieldException e) {
+ // should never happen
+ e.printStackTrace();
+ }
+
+ store.reference(f);
+ return store.getIdentifier(f);
+ }
+
+ public void dumpStore() {
+ store.dump();
+ }
+
+ public Object getObject(int identifier) {
+ return store.getObject(identifier);
+ }
+
+ public int getIdentifier(Object o) {
+ return store.getIdentifier(o);
+ }
+
+ public void store(Object o) {
+ store.reference(o);
+ }
+
+ /**
+ * Returns a "closed" AccessControlContext i.e. no permissions to get out of sandbox.
+ */
+ public AccessControlContext getClosedAccessControlContext() {
+ // Deny everything
+ Permissions p = new Permissions();
+ ProtectionDomain pd = new ProtectionDomain(null, p);
+ return new AccessControlContext(new ProtectionDomain[] {pd});
+ }
+
+ public AccessControlContext getAccessControlContext(String[] nsPrivilegeList, String src) {
+
+/*
+ for (int i=0; i < nsPrivilegeList.length; i++) {
+ String privilege = nsPrivilegeList[i];
+
+ if (privilege.equals("UniversalAccept")) {
+ SocketPermission sp = new SocketPermission("*", "accept,resolve");
+ grantedPermissions.add(sp);
+ } else if (privilege.equals("UniversalAwtEventQueueAccess")) {
+ AWTPermission awtp = new AWTPermission("accessEventQueue");
+ grantedPermissions.add(awtp);
+ } else if (privilege.equals("UniversalConnect")) {
+ SocketPermission sp = new SocketPermission("*", "connect,resolve");
+ grantedPermissions.add(sp);
+ } else if (privilege.equals("UniversalListen")) {
+ SocketPermission sp = new SocketPermission("*", "listen,resolve");
+ grantedPermissions.add(sp);
+ } else if (privilege.equals("UniversalExecAccess")) {
+ FilePermission fp = new FilePermission("<<ALL FILES>>", "execute");
+ RuntimePermission rtp = new RuntimePermission("setIO");
+ grantedPermissions.add(fp);
+ grantedPermissions.add(rtp);
+ } else if (privilege.equals("UniversalExitAccess")) {
+ // Doesn't matter what the permissions are. Do not allow VM to exit.. we
+ // use a single VM for the entire browser lifecycle once invoked, we
+ // cannot let it exit
+
+ //RuntimePermission rtp = new RuntimePermission("exitVM.*");
+ //grantedPermissions.add(rtp);
+ } else if (privilege.equals("UniversalFileDelete")) {
+ FilePermission fp = new FilePermission("<<ALL FILES>>", "delete");
+ grantedPermissions.add(fp);
+ } else if (privilege.equals("UniversalFileRead")) {
+ FilePermission fp = new FilePermission("<<ALL FILES>>", "read");
+ grantedPermissions.add(fp);
+ } else if (privilege.equals("UniversalFileWrite")) {
+ FilePermission fp = new FilePermission("<<ALL FILES>>", "write");
+ grantedPermissions.add(fp);
+ } else if (privilege.equals("UniversalFdRead")) {
+ RuntimePermission rtp = new RuntimePermission("readFileDescriptor");
+ grantedPermissions.add(rtp);
+ } else if (privilege.equals("UniversalFdWrite")) {
+ RuntimePermission rtp = new RuntimePermission("writeFileDescriptor");
+ grantedPermissions.add(rtp);
+ } else if (privilege.equals("UniversalLinkAccess")) {
+ RuntimePermission rtp = new RuntimePermission("loadLibrary.*");
+ grantedPermissions.add(rtp);
+ } else if (privilege.equals("UniversalListen")) {
+ SocketPermission sp = new SocketPermission("*", "listen");
+ grantedPermissions.add(sp);
+ } else if (privilege.equals("UniversalMulticast")) {
+ SocketPermission sp = new SocketPermission("*", "accept,connect,resolve");
+ grantedPermissions.add(sp);
+ } else if (privilege.equals("UniversalPackageAccess")) {
+ RuntimePermission rtp = new RuntimePermission("defineClassInPackage.*");
+ grantedPermissions.add(rtp);
+ } else if (privilege.equals("UniversalPackageDefinition")) {
+ RuntimePermission rtp = new RuntimePermission("accessClassInPackage.*");
+ grantedPermissions.add(rtp);
+ } else if (privilege.equals("UniversalPrintJobAccess")) {
+ RuntimePermission rtp = new RuntimePermission("queuePrintJob");
+ grantedPermissions.add(rtp);
+ } else if (privilege.equals("UniversalPropertyRead")) {
+ PropertyPermission pp = new PropertyPermission("*", "read");
+ grantedPermissions.add(pp);
+ } else if (privilege.equals("UniversalPropertyWrite")) {
+ PropertyPermission pp = new PropertyPermission("*", "write");
+ grantedPermissions.add(pp);
+ } else if (privilege.equals("UniversalSetFactory")) {
+ RuntimePermission rtp = new RuntimePermission("setFactory");
+ grantedPermissions.add(rtp);
+ } else if (privilege.equals("UniversalSystemClipboardAccess")) {
+ AWTPermission awtp = new AWTPermission("accessClipboard");
+ grantedPermissions.add(awtp);
+ } else if (privilege.equals("UniversalThreadAccess")) {
+ RuntimePermission rtp1 = new RuntimePermission("modifyThread");
+ RuntimePermission rtp2 = new RuntimePermission("stopThread");
+ grantedPermissions.add(rtp1);
+ grantedPermissions.add(rtp2);
+ } else if (privilege.equals("UniversalThreadGroupAccess")) {
+ RuntimePermission rtp1 = new RuntimePermission("modifyThreadGroup");
+ RuntimePermission rtp2 = new RuntimePermission("modifyThread");
+ RuntimePermission rtp3 = new RuntimePermission("stopThread");
+ grantedPermissions.add(rtp1);
+ grantedPermissions.add(rtp2);
+ grantedPermissions.add(rtp3);
+ } else if (privilege.equals("UniversalTopLevelWindow")) {
+ AWTPermission awtp = new AWTPermission("topLevelWindow");
+ grantedPermissions.add(awtp);
+ } else if (privilege.equals("UniversalBrowserRead")) {
+ BrowserReadPermission bp = new BrowserReadPermission();
+ grantedPermissions.add(bp);
+ } else if (privilege.equals("UniversalJavaPermissions")) {
+ AllPermission ap = new AllPermission();
+ grantedPermissions.add(ap);
+ }
+ }
+
+ // what to do with these is unknown: UniversalConnectWithRedirect, UniversalDialogModality, UniversalSendMail, LimitedInstall, FullInstall, SilentInstall
+*/
+
+ Permissions grantedPermissions = new Permissions();
+
+ for (int i=0; i < nsPrivilegeList.length; i++) {
+ String privilege = nsPrivilegeList[i];
+
+ if (privilege.equals("UniversalBrowserRead")) {
+ BrowserReadPermission bp = new BrowserReadPermission();
+ grantedPermissions.add(bp);
+ } else if (privilege.equals("UniversalJavaPermission")) {
+ AllPermission ap = new AllPermission();
+ grantedPermissions.add(ap);
+ }
+ }
+
+ CodeSource cs = new CodeSource((URL) null, (java.security.cert.Certificate [])null);
+
+ if (src != null && src.length() > 0) {
+ try {
+ cs = new CodeSource(new URL(src + "/"), (java.security.cert.Certificate[]) null);
+ } catch (MalformedURLException mfue) {
+ // do nothing
+ }
+
+ if (src.equals("[System]"))
+ grantedPermissions.add(new JSObjectCreatePermission());
+
+ } else {
+ JSObjectCreatePermission perm = new JSObjectCreatePermission();
+ grantedPermissions.add(perm);
+ }
+
+ ProtectionDomain pd = new ProtectionDomain(cs, grantedPermissions, null, null);
+
+ // Add to hashmap
+ return new AccessControlContext(new ProtectionDomain[] {pd});
+ }
+
+ // private static final == inline
+ private static final boolean isInt(Object o) {
+ boolean isInt = false;
+
+ try {
+ Integer.parseInt((String) o);
+ isInt = true;
+ } catch (Exception e) {
+ // don't care
+ }
+
+ return isInt;
+ }
+
+ class BrowserReadPermission extends BasicPermission {
+ public BrowserReadPermission() {
+ super("browserRead");
+ }
+ }
+
+}
diff --git a/plugin/icedteanp/java/sun/applet/PluginAppletViewer.java b/plugin/icedteanp/java/sun/applet/PluginAppletViewer.java
new file mode 100644
index 0000000..382ff7b
--- /dev/null
+++ b/plugin/icedteanp/java/sun/applet/PluginAppletViewer.java
@@ -0,0 +1,2056 @@
+/* PluginAppletViewer -- Handles embedding of the applet panel
+ Copyright (C) 2008 Red Hat
+
+This file is part of IcedTea.
+
+IcedTea is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+IcedTea is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with IcedTea; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+/*
+ * Copyright 1995-2004 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+ package sun.applet;
+
+ import java.applet.Applet;
+import java.applet.AppletContext;
+import java.applet.AudioClip;
+import java.awt.Dimension;
+import java.awt.Frame;
+import java.awt.Graphics;
+import java.awt.Image;
+import java.awt.Insets;
+import java.awt.Label;
+import java.awt.Toolkit;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.awt.event.WindowListener;
+import java.awt.print.PageFormat;
+import java.awt.print.Printable;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.PrintStream;
+import java.io.Reader;
+import java.io.StringReader;
+import java.io.UnsupportedEncodingException;
+import java.lang.reflect.InvocationTargetException;
+import java.net.MalformedURLException;
+import java.net.SocketPermission;
+import java.net.URI;
+import java.net.URL;
+import java.security.AccessController;
+import java.security.AllPermission;
+import java.security.PrivilegedAction;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Vector;
+
+import javax.swing.SwingUtilities;
+
+import net.sourceforge.jnlp.NetxPanel;
+import net.sourceforge.jnlp.runtime.JNLPClassLoader;
+import sun.awt.AppContext;
+import sun.awt.SunToolkit;
+import sun.awt.X11.XEmbeddedFrame;
+import sun.misc.Ref;
+
+import com.sun.jndi.toolkit.url.UrlUtil;
+
+ /**
+ * Lets us construct one using unix-style one shot behaviors
+ */
+
+ class PluginAppletPanelFactory
+ {
+
+ public AppletPanel createPanel(PluginStreamHandler streamhandler,
+ int identifier,
+ long handle, int x, int y,
+ final URL doc, final Hashtable atts) {
+
+ AppletViewerPanel panel = (AppletViewerPanel) AccessController.doPrivileged(new PrivilegedAction() {
+ public Object run() {
+ try {
+ AppletPanel panel = new NetxPanel(doc, atts, false);
+ AppletViewerPanel.debug("Using NetX panel");
+ PluginDebug.debug(atts.toString());
+ return panel;
+ } catch (Exception ex) {
+ AppletViewerPanel.debug("Unable to start NetX applet - defaulting to Sun applet", ex);
+ return new AppletViewerPanel(doc, atts);
+ }
+ }
+ });
+
+
+
+ // create the frame.
+ PluginAppletViewer.reFrame(null, identifier, System.out, handle, panel);
+
+ panel.init();
+
+ // Start the applet
+ initEventQueue(panel);
+
+ // Applet initialized. Find out it's classloader and add it to the list
+ String portComponent = doc.getPort() != -1 ? ":" + doc.getPort() : "";
+ String codeBase = doc.getProtocol() + "://" + doc.getHost() + portComponent;
+
+ if (atts.get("codebase") != null) {
+ try {
+ URL appletSrcURL = new URL(codeBase + (String) atts.get("codebase"));
+ codeBase = appletSrcURL.getProtocol() + "://" + appletSrcURL.getHost();
+ } catch (MalformedURLException mfue) {
+ // do nothing
+ }
+ }
+
+
+ // Wait for the panel to initialize
+ // (happens in a separate thread)
+ Applet a;
+
+ // Wait for panel to come alive
+ int maxWait = PluginAppletViewer.APPLET_TIMEOUT; // wait for panel to come alive
+ int wait = 0;
+ while ((panel == null) || (!((NetxPanel) panel).isAlive() && wait < maxWait)) {
+ try {
+ Thread.sleep(50);
+ wait += 50;
+ } catch (InterruptedException ie) {
+ // just wait
+ }
+ }
+
+ // Wait for the panel to initialize
+ // (happens in a separate thread)
+ while (panel.getApplet() == null &&
+ ((NetxPanel) panel).isAlive()) {
+ try {
+ Thread.sleep(50);
+ PluginDebug.debug("Waiting for applet to initialize...");
+ } catch (InterruptedException ie) {
+ // just wait
+ }
+ }
+
+ a = panel.getApplet();
+
+ // Still null?
+ if (panel.getApplet() == null) {
+ streamhandler.write("instance " + identifier + " reference " + -1 + " fatalError " + "Initialization failed");
+ return null;
+ }
+
+ PluginDebug.debug("Applet " + a.getClass() + " initialized");
+ streamhandler.write("instance " + identifier + " reference 0 initialized");
+
+ AppletSecurityContextManager.getSecurityContext(0).associateSrc(((NetxPanel) panel).getAppletClassLoader(), doc);
+ AppletSecurityContextManager.getSecurityContext(0).associateInstance(identifier, ((NetxPanel) panel).getAppletClassLoader());
+
+ return panel;
+ }
+
+ public boolean isStandalone()
+ {
+ return false;
+ }
+
+ /**
+ * Send the initial set of events to the appletviewer event queue.
+ * On start-up the current behaviour is to load the applet and call
+ * Applet.init() and Applet.start().
+ */
+ private void initEventQueue(AppletPanel panel) {
+ // appletviewer.send.event is an undocumented and unsupported system
+ // property which is used exclusively for testing purposes.
+ PrivilegedAction pa = new PrivilegedAction() {
+ public Object run() {
+ return System.getProperty("appletviewer.send.event");
+ }
+ };
+ String eventList = (String) AccessController.doPrivileged(pa);
+
+ if (eventList == null) {
+ // Add the standard events onto the event queue.
+ panel.sendEvent(AppletPanel.APPLET_LOAD);
+ panel.sendEvent(AppletPanel.APPLET_INIT);
+ panel.sendEvent(AppletPanel.APPLET_START);
+ } else {
+ // We're testing AppletViewer. Force the specified set of events
+ // onto the event queue, wait for the events to be processed, and
+ // exit.
+
+ // The list of events that will be executed is provided as a
+ // ","-separated list. No error-checking will be done on the list.
+ String [] events = splitSeparator(",", eventList);
+
+ for (int i = 0; i < events.length; i++) {
+ PluginDebug.debug("Adding event to queue: " + events[i]);
+ if (events[i].equals("dispose"))
+ panel.sendEvent(AppletPanel.APPLET_DISPOSE);
+ else if (events[i].equals("load"))
+ panel.sendEvent(AppletPanel.APPLET_LOAD);
+ else if (events[i].equals("init"))
+ panel.sendEvent(AppletPanel.APPLET_INIT);
+ else if (events[i].equals("start"))
+ panel.sendEvent(AppletPanel.APPLET_START);
+ else if (events[i].equals("stop"))
+ panel.sendEvent(AppletPanel.APPLET_STOP);
+ else if (events[i].equals("destroy"))
+ panel.sendEvent(AppletPanel.APPLET_DESTROY);
+ else if (events[i].equals("quit"))
+ panel.sendEvent(AppletPanel.APPLET_QUIT);
+ else if (events[i].equals("error"))
+ panel.sendEvent(AppletPanel.APPLET_ERROR);
+ else
+ // non-fatal error if we get an unrecognized event
+ PluginDebug.debug("Unrecognized event name: " + events[i]);
+ }
+
+ while (!panel.emptyEventQueue()) ;
+ }
+ }
+
+
+ /**
+ * Split a string based on the presence of a specified separator. Returns
+ * an array of arbitrary length. The end of each element in the array is
+ * indicated by the separator of the end of the string. If there is a
+ * separator immediately before the end of the string, the final element
+ * will be empty. None of the strings will contain the separator. Useful
+ * when separating strings such as "foo/bar/bas" using separator "/".
+ *
+ * @param sep The separator.
+ * @param s The string to split.
+ * @return An array of strings. Each string in the array is determined
+ * by the location of the provided sep in the original string,
+ * s. Whitespace not stripped.
+ */
+ private String [] splitSeparator(String sep, String s) {
+ Vector v = new Vector();
+ int tokenStart = 0;
+ int tokenEnd = 0;
+
+ while ((tokenEnd = s.indexOf(sep, tokenStart)) != -1) {
+ v.addElement(s.substring(tokenStart, tokenEnd));
+ tokenStart = tokenEnd+1;
+ }
+ // Add the final element.
+ v.addElement(s.substring(tokenStart));
+
+ String [] retVal = new String[v.size()];
+ v.copyInto(retVal);
+ return retVal;
+ }
+ }
+
+ class PluginParseRequest
+ {
+ long handle;
+ String tag;
+ String documentbase;
+ }
+
+ /*
+ */
+ // FIXME: declare JSProxy implementation
+ public class PluginAppletViewer extends XEmbeddedFrame
+ implements AppletContext, Printable {
+ /**
+ * Some constants...
+ */
+ private static String defaultSaveFile = "Applet.ser";
+
+ private static enum PAV_INIT_STATUS {PRE_INIT, IN_INIT, INIT_COMPLETE, INACTIVE};
+
+ /**
+ * The panel in which the applet is being displayed.
+ */
+ AppletViewerPanel panel;
+
+ /**
+ * The status line.
+ */
+ Label label;
+
+ /**
+ * output status messages to this stream
+ */
+
+ PrintStream statusMsgStream;
+
+ int identifier;
+
+ private static HashMap<Integer, PluginParseRequest> requests =
+ new HashMap();
+
+ // Instance identifier -> PluginAppletViewer object.
+ private static HashMap<Integer, PluginAppletViewer> applets =
+ new HashMap();
+
+ private static PluginStreamHandler streamhandler;
+
+ private static PluginCallRequestFactory requestFactory;
+
+ private static HashMap<Integer, PAV_INIT_STATUS> status =
+ new HashMap<Integer,PAV_INIT_STATUS>();
+
+
+ private long handle = 0;
+ private WindowListener windowEventListener = null;
+ private AppletEventListener appletEventListener = null;
+
+ public static final int APPLET_TIMEOUT = 180000;
+
+ private static Long requestIdentityCounter = 0L;
+
+ /**
+ * Null constructor to allow instantiation via newInstance()
+ */
+ public PluginAppletViewer() {
+ }
+
+ public static void reFrame(PluginAppletViewer oldFrame,
+ int identifier, PrintStream statusMsgStream,
+ long handle, AppletViewerPanel panel) {
+
+ PluginDebug.debug("Reframing " + panel);
+
+ // SecurityManager MUST be set, and only privileged code may call reFrame()
+ System.getSecurityManager().checkPermission(new AllPermission());
+
+ // Same handle => nothing to do
+ if (oldFrame != null && handle == oldFrame.handle)
+ return;
+
+ PluginAppletViewer newFrame = new PluginAppletViewer(handle, identifier, statusMsgStream, panel);
+
+ if (oldFrame != null) {
+ applets.remove(oldFrame.identifier);
+ oldFrame.removeWindowListener(oldFrame.windowEventListener);
+ panel.removeAppletListener(oldFrame.appletEventListener);
+ oldFrame.remove(panel);
+ oldFrame.dispose();
+ }
+
+ newFrame.add("Center", panel);
+ newFrame.pack();
+
+ newFrame.appletEventListener = new AppletEventListener(newFrame, newFrame);
+ panel.addAppletListener(newFrame.appletEventListener);
+
+ applets.put(identifier, newFrame);
+
+ // dispose oldframe if necessary
+ if (oldFrame != null) {
+ oldFrame.dispose();
+ }
+
+ PluginDebug.debug(panel + " reframed");
+ }
+
+ /**
+ * Create new plugin appletviewer frame
+ */
+ private PluginAppletViewer(long handle, final int identifier,
+ PrintStream statusMsgStream,
+ AppletViewerPanel appletPanel) {
+
+ super(handle, true);
+ this.statusMsgStream = statusMsgStream;
+ this.identifier = identifier;
+ this.panel = appletPanel;
+
+ if (!appletPanels.contains(panel))
+ appletPanels.addElement(panel);
+
+ windowEventListener = new WindowAdapter() {
+
+ public void windowClosing(WindowEvent evt) {
+ appletClose();
+ }
+
+ public void windowIconified(WindowEvent evt) {
+ appletStop();
+ }
+
+ public void windowDeiconified(WindowEvent evt) {
+ appletStart();
+ }
+ };
+
+ addWindowListener(windowEventListener);
+
+ }
+
+ private static class AppletEventListener implements AppletListener
+ {
+ final Frame frame;
+ final PluginAppletViewer appletViewer;
+
+ public AppletEventListener(Frame frame, PluginAppletViewer appletViewer)
+ {
+ this.frame = frame;
+ this.appletViewer = appletViewer;
+ }
+
+ public void appletStateChanged(AppletEvent evt)
+ {
+ AppletPanel src = (AppletPanel)evt.getSource();
+
+ switch (evt.getID()) {
+ case AppletPanel.APPLET_RESIZE: {
+ if(src != null) {
+ appletViewer.resize(appletViewer.preferredSize());
+ appletViewer.validate();
+ }
+ break;
+ }
+ case AppletPanel.APPLET_LOADING_COMPLETED: {
+ Applet a = src.getApplet(); // sun.applet.AppletPanel
+
+ // Fixed #4754451: Applet can have methods running on main
+ // thread event queue.
+ //
+ // The cause of this bug is that the frame of the applet
+ // is created in main thread group. Thus, when certain
+ // AWT/Swing events are generated, the events will be
+ // dispatched through the wrong event dispatch thread.
+ //
+ // To fix this, we rearrange the AppContext with the frame,
+ // so the proper event queue will be looked up.
+ //
+ // Swing also maintains a Frame list for the AppContext,
+ // so we will have to rearrange it as well.
+ //
+ if (a != null)
+ AppletPanel.changeFrameAppContext(frame, SunToolkit.targetToAppContext(a));
+ else
+ AppletPanel.changeFrameAppContext(frame, AppContext.getAppContext());
+
+ status.put(appletViewer.identifier, PAV_INIT_STATUS.INIT_COMPLETE);
+
+ break;
+ }
+ }
+ }
+ }
+
+ public static void setStreamhandler(PluginStreamHandler sh) {
+ streamhandler = sh;
+ }
+
+ public static void setPluginCallRequestFactory(PluginCallRequestFactory rf) {
+ requestFactory = rf;
+ }
+
+ /**
+ * Handle an incoming message from the plugin.
+ */
+ public static void handleMessage(int identifier, int reference, String message)
+ {
+
+ PluginDebug.debug("PAV handling: " + message);
+
+ try {
+ if (message.startsWith("handle")) {
+
+ // Extract the information from the message
+ String[] msgParts = new String[4];
+ for (int i=0; i < 3; i++) {
+ int spaceLocation = message.indexOf(' ');
+ int nextSpaceLocation = message.indexOf(' ', spaceLocation+1);
+ msgParts[i] = message.substring(spaceLocation + 1, nextSpaceLocation);
+ message = message.substring(nextSpaceLocation + 1);
+ }
+
+ long handle = Long.parseLong(msgParts[0]);
+ String width = msgParts[1];
+ String height = msgParts[2];
+
+ int spaceLocation = message.indexOf(' ', "tag".length()+1);
+ String documentBase =
+ UrlUtil.decode(message.substring("tag".length() + 1, spaceLocation));
+ String tag = message.substring(spaceLocation+1);
+
+ PluginDebug.debug ("Handle = " + handle + "\n" +
+ "Width = " + width + "\n" +
+ "Height = " + height + "\n" +
+ "DocumentBase = " + documentBase + "\n" +
+ "Tag = " + tag);
+
+ status.put(identifier, PAV_INIT_STATUS.PRE_INIT);
+ PluginAppletViewer.parse
+ (identifier, handle, width, height,
+ new StringReader(tag),
+ new URL(documentBase));
+
+
+ int maxWait = APPLET_TIMEOUT; // wait for applet to fully load
+ int wait = 0;
+ while (!status.get(identifier).equals(PAV_INIT_STATUS.INIT_COMPLETE) &&
+ (wait < maxWait)) {
+
+ try {
+ Thread.sleep(50);
+ wait += 50;
+ } catch (InterruptedException ie) {
+ // just wait
+ }
+ }
+
+ if (!status.get(identifier).equals(PAV_INIT_STATUS.INIT_COMPLETE))
+ throw new Exception("Applet initialization timeout");
+
+ } else {
+ PluginDebug.debug ("Handling message: " + message + " instance " + identifier + " " + Thread.currentThread());
+
+ // Wait till initialization finishes
+ while (!applets.containsKey(identifier) &&
+ (
+ !status.containsKey(identifier) ||
+ status.get(identifier).equals(PAV_INIT_STATUS.PRE_INIT)
+ )
+ );
+
+ // don't bother processing further for inactive applets
+ if (status.get(identifier).equals(PAV_INIT_STATUS.INACTIVE))
+ return;
+
+ applets.get(identifier).handleMessage(reference, message);
+ }
+ } catch (Exception e) {
+
+ e.printStackTrace();
+
+ // If an exception happened during pre-init, we need to update status
+ if (status.get(identifier).equals(PAV_INIT_STATUS.PRE_INIT))
+ status.put(identifier, PAV_INIT_STATUS.INACTIVE);
+
+ throw new RuntimeException("Failed to handle message: " +
+ message + " for instance " + identifier, e);
+ }
+ }
+
+ public void handleMessage(int reference, String message)
+ {
+ if (message.startsWith("width")) {
+
+ // Wait for panel to come alive
+ int maxWait = APPLET_TIMEOUT; // wait for panel to come alive
+ int wait = 0;
+ while (!status.get(identifier).equals(PAV_INIT_STATUS.INIT_COMPLETE) && wait < maxWait) {
+
+ try {
+ Thread.sleep(50);
+ wait += 50;
+ } catch (InterruptedException ie) {
+ // just wait
+ }
+ }
+
+
+ // 0 => width, 1=> width_value, 2 => height, 3=> height_value
+ String[] dimMsg = message.split(" ");
+
+ final int height = (int) (Integer.parseInt(dimMsg[3]));
+ final int width = (int) (Integer.parseInt(dimMsg[1]));
+
+ if (panel instanceof NetxPanel)
+ ((NetxPanel) panel).updateSizeInAtts(height, width);
+
+ try {
+ SwingUtilities.invokeAndWait(new Runnable() {
+ public void run() {
+
+ setSize(width, height);
+
+ // There is a rather odd drawing bug whereby resizing
+ // the panel makes no difference on initial call
+ // because the panel thinks that it is already the
+ // right size. Validation has no effect there either.
+ // So we work around by setting size to 1, validating,
+ // and then setting to the right size and validating
+ // again. This is not very efficient, and there is
+ // probably a better way -- but resizing happens
+ // quite infrequently, so for now this is how we do it
+
+ panel.setSize(1,1);
+ panel.validate();
+
+ panel.setSize(width, height);
+ panel.validate();
+
+ panel.applet.resize(width, height);
+ panel.applet.validate();
+ }
+ });
+ } catch (InterruptedException e) {
+ // do nothing
+ e.printStackTrace();
+ } catch (InvocationTargetException e) {
+ // do nothing
+ e.printStackTrace();
+ }
+
+ } else if (message.startsWith("destroy")) {
+ dispose();
+ status.put(identifier, PAV_INIT_STATUS.INACTIVE);
+ } else if (message.startsWith("GetJavaObject")) {
+
+ // FIXME: how do we determine what security context this
+ // object should belong to?
+ Object o;
+
+ // Wait for panel to come alive
+ int maxWait = APPLET_TIMEOUT; // wait for panel to come alive
+ int wait = 0;
+ while ((panel == null) || (!((NetxPanel) panel).isAlive() && wait < maxWait)) {
+ try {
+ Thread.sleep(50);
+ wait += 50;
+ } catch (InterruptedException ie) {
+ // just wait
+ }
+ }
+
+ // Wait for the panel to initialize
+ // (happens in a separate thread)
+ while (panel.getApplet() == null &&
+ ((NetxPanel) panel).isAlive()) {
+ try {
+ Thread.sleep(50);
+ PluginDebug.debug("Waiting for applet to initialize...");
+ } catch (InterruptedException ie) {
+ // just wait
+ }
+ }
+
+ PluginDebug.debug(panel + " -- " + panel.getApplet() + " -- " + ((NetxPanel) panel).isAlive());
+
+ // Still null?
+ if (panel.getApplet() == null) {
+ this.streamhandler.write("instance " + identifier + " reference " + -1 + " fatalError " + "Initialization failed");
+ return;
+ }
+
+ o = panel.getApplet();
+ PluginDebug.debug ("Looking for object " + o + " panel is " + panel);
+ AppletSecurityContextManager.getSecurityContext(0).store(o);
+ PluginDebug.debug ("WRITING 1: " + "context 0 reference " + reference + " GetJavaObject "
+ + AppletSecurityContextManager.getSecurityContext(0).getIdentifier(o));
+ streamhandler.write("context 0 reference " + reference + " GetJavaObject "
+ + AppletSecurityContextManager.getSecurityContext(0).getIdentifier(o));
+ PluginDebug.debug ("WRITING 1 DONE");
+ }
+ }
+
+ // FIXME: Kind of hackish way to ensure synchronized re-drawing
+ private synchronized void forceredraw() {
+ doLayout();
+ }
+
+ /*
+ * Methods for java.applet.AppletContext
+ */
+
+ private static Map audioClips = new HashMap();
+
+ /**
+ * Get an audio clip.
+ */
+ public AudioClip getAudioClip(URL url) {
+ checkConnect(url);
+ synchronized (audioClips) {
+ AudioClip clip = (AudioClip)audioClips.get(url);
+ if (clip == null) {
+ audioClips.put(url, clip = new AppletAudioClip(url));
+ }
+ return clip;
+ }
+ }
+
+ private static Map imageRefs = new HashMap();
+
+ /**
+ * Get an image.
+ */
+ public Image getImage(URL url) {
+ return getCachedImage(url);
+ }
+
+ private Image getCachedImage(URL url) {
+ // System.getSecurityManager().checkConnection(url.getHost(), url.getPort());
+ return (Image)getCachedImageRef(url).get();
+ }
+
+ /**
+ * Get an image ref.
+ */
+ private synchronized Ref getCachedImageRef(URL url) {
+ PluginDebug.debug("getCachedImageRef() searching for " + url);
+
+ try {
+
+ String originalURL = url.toString();
+ String codeBase = panel.getCodeBase().toString();
+
+ if (originalURL.startsWith(codeBase)) {
+
+ PluginDebug.debug("getCachedImageRef() got URL = " + url);
+ PluginDebug.debug("getCachedImageRef() plugin codebase = " + codeBase);
+
+ // try to fetch it locally
+ if (panel instanceof NetxPanel) {
+
+ URL localURL = null;
+
+ String resourceName = originalURL.substring(codeBase.length());
+ JNLPClassLoader loader = (JNLPClassLoader) ((NetxPanel) panel).getAppletClassLoader();
+
+ if (loader.resourceAvailableLocally(resourceName))
+ localURL = loader.getResource(resourceName);
+
+ url = localURL != null ? localURL : url;
+ }
+ }
+
+ PluginDebug.debug("getCachedImageRef() getting img from URL = " + url);
+
+ synchronized (imageRefs) {
+ AppletImageRef ref = (AppletImageRef)imageRefs.get(url);
+ if (ref == null) {
+ ref = new AppletImageRef(url);
+ imageRefs.put(url, ref);
+ }
+ return ref;
+ }
+ } catch (Exception e) {
+ System.err.println("Error occurred when trying to fetch image:");
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ /**
+ * Flush the image cache.
+ */
+ static void flushImageCache() {
+ imageRefs.clear();
+ }
+
+ static Vector appletPanels = new Vector();
+
+ /**
+ * Get an applet by name.
+ */
+ public Applet getApplet(String name) {
+ name = name.toLowerCase();
+ SocketPermission panelSp =
+ new SocketPermission(panel.getCodeBase().getHost(), "connect");
+ for (Enumeration e = appletPanels.elements() ; e.hasMoreElements() ;) {
+ AppletPanel p = (AppletPanel)e.nextElement();
+ String param = p.getParameter("name");
+ if (param != null) {
+ param = param.toLowerCase();
+ }
+ if (name.equals(param) &&
+ p.getDocumentBase().equals(panel.getDocumentBase())) {
+
+ SocketPermission sp =
+ new SocketPermission(p.getCodeBase().getHost(), "connect");
+
+ if (panelSp.implies(sp)) {
+ return p.applet;
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Return an enumeration of all the accessible
+ * applets on this page.
+ */
+ public Enumeration getApplets() {
+ Vector v = new Vector();
+ SocketPermission panelSp =
+ new SocketPermission(panel.getCodeBase().getHost(), "connect");
+
+ for (Enumeration e = appletPanels.elements() ; e.hasMoreElements() ;) {
+ AppletPanel p = (AppletPanel)e.nextElement();
+ if (p.getDocumentBase().equals(panel.getDocumentBase())) {
+
+ SocketPermission sp =
+ new SocketPermission(p.getCodeBase().getHost(), "connect");
+ if (panelSp.implies(sp)) {
+ v.addElement(p.applet);
+ }
+ }
+ }
+ return v.elements();
+ }
+
+ /**
+ * Ignore.
+ */
+ public void showDocument(URL url) {
+ PluginDebug.debug("Showing document...");
+ showDocument(url, "_self");
+ }
+
+ /**
+ * Ignore.
+ */
+ public void showDocument(URL url, String target) {
+ try {
+ // FIXME: change to postCallRequest
+ write("url " + UrlUtil.encode(url.toString(), "UTF-8") + " " + target);
+ } catch (IOException exception) {
+ // Deliberately ignore IOException. showDocument may be
+ // called from threads other than the main thread after
+ // streamhandler.pluginOutputStream has been closed.
+ }
+ }
+
+ /**
+ * Show status.
+ */
+ public void showStatus(String status) {
+ try {
+ // FIXME: change to postCallRequest
+ // For statuses, we cannot have a newline
+ status = status.replace("\n", " ");
+ write("status " + status);
+ } catch (IOException exception) {
+ // Deliberately ignore IOException. showStatus may be
+ // called from threads other than the main thread after
+ // streamhandler.pluginOutputStream has been closed.
+ }
+ }
+
+ /**
+ * Returns an incremental number (unique identifier) for a message.
+ * If identifier hits Long.MAX_VALUE it loops back starting at 0.
+ *
+ * @return A unique Long identifier for the request
+ */
+ private static Long getRequestIdentifier() {
+ synchronized (requestIdentityCounter) {
+
+ if (requestIdentityCounter == Long.MAX_VALUE)
+ requestIdentityCounter = 0L;
+
+ return requestIdentityCounter++;
+ }
+ }
+
+ public long getWindow() {
+ PluginDebug.debug ("STARTING getWindow");
+ Long reference = getRequestIdentifier();
+
+ PluginCallRequest request = requestFactory.getPluginCallRequest("window",
+ "instance " + identifier + " reference " +
+ + reference + " " + "GetWindow", reference);
+
+ PluginDebug.debug ("STARTING postCallRequest");
+ streamhandler.postCallRequest(request);
+ PluginDebug.debug ("STARTING postCallRequest done");
+ streamhandler.write(request.getMessage());
+ try {
+ PluginDebug.debug ("wait request 1");
+ synchronized(request) {
+ PluginDebug.debug ("wait request 2");
+ while ((Long) request.getObject() == 0)
+ request.wait();
+ PluginDebug.debug ("wait request 3");
+ }
+ } catch (InterruptedException e) {
+ throw new RuntimeException("Interrupted waiting for call request.",
+ e);
+ }
+
+ PluginDebug.debug ("STARTING getWindow DONE");
+ return (Long) request.getObject();
+ }
+
+ // FIXME: make private, access via reflection.
+ public static Object getMember(long internal, String name)
+ {
+ AppletSecurityContextManager.getSecurityContext(0).store(name);
+ int nameID = AppletSecurityContextManager.getSecurityContext(0).getIdentifier(name);
+ Long reference = getRequestIdentifier();
+
+ // Prefix with dummy instance for convenience.
+ PluginCallRequest request = requestFactory.getPluginCallRequest("member",
+ "instance " + 0 + " reference " + reference + " GetMember " +
+ internal + " " + nameID, reference);
+
+ streamhandler.postCallRequest(request);
+ streamhandler.write(request.getMessage());
+ try {
+ PluginDebug.debug ("wait getMEM request 1");
+ synchronized(request) {
+ PluginDebug.debug ("wait getMEM request 2");
+ while (request.isDone() == false)
+ request.wait();
+ PluginDebug.debug ("wait getMEM request 3 GOT: " + request.getObject().getClass());
+ }
+ } catch (InterruptedException e) {
+ throw new RuntimeException("Interrupted waiting for call request.",
+ e);
+ }
+ PluginDebug.debug (" getMember DONE");
+ return request.getObject();
+ }
+
+ public static void setMember(long internal, String name, Object value) {
+ System.err.println("Setting to class " + value.getClass() + ":" + value.getClass().isPrimitive());
+ AppletSecurityContextManager.getSecurityContext(0).store(name);
+ int nameID = AppletSecurityContextManager.getSecurityContext(0).getIdentifier(name);
+ Long reference = getRequestIdentifier();
+
+ // work on a copy of value, as we don't want to be manipulating
+ // complex objects
+ String valueToSetTo;
+ if (value instanceof java.lang.Byte ||
+ value instanceof java.lang.Character ||
+ value instanceof java.lang.Short ||
+ value instanceof java.lang.Integer ||
+ value instanceof java.lang.Long ||
+ value instanceof java.lang.Float ||
+ value instanceof java.lang.Double ||
+ value instanceof java.lang.Boolean) {
+
+ valueToSetTo = "literalreturn " + value.toString();
+
+ // Character -> Str results in str value.. we need int value as
+ // per specs.
+ if (value instanceof java.lang.Character) {
+ valueToSetTo = "literalreturn " + (int) ((java.lang.Character) value).charValue();
+ } else if (value instanceof Float ||
+ value instanceof Double) {
+ valueToSetTo = "literalreturn " + String.format("%308.308e", value);
+ }
+
+ } else {
+ AppletSecurityContextManager.getSecurityContext(0).store(value);
+ valueToSetTo = Integer.toString(AppletSecurityContextManager.getSecurityContext(0).getIdentifier(value));
+ }
+
+ // Prefix with dummy instance for convenience.
+ PluginCallRequest request = requestFactory.getPluginCallRequest("void",
+ "instance " + 0 + " reference " + reference + " SetMember " +
+ internal + " " + nameID + " " + valueToSetTo, reference);
+
+ streamhandler.postCallRequest(request);
+ streamhandler.write(request.getMessage());
+ try {
+ PluginDebug.debug ("wait setMem request: " + request.getMessage());
+ PluginDebug.debug ("wait setMem request 1");
+ synchronized(request) {
+ PluginDebug.debug ("wait setMem request 2");
+ while (request.isDone() == false)
+ request.wait();
+ PluginDebug.debug ("wait setMem request 3");
+ }
+ } catch (InterruptedException e) {
+ throw new RuntimeException("Interrupted waiting for call request.",
+ e);
+ }
+ PluginDebug.debug (" setMember DONE");
+ }
+
+ // FIXME: handle long index as well.
+ public static void setSlot(long internal, int index, Object value) {
+ AppletSecurityContextManager.getSecurityContext(0).store(value);
+ Long reference = getRequestIdentifier();
+
+ // work on a copy of value, as we don't want to be manipulating
+ // complex objects
+ String valueToSetTo;
+ if (value instanceof java.lang.Byte ||
+ value instanceof java.lang.Character ||
+ value instanceof java.lang.Short ||
+ value instanceof java.lang.Integer ||
+ value instanceof java.lang.Long ||
+ value instanceof java.lang.Float ||
+ value instanceof java.lang.Double ||
+ value instanceof java.lang.Boolean) {
+
+ valueToSetTo = "literalreturn " + value.toString();
+
+ // Character -> Str results in str value.. we need int value as
+ // per specs.
+ if (value instanceof java.lang.Character) {
+ valueToSetTo = "literalreturn " + (int) ((java.lang.Character) value).charValue();
+ } else if (value instanceof Float ||
+ value instanceof Double) {
+ valueToSetTo = "literalreturn " + String.format("%308.308e", value);
+ }
+
+ } else {
+ AppletSecurityContextManager.getSecurityContext(0).store(value);
+ valueToSetTo = Integer.toString(AppletSecurityContextManager.getSecurityContext(0).getIdentifier(value));
+ }
+
+ // Prefix with dummy instance for convenience.
+ PluginCallRequest request = requestFactory.getPluginCallRequest("void",
+ "instance " + 0 + " reference " + reference + " SetSlot " +
+ internal + " " + index + " " + valueToSetTo, reference);
+
+ streamhandler.postCallRequest(request);
+ streamhandler.write(request.getMessage());
+ try {
+ PluginDebug.debug ("wait setSlot request 1");
+ synchronized(request) {
+ PluginDebug.debug ("wait setSlot request 2");
+ while (request.isDone() == false)
+ request.wait();
+ PluginDebug.debug ("wait setSlot request 3");
+ }
+ } catch (InterruptedException e) {
+ throw new RuntimeException("Interrupted waiting for call request.",
+ e);
+ }
+ PluginDebug.debug (" setSlot DONE");
+ }
+
+ public static Object getSlot(long internal, int index)
+ {
+ Long reference = getRequestIdentifier();
+
+ // Prefix with dummy instance for convenience.
+ PluginCallRequest request = requestFactory.getPluginCallRequest("member",
+ "instance " + 0 + " reference " + reference + " GetSlot " +
+ internal + " " + index, reference);
+ streamhandler.postCallRequest(request);
+ streamhandler.write(request.getMessage());
+ try {
+ PluginDebug.debug ("wait getSlot request 1");
+ synchronized(request) {
+ PluginDebug.debug ("wait getSlot request 2");
+ while (request.isDone() == false)
+ request.wait();
+ PluginDebug.debug ("wait getSlot request 3");
+ }
+ } catch (InterruptedException e) {
+ throw new RuntimeException("Interrupted waiting for call request.",
+ e);
+ }
+ PluginDebug.debug (" getSlot DONE");
+ return request.getObject();
+ }
+
+ public static Object eval(long internal, String s)
+ {
+ AppletSecurityContextManager.getSecurityContext(0).store(s);
+ int stringID = AppletSecurityContextManager.getSecurityContext(0).getIdentifier(s);
+ Long reference = getRequestIdentifier();
+
+ // Prefix with dummy instance for convenience.
+ // FIXME: rename GetMemberPluginCallRequest ObjectPluginCallRequest.
+ PluginCallRequest request = requestFactory.getPluginCallRequest("member",
+ "instance " + 0 + " reference " + reference + " Eval " +
+ internal + " " + stringID, reference);
+ streamhandler.postCallRequest(request);
+ streamhandler.write(request.getMessage());
+ try {
+ PluginDebug.debug ("wait eval request 1");
+ synchronized(request) {
+ PluginDebug.debug ("wait eval request 2");
+ while (request.isDone() == false)
+ request.wait();
+ PluginDebug.debug ("wait eval request 3");
+ }
+ } catch (InterruptedException e) {
+ throw new RuntimeException("Interrupted waiting for call request.",
+ e);
+ }
+ PluginDebug.debug (" getSlot DONE");
+ return request.getObject();
+ }
+
+ public static void removeMember (long internal, String name) {
+ AppletSecurityContextManager.getSecurityContext(0).store(name);
+ int nameID = AppletSecurityContextManager.getSecurityContext(0).getIdentifier(name);
+ Long reference = getRequestIdentifier();
+
+ // Prefix with dummy instance for convenience.
+ PluginCallRequest request = requestFactory.getPluginCallRequest("void",
+ "instance " + 0 + " reference " + reference + " RemoveMember " +
+ internal + " " + nameID, reference);
+
+ streamhandler.postCallRequest(request);
+ streamhandler.write(request.getMessage());
+ try {
+ PluginDebug.debug ("wait removeMember request 1");
+ synchronized(request) {
+ PluginDebug.debug ("wait removeMember request 2");
+ while (request.isDone() == false)
+ request.wait();
+ PluginDebug.debug ("wait removeMember request 3");
+ }
+ } catch (InterruptedException e) {
+ throw new RuntimeException("Interrupted waiting for call request.",
+ e);
+ }
+ PluginDebug.debug (" RemoveMember DONE");
+ }
+
+ public static Object call(long internal, String name, Object args[])
+ {
+ // FIXME: when is this removed from the object store?
+ // FIXME: reference should return the ID.
+ // FIXME: convenience method for this long line.
+ AppletSecurityContextManager.getSecurityContext(0).store(name);
+ int nameID = AppletSecurityContextManager.getSecurityContext(0).getIdentifier(name);
+ Long reference = getRequestIdentifier();
+
+ String argIDs = "";
+ for (Object arg : args)
+ {
+ AppletSecurityContextManager.getSecurityContext(0).store(arg);
+ argIDs += AppletSecurityContextManager.getSecurityContext(0).getIdentifier(arg) + " ";
+ }
+ argIDs = argIDs.trim();
+
+ // Prefix with dummy instance for convenience.
+ PluginCallRequest request = requestFactory.getPluginCallRequest("member",
+ "instance " + 0 + " reference " + reference + " Call " +
+ internal + " " + nameID + " " + argIDs, reference);
+
+ streamhandler.postCallRequest(request);
+ streamhandler.write(request.getMessage());
+ try {
+ PluginDebug.debug ("wait call request 1");
+ synchronized(request) {
+ PluginDebug.debug ("wait call request 2");
+ while (request.isDone() == false)
+ request.wait();
+ PluginDebug.debug ("wait call request 3");
+ }
+ } catch (InterruptedException e) {
+ throw new RuntimeException("Interrupted waiting for call request.",
+ e);
+ }
+ PluginDebug.debug (" Call DONE");
+ return request.getObject();
+ }
+
+ public static Object requestPluginCookieInfo(URI uri) {
+
+ PluginCallRequest request;
+ Long reference = getRequestIdentifier();
+
+ try
+ {
+ String encodedURI = UrlUtil.encode(uri.toString(), "UTF-8");
+ request = requestFactory.getPluginCallRequest("cookieinfo",
+ "plugin PluginCookieInfo " + "reference " + reference +
+ " " + encodedURI, reference);
+
+ } catch (UnsupportedEncodingException e)
+ {
+ e.printStackTrace();
+ return null;
+ }
+
+ PluginMessageConsumer.registerPriorityWait(reference);
+ streamhandler.postCallRequest(request);
+ streamhandler.write(request.getMessage());
+ try {
+ PluginDebug.debug ("wait cookieinfo request 1");
+ synchronized(request) {
+ PluginDebug.debug ("wait cookieinfo request 2");
+ while (request.isDone() == false)
+ request.wait();
+ PluginDebug.debug ("wait cookieinfo request 3");
+ }
+ } catch (InterruptedException e) {
+ throw new RuntimeException("Interrupted waiting for cookieinfo request.",
+ e);
+ }
+ PluginDebug.debug (" Cookieinfo DONE");
+ return request.getObject();
+ }
+
+ public static Object requestPluginProxyInfo(URI uri) {
+
+ String requestURI = null;
+ Long reference = getRequestIdentifier();
+
+ try {
+
+ // there is no easy way to get SOCKS proxy info. So, we tell mozilla that we want proxy for
+ // an HTTP uri in case of non http/ftp protocols. If we get back a SOCKS proxy, we can
+ // use that, if we get back an http proxy, we fallback to DIRECT connect
+
+ String scheme = uri.getScheme();
+ String port = uri.getPort() != -1 ? ":" + uri.getPort() : "";
+ if (!uri.getScheme().startsWith("http") && !uri.getScheme().equals("ftp"))
+ scheme = "http";
+
+ requestURI = UrlUtil.encode(scheme + "://" + uri.getHost() + port + "/" + uri.getPath(), "UTF-8");
+ } catch (Exception e) {
+ PluginDebug.debug("Cannot construct URL from " + uri.toString() + " ... falling back to DIRECT proxy");
+ e.printStackTrace();
+ return null;
+ }
+
+ PluginCallRequest request = requestFactory.getPluginCallRequest("proxyinfo",
+ "plugin PluginProxyInfo reference " + reference + " " +
+ requestURI, reference);
+
+ PluginMessageConsumer.registerPriorityWait(reference);
+ streamhandler.postCallRequest(request);
+ streamhandler.write(request.getMessage());
+ try {
+ PluginDebug.debug ("wait call request 1");
+ synchronized(request) {
+ PluginDebug.debug ("wait call request 2");
+ while (request.isDone() == false)
+ request.wait();
+ PluginDebug.debug ("wait call request 3");
+ }
+ } catch (InterruptedException e) {
+ throw new RuntimeException("Interrupted waiting for call request.",
+ e);
+ }
+ PluginDebug.debug (" Call DONE");
+ return request.getObject();
+ }
+
+ public static void JavaScriptFinalize(long internal)
+ {
+ Long reference = getRequestIdentifier();
+
+ // Prefix with dummy instance for convenience.
+ PluginCallRequest request = requestFactory.getPluginCallRequest("void",
+ "instance " + 0 + " reference " + reference + " Finalize " +
+ internal, reference);
+
+ streamhandler.postCallRequest(request);
+ streamhandler.write(request.getMessage());
+ try {
+ PluginDebug.debug ("wait finalize request 1");
+ synchronized(request) {
+ PluginDebug.debug ("wait finalize request 2");
+ while (request.isDone() == false)
+ request.wait();
+ PluginDebug.debug ("wait finalize request 3");
+ }
+ } catch (InterruptedException e) {
+ throw new RuntimeException("Interrupted waiting for call request.",
+ e);
+ }
+ PluginDebug.debug (" finalize DONE");
+ }
+
+ public static String javascriptToString(long internal)
+ {
+ Long reference = getRequestIdentifier();
+
+ // Prefix with dummy instance for convenience.
+ PluginCallRequest request = requestFactory.getPluginCallRequest("member",
+ "instance " + 0 + " reference " + reference + " ToString " +
+ internal, reference);
+
+ streamhandler.postCallRequest(request);
+ streamhandler.write(request.getMessage());
+ try {
+ PluginDebug.debug ("wait ToString request 1");
+ synchronized(request) {
+ PluginDebug.debug ("wait ToString request 2");
+ while (request.isDone() == false)
+ request.wait();
+ PluginDebug.debug ("wait ToString request 3");
+ }
+ } catch (InterruptedException e) {
+ throw new RuntimeException("Interrupted waiting for call request.",
+ e);
+ }
+ PluginDebug.debug (" ToString DONE");
+ return (String) request.getObject();
+ }
+
+ // FIXME: make this private and access it from JSObject using
+ // reflection.
+ private void write(String message) throws IOException {
+ PluginDebug.debug ("WRITING 2: " + "instance " + identifier + " " + message);
+ streamhandler.write("instance " + identifier + " " + message);
+ PluginDebug.debug ("WRITING 2 DONE");
+ }
+
+ public void setStream(String key, InputStream stream)throws IOException{
+ // We do nothing.
+ }
+
+ public InputStream getStream(String key){
+ // We do nothing.
+ return null;
+ }
+
+ public Iterator getStreamKeys(){
+ // We do nothing.
+ return null;
+ }
+
+ /**
+ * System parameters.
+ */
+ static Hashtable systemParam = new Hashtable();
+
+ static {
+ systemParam.put("codebase", "codebase");
+ systemParam.put("code", "code");
+ systemParam.put("alt", "alt");
+ systemParam.put("width", "width");
+ systemParam.put("height", "height");
+ systemParam.put("align", "align");
+ systemParam.put("vspace", "vspace");
+ systemParam.put("hspace", "hspace");
+ }
+
+ /**
+ * Print the HTML tag.
+ */
+ public static void printTag(PrintStream out, Hashtable atts) {
+ out.print("<applet");
+
+ String v = (String)atts.get("codebase");
+ if (v != null) {
+ out.print(" codebase=\"" + v + "\"");
+ }
+
+ v = (String)atts.get("code");
+ if (v == null) {
+ v = "applet.class";
+ }
+ out.print(" code=\"" + v + "\"");
+ v = (String)atts.get("width");
+ if (v == null) {
+ v = "150";
+ }
+ out.print(" width=" + v);
+
+ v = (String)atts.get("height");
+ if (v == null) {
+ v = "100";
+ }
+ out.print(" height=" + v);
+
+ v = (String)atts.get("name");
+ if (v != null) {
+ out.print(" name=\"" + v + "\"");
+ }
+ out.println(">");
+
+ // A very slow sorting algorithm
+ int len = atts.size();
+ String params[] = new String[len];
+ len = 0;
+ for (Enumeration e = atts.keys() ; e.hasMoreElements() ;) {
+ String param = (String)e.nextElement();
+ int i = 0;
+ for (; i < len ; i++) {
+ if (params[i].compareTo(param) >= 0) {
+ break;
+ }
+ }
+ System.arraycopy(params, i, params, i + 1, len - i);
+ params[i] = param;
+ len++;
+ }
+
+ for (int i = 0 ; i < len ; i++) {
+ String param = params[i];
+ if (systemParam.get(param) == null) {
+ out.println("<param name=" + param +
+ " value=\"" + atts.get(param) + "\">");
+ }
+ }
+ out.println("</applet>");
+ }
+
+ /**
+ * Make sure the atrributes are uptodate.
+ */
+ public void updateAtts() {
+ Dimension d = panel.size();
+ Insets in = panel.insets();
+ panel.atts.put("width",
+ new Integer(d.width - (in.left + in.right)).toString());
+ panel.atts.put("height",
+ new Integer(d.height - (in.top + in.bottom)).toString());
+ }
+
+ /**
+ * Restart the applet.
+ */
+ void appletRestart() {
+ panel.sendEvent(AppletPanel.APPLET_STOP);
+ panel.sendEvent(AppletPanel.APPLET_DESTROY);
+ panel.sendEvent(AppletPanel.APPLET_INIT);
+ panel.sendEvent(AppletPanel.APPLET_START);
+ }
+
+ /**
+ * Reload the applet.
+ */
+ void appletReload() {
+ panel.sendEvent(AppletPanel.APPLET_STOP);
+ panel.sendEvent(AppletPanel.APPLET_DESTROY);
+ panel.sendEvent(AppletPanel.APPLET_DISPOSE);
+
+ /**
+ * Fixed #4501142: Classlaoder sharing policy doesn't
+ * take "archive" into account. This will be overridden
+ * by Java Plug-in. [stanleyh]
+ */
+ AppletPanel.flushClassLoader(panel.getClassLoaderCacheKey());
+
+ /*
+ * Make sure we don't have two threads running through the event queue
+ * at the same time.
+ */
+ try {
+ panel.joinAppletThread();
+ panel.release();
+ } catch (InterruptedException e) {
+ return; // abort the reload
+ }
+
+ AccessController.doPrivileged(new PrivilegedAction() {
+ public Object run() {
+ panel.createAppletThread();
+ return null;
+ }
+ });
+
+ panel.sendEvent(AppletPanel.APPLET_LOAD);
+ panel.sendEvent(AppletPanel.APPLET_INIT);
+ panel.sendEvent(AppletPanel.APPLET_START);
+ }
+
+ public int print(Graphics graphics, PageFormat pf, int pageIndex) {
+ return Printable.NO_SUCH_PAGE;
+ }
+
+ /**
+ * Start the applet.
+ */
+ void appletStart() {
+ panel.sendEvent(AppletPanel.APPLET_START);
+ }
+
+ /**
+ * Stop the applet.
+ */
+ void appletStop() {
+ panel.sendEvent(AppletPanel.APPLET_STOP);
+ }
+
+ /**
+ * Shutdown a viewer.
+ * Stop, Destroy, Dispose and Quit a viewer
+ */
+ private void appletShutdown(AppletPanel p) {
+ p.sendEvent(AppletPanel.APPLET_STOP);
+ p.sendEvent(AppletPanel.APPLET_DESTROY);
+ p.sendEvent(AppletPanel.APPLET_DISPOSE);
+ p.sendEvent(AppletPanel.APPLET_QUIT);
+ }
+
+ /**
+ * Close this viewer.
+ * Stop, Destroy, Dispose and Quit an AppletView, then
+ * reclaim resources and exit the program if this is
+ * the last applet.
+ */
+ void appletClose() {
+
+ // The caller thread is event dispatch thread, so
+ // spawn a new thread to avoid blocking the event queue
+ // when calling appletShutdown.
+ //
+ final AppletPanel p = panel;
+
+ new Thread(new Runnable()
+ {
+ public void run()
+ {
+ ThreadGroup tg = ((JNLPClassLoader) p.applet.getClass().getClassLoader()).getApplication().getThreadGroup();
+
+ appletShutdown(p);
+ appletPanels.removeElement(p);
+ dispose();
+
+ if (tg.activeCount() > 0)
+ tg.stop();
+
+ if (countApplets() == 0) {
+ appletSystemExit();
+ }
+ }
+ }).start();
+
+ status.put(identifier, PAV_INIT_STATUS.INACTIVE);
+ }
+
+ /**
+ * Exit the program.
+ * Exit from the program (if not stand alone) - do no clean-up
+ */
+ private void appletSystemExit() {
+ // Do nothing. Exit is handled by another
+ // block of code, called when _all_ applets are gone
+ }
+
+ /**
+ * How many applets are running?
+ */
+
+ public static int countApplets() {
+ return appletPanels.size();
+ }
+
+
+ /**
+ * Scan spaces.
+ */
+ public static void skipSpace(int[] c, Reader in) throws IOException {
+ while ((c[0] >= 0) &&
+ ((c[0] == ' ') || (c[0] == '\t') || (c[0] == '\n') || (c[0] == '\r'))) {
+ c[0] = in.read();
+ }
+ }
+
+ /**
+ * Scan identifier
+ */
+ public static String scanIdentifier(int[] c, Reader in) throws IOException {
+ StringBuffer buf = new StringBuffer();
+
+ if (c[0] == '!') {
+ // Technically, we should be scanning for '!--' but we are reading
+ // from a stream, and there is no way to peek ahead. That said,
+ // a ! at this point can only mean comment here afaik, so we
+ // should be okay
+ skipComment(c, in);
+ return "";
+ }
+
+ while (true) {
+ if (((c[0] >= 'a') && (c[0] <= 'z')) ||
+ ((c[0] >= 'A') && (c[0] <= 'Z')) ||
+ ((c[0] >= '0') && (c[0] <= '9')) || (c[0] == '_')) {
+ buf.append((char)c[0]);
+ c[0] = in.read();
+ } else {
+ return buf.toString();
+ }
+ }
+ }
+
+ public static void skipComment(int[] c, Reader in) throws IOException {
+ StringBuffer buf = new StringBuffer();
+ boolean commentHeaderPassed = false;
+ c[0] = in.read();
+ buf.append((char)c[0]);
+
+ while (true) {
+ if (c[0] == '-' && (c[0] = in.read()) == '-') {
+ buf.append((char)c[0]);
+ if (commentHeaderPassed) {
+ // -- encountered ... is > next?
+ if ((c[0] = in.read()) == '>') {
+ buf.append((char)c[0]);
+
+ PluginDebug.debug("Comment skipped: " + buf.toString());
+
+ // comment skipped.
+ return;
+ }
+ } else {
+ // first -- is part of <!-- ... , just mark that we have passed it
+ commentHeaderPassed = true;
+ }
+
+ } else if (commentHeaderPassed == false) {
+ buf.append((char)c[0]);
+ PluginDebug.debug("Warning: Attempted to skip comment, but this tag does not appear to be a comment: " + buf.toString());
+ return;
+ }
+
+ c[0] = in.read();
+ buf.append((char)c[0]);
+ }
+ }
+
+ /**
+ * Scan tag
+ */
+ public static Hashtable scanTag(int[] c, Reader in) throws IOException {
+ Hashtable atts = new Hashtable();
+ skipSpace(c, in);
+ while (c[0] >= 0 && c[0] != '>') {
+ String att = scanIdentifier(c, in);
+ String val = "";
+ skipSpace(c, in);
+ if (c[0] == '=') {
+ int quote = -1;
+ c[0] = in.read();
+ skipSpace(c, in);
+ if ((c[0] == '\'') || (c[0] == '\"')) {
+ quote = c[0];
+ c[0] = in.read();
+ }
+ StringBuffer buf = new StringBuffer();
+ while ((c[0] > 0) &&
+ (((quote < 0) && (c[0] != ' ') && (c[0] != '\t') &&
+ (c[0] != '\n') && (c[0] != '\r') && (c[0] != '>'))
+ || ((quote >= 0) && (c[0] != quote)))) {
+ buf.append((char)c[0]);
+ c[0] = in.read();
+ }
+ if (c[0] == quote) {
+ c[0] = in.read();
+ }
+ skipSpace(c, in);
+ val = buf.toString();
+ }
+
+ att = att.replace("&gt;", ">");
+ att = att.replace("&lt;", "<");
+ att = att.replace("&amp;", "&");
+ att = att.replace("&#10;", "\n");
+ att = att.replace("&#13;", "\r");
+
+ val = val.replace("&gt;", ">");
+ val = val.replace("&lt;", "<");
+ val = val.replace("&amp;", "&");
+ val = val.replace("&#10;", "\n");
+ val = val.replace("&#13;", "\r");
+
+ PluginDebug.debug("PUT " + att + " = '" + val + "'");
+ atts.put(att.toLowerCase(java.util.Locale.ENGLISH), val);
+
+ while (true) {
+ if ((c[0] == '>') || (c[0] < 0) ||
+ ((c[0] >= 'a') && (c[0] <= 'z')) ||
+ ((c[0] >= 'A') && (c[0] <= 'Z')) ||
+ ((c[0] >= '0') && (c[0] <= '9')) || (c[0] == '_'))
+ break;
+ c[0] = in.read();
+ }
+ //skipSpace(in);
+ }
+ return atts;
+ }
+
+ // private static final == inline
+ private static final boolean isInt(Object o) {
+ boolean isInt = false;
+
+ try {
+ Integer.parseInt((String) o);
+ isInt = true;
+ } catch (Exception e) {
+ // don't care
+ }
+
+ return isInt;
+ }
+
+ /* values used for placement of AppletViewer's frames */
+ private static int x = 0;
+ private static int y = 0;
+ private static final int XDELTA = 30;
+ private static final int YDELTA = XDELTA;
+
+ static String encoding = null;
+
+ static private Reader makeReader(InputStream is) {
+ if (encoding != null) {
+ try {
+ return new BufferedReader(new InputStreamReader(is, encoding));
+ } catch (IOException x) { }
+ }
+ InputStreamReader r = new InputStreamReader(is);
+ encoding = r.getEncoding();
+ return new BufferedReader(r);
+ }
+
+ /**
+ * Scan an html file for <applet> tags
+ */
+ public static void parse(int identifier, long handle, String width, String height, Reader in, URL url, String enc)
+ throws IOException {
+ encoding = enc;
+ parse(identifier, handle, width, height, in, url, System.out, new PluginAppletPanelFactory());
+ }
+
+ public static void parse(int identifier, long handle, String width, String height, Reader in, URL url)
+ throws IOException {
+
+ final int fIdentifier = identifier;
+ final long fHandle = handle;
+ final String fWidth = width;
+ final String fHeight = height;
+ final Reader fIn = in;
+ final URL fUrl = url;
+ PrivilegedAction pa = new PrivilegedAction() {
+ public Object run() {
+ try {
+ parse(fIdentifier, fHandle, fWidth, fHeight, fIn, fUrl, System.out, new PluginAppletPanelFactory());
+ } catch (IOException ioe) {
+ return ioe;
+ }
+
+ return null;
+ }
+ };
+
+ Object ret = AccessController.doPrivileged(pa);
+ if (ret instanceof IOException) {
+ throw (IOException) ret;
+ }
+ }
+
+ public static void parse(int identifier, long handle, String width,
+ String height, Reader in, URL url,
+ PrintStream statusMsgStream,
+ PluginAppletPanelFactory factory)
+ throws IOException
+ {
+ // <OBJECT> <EMBED> tag flags
+ boolean isAppletTag = false;
+ boolean isObjectTag = false;
+ boolean isEmbedTag = false;
+ boolean objectTagAlreadyParsed = false;
+ // The current character
+ // FIXME: This is an evil hack to force pass-by-reference.. the
+ // parsing code needs to be rewritten from scratch to prevent such
+ //a need
+ int[] c = new int[1];
+
+ // warning messages
+ String requiresNameWarning = amh.getMessage("parse.warning.requiresname");
+ String paramOutsideWarning = amh.getMessage("parse.warning.paramoutside");
+ String appletRequiresCodeWarning = amh.getMessage("parse.warning.applet.requirescode");
+ String appletRequiresHeightWarning = amh.getMessage("parse.warning.applet.requiresheight");
+ String appletRequiresWidthWarning = amh.getMessage("parse.warning.applet.requireswidth");
+ String objectRequiresCodeWarning = amh.getMessage("parse.warning.object.requirescode");
+ String objectRequiresHeightWarning = amh.getMessage("parse.warning.object.requiresheight");
+ String objectRequiresWidthWarning = amh.getMessage("parse.warning.object.requireswidth");
+ String embedRequiresCodeWarning = amh.getMessage("parse.warning.embed.requirescode");
+ String embedRequiresHeightWarning = amh.getMessage("parse.warning.embed.requiresheight");
+ String embedRequiresWidthWarning = amh.getMessage("parse.warning.embed.requireswidth");
+ String appNotLongerSupportedWarning = amh.getMessage("parse.warning.appnotLongersupported");
+
+ java.net.URLConnection conn = url.openConnection();
+ /* The original URL may have been redirected - this
+ * sets it to whatever URL/codebase we ended up getting
+ */
+ url = conn.getURL();
+
+ int ydisp = 1;
+ Hashtable atts = null;
+
+ while(true) {
+ c[0] = in.read();
+ if (c[0] == -1)
+ break;
+
+ if (c[0] == '<') {
+ c[0] = in.read();
+ if (c[0] == '/') {
+ c[0] = in.read();
+ String nm = scanIdentifier(c, in);
+ if (nm.equalsIgnoreCase("applet") ||
+ nm.equalsIgnoreCase("object") ||
+ nm.equalsIgnoreCase("embed")) {
+
+ // We can't test for a code tag until </OBJECT>
+ // because it is a parameter, not an attribute.
+ if(isObjectTag) {
+ if (atts.get("code") == null && atts.get("object") == null) {
+ statusMsgStream.println(objectRequiresCodeWarning);
+ atts = null;
+ }
+ }
+
+ if (atts != null) {
+ // XXX 5/18 In general this code just simply
+ // shouldn't be part of parsing. It's presence
+ // causes things to be a little too much of a
+ // hack.
+
+ // Let user know we are starting up
+ streamhandler.write("instance " + identifier + " status " + amh.getMessage("status.start"));
+ factory.createPanel(streamhandler, identifier, handle, x, y, url, atts);
+
+ x += XDELTA;
+ y += YDELTA;
+ // make sure we don't go too far!
+ Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
+ if ((x > d.width - 300) || (y > d.height - 300)) {
+ x = 0;
+ y = 2 * ydisp * YDELTA;
+ ydisp++;
+ }
+ }
+ atts = null;
+ isAppletTag = false;
+ isObjectTag = false;
+ isEmbedTag = false;
+ }
+ }
+ else {
+ String nm = scanIdentifier(c, in);
+ if (nm.equalsIgnoreCase("param")) {
+ Hashtable t = scanTag(c, in);
+ String att = (String)t.get("name");
+
+ if (atts.containsKey(att))
+ continue;
+
+ if (att == null) {
+ statusMsgStream.println(requiresNameWarning);
+ } else {
+ String val = (String)t.get("value");
+ if (val == null) {
+ statusMsgStream.println(requiresNameWarning);
+ } else if (atts != null) {
+ att = att.replace("&gt;", ">");
+ att = att.replace("&lt;", "<");
+ att = att.replace("&amp;", "&");
+ att = att.replace("&#10;", "\n");
+ att = att.replace("&#13;", "\r");
+ att = att.replace("&quot;", "\"");
+
+ val = val.replace("&gt;", ">");
+ val = val.replace("&lt;", "<");
+ val = val.replace("&amp;", "&");
+ val = val.replace("&#10;", "\n");
+ val = val.replace("&#13;", "\r");
+ val = val.replace("&quot;", "\"");
+ PluginDebug.debug("PUT " + att + " = " + val);
+ atts.put(att.toLowerCase(), val);
+ } else {
+ statusMsgStream.println(paramOutsideWarning);
+ }
+ }
+ }
+ else if (nm.equalsIgnoreCase("applet")) {
+ isAppletTag = true;
+ atts = scanTag(c, in);
+
+ // If there is a classid and no code tag present, transform it to code tag
+ if (atts.get("code") == null && atts.get("classid") != null && !((String) atts.get("classid")).startsWith("clsid:")) {
+ atts.put("code", atts.get("classid"));
+ }
+
+ // remove java: from code tag
+ if (atts.get("code") != null && ((String) atts.get("code")).startsWith("java:")) {
+ atts.put("code", ((String) atts.get("code")).substring(5));
+ }
+
+ if (atts.get("code") == null && atts.get("object") == null) {
+ statusMsgStream.println(appletRequiresCodeWarning);
+ atts = null;
+ }
+
+ if (atts.get("width") == null || !isInt(atts.get("width"))) {
+ atts.put("width", width);
+ }
+
+ if (atts.get("height") == null || !isInt(atts.get("height"))) {
+ atts.put("height", height);
+ }
+ }
+ else if (nm.equalsIgnoreCase("object")) {
+ isObjectTag = true;
+
+ // Once code is set, additional nested objects are ignored
+ if (!objectTagAlreadyParsed) {
+ objectTagAlreadyParsed = true;
+ atts = scanTag(c, in);
+ }
+
+ // If there is a classid and no code tag present, transform it to code tag
+ if (atts.get("code") == null && atts.get("classid") != null && !((String) atts.get("classid")).startsWith("clsid:")) {
+ atts.put("code", atts.get("classid"));
+ }
+
+ // remove java: from code tag
+ if (atts.get("code") != null && ((String) atts.get("code")).startsWith("java:")) {
+ atts.put("code", ((String) atts.get("code")).substring(5));
+ }
+
+ // java_* aliases override older names:
+ // http://java.sun.com/j2se/1.4.2/docs/guide/plugin/developer_guide/using_tags.html#in-ie
+ if (atts.get("java_code") != null) {
+ atts.put("code", ((String) atts.get("java_code")));
+ }
+
+ if (atts.containsKey("code")) {
+ objectTagAlreadyParsed = true;
+ }
+
+ if (atts.get("java_codebase") != null) {
+ atts.put("codebase", ((String) atts.get("java_codebase")));
+ }
+
+ if (atts.get("java_archive") != null) {
+ atts.put("archive", ((String) atts.get("java_archive")));
+ }
+
+ if (atts.get("java_object") != null) {
+ atts.put("object", ((String) atts.get("java_object")));
+ }
+
+ if (atts.get("java_type") != null) {
+ atts.put("type", ((String) atts.get("java_type")));
+ }
+
+ if (atts.get("width") == null || !isInt(atts.get("width"))) {
+ atts.put("width", width);
+ }
+
+ if (atts.get("height") == null || !isInt(atts.get("height"))) {
+ atts.put("height", height);
+ }
+ }
+ else if (nm.equalsIgnoreCase("embed")) {
+ isEmbedTag = true;
+ atts = scanTag(c, in);
+
+ // If there is a classid and no code tag present, transform it to code tag
+ if (atts.get("code") == null && atts.get("classid") != null && !((String) atts.get("classid")).startsWith("clsid:")) {
+ atts.put("code", atts.get("classid"));
+ }
+
+ // remove java: from code tag
+ if (atts.get("code") != null && ((String) atts.get("code")).startsWith("java:")) {
+ atts.put("code", ((String) atts.get("code")).substring(5));
+ }
+
+ // java_* aliases override older names:
+ // http://java.sun.com/j2se/1.4.2/docs/guide/plugin/developer_guide/using_tags.html#in-nav
+ if (atts.get("java_code") != null) {
+ atts.put("code", ((String) atts.get("java_code")));
+ }
+
+ if (atts.get("java_codebase") != null) {
+ atts.put("codebase", ((String) atts.get("java_codebase")));
+ }
+
+ if (atts.get("java_archive") != null) {
+ atts.put("archive", ((String) atts.get("java_archive")));
+ }
+
+ if (atts.get("java_object") != null) {
+ atts.put("object", ((String) atts.get("java_object")));
+ }
+
+ if (atts.get("java_type") != null) {
+ atts.put("type", ((String) atts.get("java_type")));
+ }
+
+ if (atts.get("code") == null && atts.get("object") == null) {
+ statusMsgStream.println(embedRequiresCodeWarning);
+ atts = null;
+ }
+
+ if (atts.get("width") == null || !isInt(atts.get("width"))) {
+ atts.put("width", width);
+ }
+
+ if (atts.get("height") == null || !isInt(atts.get("height"))) {
+ atts.put("height", height);
+ }
+ }
+ }
+ }
+ }
+ in.close();
+ }
+
+
+ private static AppletMessageHandler amh = new AppletMessageHandler("appletviewer");
+
+ private static void checkConnect(URL url)
+ {
+ SecurityManager security = System.getSecurityManager();
+ if (security != null) {
+ try {
+ java.security.Permission perm =
+ url.openConnection().getPermission();
+ if (perm != null)
+ security.checkPermission(perm);
+ else
+ security.checkConnect(url.getHost(), url.getPort());
+ } catch (java.io.IOException ioe) {
+ security.checkConnect(url.getHost(), url.getPort());
+ }
+ }
+ }
+ }
diff --git a/plugin/icedteanp/java/sun/applet/PluginCallRequest.java b/plugin/icedteanp/java/sun/applet/PluginCallRequest.java
new file mode 100644
index 0000000..a4f01a7
--- /dev/null
+++ b/plugin/icedteanp/java/sun/applet/PluginCallRequest.java
@@ -0,0 +1,89 @@
+/* PluginCallRequest -- represent Java-to-JavaScript requests
+ Copyright (C) 2008 Red Hat
+
+This file is part of IcedTea.
+
+IcedTea is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+IcedTea is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with IcedTea; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package sun.applet;
+
+import java.security.AccessControlContext;
+import java.security.ProtectionDomain;
+
+// FIXME: for each type of request extend a new (anonymous?)
+// PluginCallRequest.
+public abstract class PluginCallRequest {
+ String message;
+ Long reference;
+ PluginCallRequest next;
+ boolean done = false;
+
+ public PluginCallRequest(String message, Long reference) {
+ this.message = message;
+ this.reference = reference;
+ }
+
+ public String getMessage() {
+ return this.message;
+ }
+
+ public boolean isDone() {
+ return this.done;
+ }
+
+ public boolean setDone(boolean done) {
+ return this.done = done;
+ }
+
+ public void setNext(PluginCallRequest next) {
+ this.next = next;
+ }
+
+ public PluginCallRequest getNext() {
+ return this.next;
+ }
+
+ /**
+ * Returns whether the given message is serviceable by this object
+ *
+ * @param message The message to service
+ * @return boolean indicating if message is serviceable
+ */
+ public boolean serviceable(String message) {
+ return message.contains("reference " + reference);
+ }
+
+ public abstract void parseReturn(String message);
+
+ public abstract Object getObject();
+}
diff --git a/plugin/icedteanp/java/sun/applet/PluginCallRequestFactory.java b/plugin/icedteanp/java/sun/applet/PluginCallRequestFactory.java
new file mode 100644
index 0000000..69cec35
--- /dev/null
+++ b/plugin/icedteanp/java/sun/applet/PluginCallRequestFactory.java
@@ -0,0 +1,61 @@
+/* VoidPluginCallRequest -- represent Java-to-JavaScript requests
+ Copyright (C) 2008 Red Hat
+
+This file is part of IcedTea.
+
+IcedTea is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+IcedTea is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with IcedTea; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package sun.applet;
+
+
+public class PluginCallRequestFactory {
+
+ public PluginCallRequest getPluginCallRequest(String id, String message, Long reference) {
+
+ if (id == "member") {
+ return new GetMemberPluginCallRequest(message, reference);
+ } else if (id == "void") {
+ return new VoidPluginCallRequest(message, reference);
+ } else if (id == "window") {
+ return new GetWindowPluginCallRequest(message, reference);
+ } else if (id == "proxyinfo") {
+ return new PluginProxyInfoRequest(message, reference);
+ } else if (id == "cookieinfo") {
+ return new PluginCookieInfoRequest(message, reference);
+ } else {
+ throw new RuntimeException ("Unknown plugin call request type requested from factory");
+ }
+ }
+
+}
diff --git a/plugin/icedteanp/java/sun/applet/PluginClassLoader.java b/plugin/icedteanp/java/sun/applet/PluginClassLoader.java
new file mode 100644
index 0000000..5965d0d
--- /dev/null
+++ b/plugin/icedteanp/java/sun/applet/PluginClassLoader.java
@@ -0,0 +1,51 @@
+/* VoidPluginCallRequest -- represent Java-to-JavaScript requests
+ Copyright (C) 2008 Red Hat
+
+This file is part of IcedTea.
+
+IcedTea is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+IcedTea is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with IcedTea; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package sun.applet;
+
+public class PluginClassLoader extends ClassLoader {
+
+ public PluginClassLoader() {
+ super();
+ }
+
+ public Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
+ return super.loadClass(name, resolve);
+ }
+
+}
diff --git a/plugin/icedteanp/java/sun/applet/PluginCookieInfoRequest.java b/plugin/icedteanp/java/sun/applet/PluginCookieInfoRequest.java
new file mode 100644
index 0000000..c08d9f5
--- /dev/null
+++ b/plugin/icedteanp/java/sun/applet/PluginCookieInfoRequest.java
@@ -0,0 +1,74 @@
+/* PluginCookieInfoRequest -- Object representing a request for cookie information from the browser
+ Copyright (C) 2009 Red Hat
+
+This file is part of IcedTea.
+
+IcedTea is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+IcedTea is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with IcedTea; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package sun.applet;
+
+
+/**
+ * This class represents a request object for cookie information for a given URI
+ */
+
+public class PluginCookieInfoRequest extends PluginCallRequest {
+
+ String cookieString = new String();
+
+ public PluginCookieInfoRequest(String message, Long reference) {
+ super(message, reference);
+ }
+
+ public void parseReturn(String cookieInfo) {
+
+ // try to parse the proxy information. If things go wrong, do nothing ..
+ // this will keep internal = null which forces a direct connection
+
+ PluginDebug.debug ("PluginCookieInfoRequest GOT: " + cookieInfo);
+
+ // Skip the first 5 components. We are guaranteed 5 components,
+ // so no index -1 to worry about
+ cookieInfo = cookieInfo.substring(cookieInfo.indexOf(' ')+1);
+ cookieInfo = cookieInfo.substring(cookieInfo.indexOf(' ')+1);
+ cookieInfo = cookieInfo.substring(cookieInfo.indexOf(' ')+1);
+ cookieInfo = cookieInfo.substring(cookieInfo.indexOf(' ')+1);
+ cookieString = cookieInfo.substring(cookieInfo.indexOf(' ')+1);
+
+ setDone(true);
+ }
+
+ public String getObject() {
+ return this.cookieString;
+ }
+}
diff --git a/plugin/icedteanp/java/sun/applet/PluginCookieManager.java b/plugin/icedteanp/java/sun/applet/PluginCookieManager.java
new file mode 100644
index 0000000..233cfa9
--- /dev/null
+++ b/plugin/icedteanp/java/sun/applet/PluginCookieManager.java
@@ -0,0 +1,88 @@
+/* PluginCookieManager -- Cookie manager for the plugin
+ Copyright (C) 2009 Red Hat
+
+This file is part of IcedTea.
+
+IcedTea is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+IcedTea is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with IcedTea; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package sun.applet;
+
+import java.io.IOException;
+import java.net.CookieManager;
+import java.net.HttpCookie;
+import java.net.URI;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+public class PluginCookieManager extends CookieManager
+{
+ public Map<String, List<String>> get(URI uri,
+ Map<String, List<String>> requestHeaders) throws IOException {
+ // pre-condition check
+ if (uri == null || requestHeaders == null) {
+ throw new IllegalArgumentException("Argument is null");
+ }
+
+ Map<String, List<String>> cookieMap = new java.util.HashMap<String, List<String>>();
+
+ String cookies = (String) PluginAppletViewer
+ .requestPluginCookieInfo(uri);
+ List<String> cookieHeader = new java.util.ArrayList<String>();
+
+ if (cookies != null && cookies.length() > 0)
+ cookieHeader.add(cookies);
+
+ // Add anything else that mozilla didn't add
+ for (HttpCookie cookie : getCookieStore().get(uri)) {
+ // apply path-matches rule (RFC 2965 sec. 3.3.4)
+ if (pathMatches(uri.getPath(), cookie.getPath())) {
+ cookieHeader.add(cookie.toString());
+ }
+ }
+
+ cookieMap.put("Cookie", cookieHeader);
+ return Collections.unmodifiableMap(cookieMap);
+ }
+
+ private boolean pathMatches(String path, String pathToMatchWith) {
+ if (path == pathToMatchWith)
+ return true;
+ if (path == null || pathToMatchWith == null)
+ return false;
+ if (path.startsWith(pathToMatchWith))
+ return true;
+
+ return false;
+ }
+}
diff --git a/plugin/icedteanp/java/sun/applet/PluginDebug.java b/plugin/icedteanp/java/sun/applet/PluginDebug.java
new file mode 100644
index 0000000..60e2bd0
--- /dev/null
+++ b/plugin/icedteanp/java/sun/applet/PluginDebug.java
@@ -0,0 +1,51 @@
+/* VoidPluginCallRequest -- represent Java-to-JavaScript requests
+ Copyright (C) 2008 Red Hat
+
+This file is part of IcedTea.
+
+IcedTea is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+IcedTea is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with IcedTea; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package sun.applet;
+
+import java.io.*;
+
+public class PluginDebug {
+
+ static final boolean DEBUG = System.getenv().containsKey("ICEDTEAPLUGIN_DEBUG");
+
+ public static void debug(String message) {
+ if (DEBUG)
+ System.err.println(message);
+ }
+}
diff --git a/plugin/icedteanp/java/sun/applet/PluginException.java b/plugin/icedteanp/java/sun/applet/PluginException.java
new file mode 100644
index 0000000..0f6e660
--- /dev/null
+++ b/plugin/icedteanp/java/sun/applet/PluginException.java
@@ -0,0 +1,53 @@
+/* VoidPluginCallRequest -- represent Java-to-JavaScript requests
+ Copyright (C) 2008 Red Hat
+
+This file is part of IcedTea.
+
+IcedTea is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+IcedTea is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with IcedTea; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package sun.applet;
+
+
+public class PluginException extends Exception {
+
+ public PluginException (PluginStreamHandler sh, int instance, int reference, Throwable t) {
+ t.printStackTrace();
+ this.setStackTrace(t.getStackTrace());
+
+ AppletSecurityContextManager.dumpStore(0);
+
+ String message = "instance " + instance + " reference " + reference + " Error " + t.getMessage();
+ sh.write(message);
+ }
+}
diff --git a/plugin/icedteanp/java/sun/applet/PluginMain.java b/plugin/icedteanp/java/sun/applet/PluginMain.java
new file mode 100644
index 0000000..bce87b2
--- /dev/null
+++ b/plugin/icedteanp/java/sun/applet/PluginMain.java
@@ -0,0 +1,319 @@
+/* VoidPluginCallRequest -- represent Java-to-JavaScript requests
+ Copyright (C) 2008 Red Hat
+
+This file is part of IcedTea.
+
+IcedTea is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+IcedTea is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with IcedTea; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+/*
+ * Copyright 1999-2006 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.applet;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.net.Authenticator;
+import java.net.CookieHandler;
+import java.net.CookieManager;
+import java.net.PasswordAuthentication;
+import java.net.ProxySelector;
+import java.util.Enumeration;
+import java.util.Properties;
+
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManager;
+
+import net.sourceforge.jnlp.security.VariableX509TrustManager;
+
+/**
+ * The main entry point into PluginAppletViewer.
+ */
+public class PluginMain
+{
+
+ // the files where stdout/stderr are sent to
+ public static final String PLUGIN_STDERR_FILE = System.getProperty("user.home") + "/.icedteaplugin/java.stderr";
+ public static final String PLUGIN_STDOUT_FILE = System.getProperty("user.home") + "/.icedteaplugin/java.stdout";
+
+ final boolean redirectStreams = System.getenv().containsKey("ICEDTEAPLUGIN_DEBUG");
+ static PluginStreamHandler streamHandler;
+
+ // This is used in init(). Getting rid of this is desirable but depends
+ // on whether the property that uses it is necessary/standard.
+ public static final String theVersion = System.getProperty("java.version");
+
+ private PluginAppletSecurityContext securityContext;
+
+ /**
+ * The main entry point into AppletViewer.
+ */
+ public static void main(String args[])
+ throws IOException
+ {
+ if (args.length != 2 || !(new File(args[0]).exists()) || !(new File(args[1]).exists())) {
+ System.err.println("Invalid pipe names provided. Refusing to proceed.");
+ System.exit(1);
+ }
+
+ try {
+ PluginMain pm = new PluginMain(args[0], args[1]);
+ } catch (Exception e) {
+ e.printStackTrace();
+ System.err.println("Something very bad happened. I don't know what to do, so I am going to exit :(");
+ System.exit(1);
+ }
+ }
+
+ public PluginMain(String inPipe, String outPipe) {
+
+ try {
+ File errFile = new File(PLUGIN_STDERR_FILE);
+ File outFile = new File(PLUGIN_STDOUT_FILE);
+
+ System.setErr(new TeeOutputStream(new FileOutputStream(errFile), System.err));
+ System.setOut(new TeeOutputStream(new FileOutputStream(outFile), System.out));
+ } catch (Exception e) {
+ PluginDebug.debug("Unable to redirect streams");
+ e.printStackTrace();
+ }
+
+ connect(inPipe, outPipe);
+
+ securityContext = new PluginAppletSecurityContext(0);
+ securityContext.prePopulateLCClasses();
+ securityContext.setStreamhandler(streamHandler);
+ AppletSecurityContextManager.addContext(0, securityContext);
+
+ PluginAppletViewer.setStreamhandler(streamHandler);
+ PluginAppletViewer.setPluginCallRequestFactory(new PluginCallRequestFactory());
+
+ init();
+
+ // Streams set. Start processing.
+ streamHandler.startProcessing();
+ }
+
+ public void connect(String inPipe, String outPipe) {
+ try {
+ streamHandler = new PluginStreamHandler(new FileInputStream(inPipe), new FileOutputStream(outPipe));
+ PluginDebug.debug("Streams initialized");
+ } catch (IOException ioe) {
+ ioe.printStackTrace();
+ }
+ }
+
+ private static void init() {
+ Properties avProps = new Properties();
+
+ // ADD OTHER RANDOM PROPERTIES
+ // XXX 5/18 need to revisit why these are here, is there some
+ // standard for what is available?
+
+ // Standard browser properties
+ avProps.put("browser", "sun.applet.AppletViewer");
+ avProps.put("browser.version", "1.06");
+ avProps.put("browser.vendor", "Sun Microsystems Inc.");
+ avProps.put("http.agent", "Java(tm) 2 SDK, Standard Edition v" + theVersion);
+
+ // Define which packages can be extended by applets
+ // XXX 5/19 probably not needed, not checked in AppletSecurity
+ avProps.put("package.restrict.definition.java", "true");
+ avProps.put("package.restrict.definition.sun", "true");
+
+ // Define which properties can be read by applets.
+ // A property named by "key" can be read only when its twin
+ // property "key.applet" is true. The following ten properties
+ // are open by default. Any other property can be explicitly
+ // opened up by the browser user by calling appletviewer with
+ // -J-Dkey.applet=true
+ avProps.put("java.version.applet", "true");
+ avProps.put("java.vendor.applet", "true");
+ avProps.put("java.vendor.url.applet", "true");
+ avProps.put("java.class.version.applet", "true");
+ avProps.put("os.name.applet", "true");
+ avProps.put("os.version.applet", "true");
+ avProps.put("os.arch.applet", "true");
+ avProps.put("file.separator.applet", "true");
+ avProps.put("path.separator.applet", "true");
+ avProps.put("line.separator.applet", "true");
+
+ avProps.put("javaplugin.nodotversion", "160_17");
+ avProps.put("javaplugin.version", "1.6.0_17");
+ avProps.put("javaplugin.vm.options", "");
+
+ // Read in the System properties. If something is going to be
+ // over-written, warn about it.
+ Properties sysProps = System.getProperties();
+ for (Enumeration e = sysProps.propertyNames(); e.hasMoreElements(); ) {
+ String key = (String) e.nextElement();
+ String val = (String) sysProps.getProperty(key);
+ avProps.setProperty(key, val);
+ }
+
+ // INSTALL THE PROPERTY LIST
+ System.setProperties(avProps);
+
+
+ try {
+ SSLSocketFactory sslSocketFactory;
+ SSLContext context = SSLContext.getInstance("SSL");
+ TrustManager[] trust = new TrustManager[] { VariableX509TrustManager.getInstance() };
+ context.init(null, trust, null);
+ sslSocketFactory = context.getSocketFactory();
+
+ HttpsURLConnection.setDefaultSSLSocketFactory(sslSocketFactory);
+ } catch (Exception e) {
+ System.err.println("Unable to set SSLSocketfactory (may _prevent_ access to sites that should be trusted)! Continuing anyway...");
+ e.printStackTrace();
+ }
+
+ // plug in a custom authenticator and proxy selector
+ Authenticator.setDefault(new CustomAuthenticator());
+ ProxySelector.setDefault(new PluginProxySelector());
+
+ CookieManager ckManager = new PluginCookieManager();
+ CookieHandler.setDefault(ckManager);
+ }
+
+ static boolean messageAvailable() {
+ return streamHandler.messageAvailable();
+ }
+
+ static String getMessage() {
+ return streamHandler.getMessage();
+ }
+
+ static class CustomAuthenticator extends Authenticator {
+
+ public PasswordAuthentication getPasswordAuthentication() {
+
+ // No security check is required here, because the only way to
+ // set parameters for which auth info is needed
+ // (Authenticator:requestPasswordAuthentication()), has a security
+ // check
+
+ String type = this.getRequestorType() == RequestorType.PROXY ? "proxy" : "web";
+
+ // request auth info from user
+ PasswordAuthenticationDialog pwDialog = new PasswordAuthenticationDialog();
+ PasswordAuthentication auth = pwDialog.askUser(this.getRequestingHost(), this.getRequestingPort(), this.getRequestingPrompt(), type);
+
+ // send it along
+ return auth;
+ }
+ }
+
+ /**
+ * Behaves like the 'tee' command, sends output to both actual std stream and a
+ * file
+ */
+ class TeeOutputStream extends PrintStream {
+
+ // Everthing written to TeeOutputStream is written to this file
+ PrintStream logFile;
+
+ public TeeOutputStream(FileOutputStream fileOutputStream,
+ PrintStream stdStream) {
+ super(stdStream);
+ logFile = new PrintStream(fileOutputStream);
+ }
+
+ @Override
+ public boolean checkError() {
+ boolean thisError = super.checkError();
+ boolean fileError = logFile.checkError();
+
+ return thisError || fileError;
+ }
+
+ @Override
+ public void close() {
+ logFile.close();
+ super.close();
+ }
+
+ @Override
+ public void flush() {
+ logFile.flush();
+ super.flush();
+ }
+
+ /*
+ * The big ones: these do the actual writing
+ */
+
+ @Override
+ public void write(byte[] buf, int off, int len) {
+ logFile.write(buf, off, len);
+
+ if (!redirectStreams)
+ super.write(buf, off, len);
+ }
+
+ @Override
+ public void write(int b) {
+ logFile.write(b);
+
+ if (!redirectStreams)
+ super.write(b);
+ }
+ }
+
+}
diff --git a/plugin/icedteanp/java/sun/applet/PluginMessageConsumer.java b/plugin/icedteanp/java/sun/applet/PluginMessageConsumer.java
new file mode 100644
index 0000000..0bc5dda
--- /dev/null
+++ b/plugin/icedteanp/java/sun/applet/PluginMessageConsumer.java
@@ -0,0 +1,268 @@
+/* VoidPluginCallRequest -- represent Java-to-JavaScript requests
+ Copyright (C) 2008 Red Hat
+
+This file is part of IcedTea.
+
+IcedTea is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+IcedTea is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with IcedTea; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package sun.applet;
+
+import java.util.ArrayList;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.Set;
+
+class PluginMessageConsumer {
+
+ private static int MAX_PARALLEL_INITS = 1;
+
+ // Each initialization requires 5 responses (tag, handle, width, proxy, cookie)
+ // before the message stack unlocks/collapses. This works out well because we
+ // want to allow upto 5 parallel tasks anyway
+ private static int MAX_WORKERS = MAX_PARALLEL_INITS*4;
+ private static int PRIORITY_WORKERS = MAX_PARALLEL_INITS*2;
+
+ private static Hashtable<Integer, PluginMessageHandlerWorker> initWorkers = new Hashtable<Integer, PluginMessageHandlerWorker>(2);
+
+ LinkedList<String> readQueue = new LinkedList<String>();
+ private static LinkedList<String> priorityWaitQueue = new LinkedList<String>();
+ ArrayList<PluginMessageHandlerWorker> workers = new ArrayList<PluginMessageHandlerWorker>();
+ PluginStreamHandler streamHandler = null;
+ AppletSecurity as;
+ ConsumerThread consumerThread = new ConsumerThread();
+ private static ArrayList<Integer> processedIds = new ArrayList<Integer>();
+
+ /**
+ * Registers a reference to wait for. Responses to registered priority
+ * references get handled by priority worker if normal workers are busy.
+ *
+ * @param reference The reference to give priority to
+ */
+ public static void registerPriorityWait(Long reference) {
+ PluginDebug.debug("Registering priority for reference " + reference);
+ registerPriorityWait("reference " + reference.toString());
+ }
+
+ /**
+ * Registers a string to wait for.
+ *
+ * @param searchString the string to look for in a response
+ */
+ public static void registerPriorityWait(String searchString) {
+ PluginDebug.debug("Registering priority for string " + searchString);
+ synchronized (priorityWaitQueue) {
+ if (!priorityWaitQueue.contains(searchString))
+ priorityWaitQueue.add(searchString);
+ }
+ }
+
+ /**
+ * Unregisters a priority reference to wait for.
+ *
+ * @param reference The reference to remove
+ */
+ public static void unRegisterPriorityWait(Long reference) {
+ unRegisterPriorityWait(reference.toString());
+ }
+
+ /**
+ * Unregisters a priority string to wait for.
+ *
+ * @param searchString The string to unregister from the priority list
+ */
+ public static void unRegisterPriorityWait(String searchString) {
+ synchronized (priorityWaitQueue) {
+ priorityWaitQueue.remove(searchString);
+ }
+ }
+
+ /**
+ * Returns the reference for this message. This method assumes that
+ * the message has a reference number.
+ *
+ * @param The message
+ * @return the reference number
+ */
+ private Long getReference(String[] msgParts) {
+ return Long.parseLong(msgParts[3]);
+ }
+
+ public PluginMessageConsumer(PluginStreamHandler streamHandler) {
+
+ as = new AppletSecurity();
+ this.streamHandler = streamHandler;
+ this.consumerThread.start();
+ }
+
+ private String getPriorityStrIfPriority(String message) {
+
+ synchronized (priorityWaitQueue) {
+ Iterator<String> it = priorityWaitQueue.iterator();
+
+ while (it.hasNext()) {
+ String priorityStr = it.next();
+ if (message.indexOf(priorityStr) > 0)
+ return priorityStr;
+ }
+ }
+
+ return null;
+ }
+
+ private boolean isInInit(Integer instanceNum) {
+ return initWorkers.containsKey(instanceNum);
+ }
+
+ private void addToInitWorkers(Integer instanceNum, PluginMessageHandlerWorker worker) {
+ synchronized(initWorkers) {
+ initWorkers.put(instanceNum, worker);
+ }
+ }
+
+
+ public void notifyWorkerIsFree(PluginMessageHandlerWorker worker) {
+ synchronized (initWorkers) {
+ Iterator<Integer> i = initWorkers.keySet().iterator();
+ while (i.hasNext()) {
+ Integer key = i.next();
+ if (initWorkers.get(key).equals(worker)) {
+ processedIds.add(key);
+ initWorkers.remove(key);
+ }
+ }
+ }
+
+ consumerThread.interrupt();
+ }
+
+ public void queue(String message) {
+ synchronized(readQueue) {
+ readQueue.addLast(message);
+ }
+
+ // Wake that lazy consumer thread
+ consumerThread.interrupt();
+ }
+
+ protected class ConsumerThread extends Thread {
+ public void run() {
+
+ while (true) {
+
+ String message = null;
+
+ synchronized(readQueue) {
+ message = readQueue.poll();
+ }
+
+ if (message != null) {
+
+ String[] msgParts = message.split(" ");
+
+
+ String priorityStr = getPriorityStrIfPriority(message);
+ boolean isPriorityResponse = (priorityStr != null);
+
+ //PluginDebug.debug("Message " + message + " (priority=" + isPriorityResponse + ") ready to be processed. Looking for free worker...");
+ final PluginMessageHandlerWorker worker = getFreeWorker(isPriorityResponse);
+
+ if (worker == null) {
+ synchronized(readQueue) {
+ readQueue.addLast(message);
+ }
+
+ continue; // re-loop to try next msg
+ }
+
+ if (msgParts[2].equals("tag"))
+ addToInitWorkers((new Integer(msgParts[1])), worker);
+
+ if (isPriorityResponse) {
+ unRegisterPriorityWait(priorityStr);
+ }
+
+ worker.setmessage(message);
+ worker.interrupt();
+
+ } else {
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException ie) {}
+ }
+ }
+ }
+ }
+
+ private PluginMessageHandlerWorker getFreeWorker(boolean prioritized) {
+
+ for (PluginMessageHandlerWorker worker: workers) {
+ if (worker.isFree(prioritized)) {
+ PluginDebug.debug("Found free worker (" + worker.isPriority() + ") with id " + worker.getWorkerId());
+ // mark it busy before returning
+ worker.busy();
+ return worker;
+ }
+ }
+
+ // If we have less than MAX_WORKERS, create a new worker
+ if (workers.size() <= MAX_WORKERS) {
+ PluginMessageHandlerWorker worker = null;
+
+ if (workers.size() < (MAX_WORKERS - PRIORITY_WORKERS)) {
+ PluginDebug.debug("Cannot find free worker, creating worker " + workers.size());
+ worker = new PluginMessageHandlerWorker(this, streamHandler, workers.size(), as, false);
+ } else if (prioritized) {
+ PluginDebug.debug("Cannot find free worker, creating priority worker " + workers.size());
+ worker = new PluginMessageHandlerWorker(this, streamHandler, workers.size(), as, true);
+ } else {
+ return null;
+ }
+
+ worker.start();
+ worker.busy();
+ workers.add(worker);
+ return worker;
+
+ }
+
+ // No workers available. Better luck next time!
+ return null;
+ }
+
+ private void dumpWorkerStatus() {
+ for (PluginMessageHandlerWorker worker: workers) {
+ PluginDebug.debug(worker.toString());
+ }
+ }
+}
diff --git a/plugin/icedteanp/java/sun/applet/PluginMessageHandlerWorker.java b/plugin/icedteanp/java/sun/applet/PluginMessageHandlerWorker.java
new file mode 100644
index 0000000..30714c4
--- /dev/null
+++ b/plugin/icedteanp/java/sun/applet/PluginMessageHandlerWorker.java
@@ -0,0 +1,147 @@
+/* VoidPluginCallRequest -- represent Java-to-JavaScript requests
+ Copyright (C) 2008 Red Hat
+
+This file is part of IcedTea.
+
+IcedTea is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+IcedTea is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with IcedTea; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package sun.applet;
+
+
+class PluginMessageHandlerWorker extends Thread {
+
+ private boolean free = true;
+ private boolean isPriorityWorker = false;
+ private int id;
+ private String message = null;
+ private SecurityManager sm;
+ PluginStreamHandler streamHandler = null;
+ PluginMessageConsumer consumer = null;
+
+ public PluginMessageHandlerWorker(
+ PluginMessageConsumer consumer,
+ PluginStreamHandler streamHandler, int id,
+ SecurityManager sm, boolean isPriorityWorker) {
+
+ this.id = id;
+ this.streamHandler = streamHandler;
+ this.sm = sm;
+ this.isPriorityWorker = isPriorityWorker;
+ this.consumer = consumer;
+
+ PluginDebug.debug("Worker " + this.id + " (priority=" + isPriorityWorker + ") created.");
+ }
+
+ public void setmessage(String message) {
+ this.message = message;
+ }
+
+ public void run() {
+ while (true) {
+
+ if (message != null) {
+
+ PluginDebug.debug("Consumer (priority=" + isPriorityWorker + ") thread " + id + " consuming " + message);
+
+ // ideally, whoever returns things object should mark it
+ // busy first, but just in case..
+ busy();
+
+ try {
+ streamHandler.handleMessage(message);
+ } catch (PluginException pe) {
+ /*
+ catch the exception and DO NOTHING. The plugin should take over after
+ this error and let the user know. We don't quit because otherwise the
+ exception will spread to the rest of the applets which is a no-no
+ */
+ }
+
+ this.message = null;
+
+ PluginDebug.debug("Consumption (priority=" + isPriorityWorker + ") completed by consumer thread " + id);
+
+ // mark ourselves free again
+ free();
+
+ } else {
+
+ // Sleep when there is nothing to do
+ try {
+ Thread.sleep(Integer.MAX_VALUE);
+ PluginDebug.debug("Consumer thread " + id + " sleeping...");
+ } catch (InterruptedException ie) {
+ PluginDebug.debug("Consumer thread " + id + " woken...");
+ // nothing.. someone woke us up, see if there
+ // is work to do
+ }
+ }
+ }
+ }
+
+
+
+ public int getWorkerId() {
+ return id;
+ }
+
+ public void busy() {
+ synchronized (this) {
+ this.free = false;
+ }
+ }
+
+ public void free() {
+ synchronized (this) {
+ this.free = true;
+
+ // Signal the consumer that we are done in case it was waiting
+ consumer.notifyWorkerIsFree(this);
+ }
+ }
+
+ public boolean isPriority() {
+ return isPriorityWorker;
+ }
+
+ public boolean isFree(boolean prioritized) {
+ synchronized (this) {
+ return free && (prioritized == isPriorityWorker);
+ }
+ }
+
+ public String toString() {
+ return "Worker #" + this.id + "/IsPriority=" + this.isPriorityWorker + "/IsFree=" + this.free + "/Message=" + message;
+ }
+}
diff --git a/plugin/icedteanp/java/sun/applet/PluginObjectStore.java b/plugin/icedteanp/java/sun/applet/PluginObjectStore.java
new file mode 100644
index 0000000..b744744
--- /dev/null
+++ b/plugin/icedteanp/java/sun/applet/PluginObjectStore.java
@@ -0,0 +1,132 @@
+/* PluginObjectStore -- manage identifier-to-object mapping
+ Copyright (C) 2008 Red Hat
+
+This file is part of IcedTea.
+
+IcedTea is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+IcedTea is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with IcedTea; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package sun.applet;
+
+import java.util.*;
+import java.lang.reflect.*;
+import java.io.*;
+
+public class PluginObjectStore
+{
+ private static HashMap<Integer, Object> objects = new HashMap();
+ private static HashMap<Integer, Integer> counts = new HashMap();
+ private static HashMap<Object, Integer> identifiers = new HashMap();
+ // FIXME:
+ //
+ // IF uniqueID == MAX_LONG, uniqueID =
+ // 0 && wrapped = true
+ //
+ // if (wrapped), check if
+ // objects.get(uniqueID) returns null
+ //
+ // if yes, use uniqueID, if no,
+ // uniqueID++ and keep checking
+ // or:
+ // stack of available ids:
+ // derefed id -> derefed id -> nextUniqueIdentifier
+ private static int nextUniqueIdentifier = 1;
+
+ public Object getObject(Integer identifier) {
+ return objects.get(identifier);
+ }
+
+ public Integer getIdentifier(Object object) {
+ if (object == null)
+ return 0;
+ return identifiers.get(object);
+ }
+
+ public boolean contains(Object object) {
+ if (object == null)
+ return identifiers.containsKey(object);
+
+ return false;
+ }
+
+ public boolean contains(int identifier) {
+ return objects.containsKey(identifier);
+ }
+
+ public void reference(Object object) {
+ Integer identifier = identifiers.get(object);
+ if (identifier == null) {
+ objects.put(nextUniqueIdentifier, object);
+ counts.put(nextUniqueIdentifier, 1);
+ identifiers.put(object, nextUniqueIdentifier);
+ //System.out.println("JAVA ADDED: " + nextUniqueIdentifier);
+ //System.out.println("JAVA REFERENCED: " + nextUniqueIdentifier
+ // + " to: 1");
+ nextUniqueIdentifier++;
+ } else {
+ counts.put(identifier, counts.get(identifier) + 1);
+ //System.out.println("JAVA REFERENCED: " + identifier +
+ // " to: " + counts.get(identifier));
+ }
+ }
+
+ public void unreference(int identifier) {
+ Integer currentCount = counts.get(identifier);
+ if (currentCount == null) {
+ //System.out.println("ERROR UNREFERENCING: " + identifier);
+ return;
+ }
+ if (currentCount == 1) {
+ //System.out.println("JAVA DEREFERENCED: " + identifier
+ // + " to: 0");
+ Object object = objects.get(identifier);
+ objects.remove(identifier);
+ counts.remove(identifier);
+ identifiers.remove(object);
+ //System.out.println("JAVA REMOVED: " + identifier);
+ } else {
+ counts.put(identifier, currentCount - 1);
+ //System.out.println("JAVA DEREFERENCED: " +
+ // identifier + " to: " +
+ // counts.get(identifier));
+ }
+ }
+
+ public void dump() {
+ Iterator i = objects.keySet().iterator();
+ while (i.hasNext()) {
+ Object key = i.next();
+ PluginDebug.debug(key + "::" + objects.get(key));
+ }
+ }
+}
+
diff --git a/plugin/icedteanp/java/sun/applet/PluginProxyInfoRequest.java b/plugin/icedteanp/java/sun/applet/PluginProxyInfoRequest.java
new file mode 100644
index 0000000..674f11d
--- /dev/null
+++ b/plugin/icedteanp/java/sun/applet/PluginProxyInfoRequest.java
@@ -0,0 +1,81 @@
+/* PluginProxyInfoRequest -- Object representing a request for proxy information from the browser
+ Copyright (C) 2009 Red Hat
+
+This file is part of IcedTea.
+
+IcedTea is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+IcedTea is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with IcedTea; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package sun.applet;
+
+import java.net.MalformedURLException;
+import java.net.URI;
+
+/**
+ * This class represents a request object for proxy information for a given URI
+ */
+
+public class PluginProxyInfoRequest extends PluginCallRequest {
+
+ URI internal = null;
+
+ public PluginProxyInfoRequest(String message, Long reference) {
+ super(message, reference);
+ }
+
+ public void parseReturn(String proxyInfo) {
+
+ // try to parse the proxy information. If things go wrong, do nothing ..
+ // this will keep internal = null which forces a direct connection
+
+ PluginDebug.debug ("PluginProxyInfoRequest GOT: " + proxyInfo);
+ String[] messageComponents = proxyInfo.split(" ");
+
+ try {
+ String protocol = messageComponents[4].equals("PROXY") ? "http" : "socks";
+ String host = messageComponents[5].split(":")[0];
+ int port = Integer.parseInt(messageComponents[5].split(":")[1]);
+
+ internal = new URI(protocol, null, host, port, null, null, null);
+ } catch (ArrayIndexOutOfBoundsException aioobe) {
+ // Nothing.. this is expected if there is no proxy
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ setDone(true);
+ }
+
+ public URI getObject() {
+ return this.internal;
+ }
+}
diff --git a/plugin/icedteanp/java/sun/applet/PluginProxySelector.java b/plugin/icedteanp/java/sun/applet/PluginProxySelector.java
new file mode 100644
index 0000000..dff8ded
--- /dev/null
+++ b/plugin/icedteanp/java/sun/applet/PluginProxySelector.java
@@ -0,0 +1,195 @@
+/* PluginProxySelector -- proxy selector for all connections from applets and the plugin
+ Copyright (C) 2009 Red Hat
+
+This file is part of IcedTea.
+
+IcedTea is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+IcedTea is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with IcedTea; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package sun.applet;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.Proxy;
+import java.net.ProxySelector;
+import java.net.SocketAddress;
+import java.net.URI;
+import java.util.Date;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * Proxy selector implementation for plugin network functions.
+ *
+ * This class fetches proxy information from the web browser and
+ * uses that information in the context of all network connection
+ * (plugin specific and applet connections) as applicable
+ *
+ */
+
+public class PluginProxySelector extends ProxySelector {
+
+ private TimedHashMap<String, Proxy> proxyCache = new TimedHashMap<String, Proxy>();
+
+
+ @Override
+ public void connectFailed(URI uri, SocketAddress sa, IOException ioe) {
+ // If the connection fails, there is little we can do here. Just print the exception
+ ioe.printStackTrace();
+ }
+
+ /**
+ * Selects the appropriate proxy (or DIRECT connection method) for the given URI
+ *
+ * @param uri The URI being accessed
+ * @return A list of Proxy objects that are usable for this URI
+ */
+ @Override
+ public List<Proxy> select(URI uri) {
+
+ List<Proxy> proxyList = new ArrayList<Proxy>();
+
+ // check cache first
+ Proxy cachedProxy = checkCache(uri);
+ if (cachedProxy != null) {
+ proxyList.add(cachedProxy);
+ return proxyList;
+ }
+
+ // Nothing usable in cache. Fetch info from browser
+ Proxy proxy = Proxy.NO_PROXY;
+ Object o = PluginAppletViewer.requestPluginProxyInfo(uri);
+
+ // If the browser returned anything, try to parse it. If anything in the try block fails, the fallback is direct connection
+ try {
+ if (o != null) {
+ PluginDebug.debug("Proxy URI = " + o);
+ URI proxyURI = (URI) o;
+
+ // If origin uri is http/ftp, we're good. If origin uri is not that, the proxy _must_ be socks, else we fallback to direct
+ if (uri.getScheme().startsWith("http") || uri.getScheme().equals("ftp") || proxyURI.getScheme().startsWith("socks")) {
+
+ Proxy.Type type = proxyURI.getScheme().equals("http") ? Proxy.Type.HTTP : Proxy.Type.SOCKS;
+ InetSocketAddress socketAddr = new InetSocketAddress(proxyURI.getHost(), proxyURI.getPort());
+
+ proxy = new Proxy(type, socketAddr);
+
+ String uriKey = uri.getScheme() + "://" + uri.getHost();
+ proxyCache.put(uriKey, proxy);
+ } else {
+ PluginDebug.debug("Proxy " + proxyURI + " cannot be used for " + uri + ". Falling back to DIRECT");
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ proxyList.add(proxy);
+
+ PluginDebug.debug("Proxy for " + uri.toString() + " is " + proxy);
+
+ return proxyList;
+ }
+
+ /**
+ * Checks to see if proxy information is already cached.
+ *
+ * @param uri The URI to check
+ * @return The cached Proxy. null if there is no suitable cached proxy.
+ */
+ private Proxy checkCache(URI uri) {
+
+ String uriKey = uri.getScheme() + "://" + uri.getHost();
+ if (proxyCache.get(uriKey) != null) {
+ return proxyCache.get(uriKey);
+ }
+
+ return null;
+ }
+
+ /**
+ * Simple utility class that extends HashMap by adding an expiry to the entries.
+ *
+ * This map stores entries, and returns them only if the entries were last accessed within time t=10 seconds
+ *
+ * @param <K> The key type
+ * @param <V> The Object type
+ */
+
+ private class TimedHashMap<K,V> extends HashMap<K,V> {
+
+ HashMap<K, Long> timeStamps = new HashMap<K, Long>();
+ Long expiry = 10000L;
+
+ /**
+ * Store the item in the map and associate a timestamp with it
+ *
+ * @param key The key
+ * @param value The value to store
+ */
+ public V put(K key, V value) {
+ timeStamps.put(key, new Date().getTime());
+ return super.put(key, value);
+ }
+
+ /**
+ * Return cached item if it has not already expired.
+ *
+ * Before returning, this method also resets the "last accessed"
+ * time for this entry, so it is good for another 10 seconds
+ *
+ * @param key The key
+ */
+ public V get(Object key) {
+
+ Long now = new Date().getTime();
+
+ if (super.containsKey(key)) {
+ Long age = now - timeStamps.get(key);
+
+ // Item exists. If it has not expired, renew its access time and return it
+ if (age <= expiry) {
+ PluginDebug.debug("Returning proxy " + super.get(key) + " from cache for " + key);
+ timeStamps.put((K) key, (new Date()).getTime());
+ return super.get(key);
+ } else {
+ PluginDebug.debug("Proxy cache for " + key + " has expired (age=" + age/1000.0 + " seconds)");
+ }
+ }
+
+ return null;
+ }
+ }
+
+}
diff --git a/plugin/icedteanp/java/sun/applet/PluginStreamHandler.java b/plugin/icedteanp/java/sun/applet/PluginStreamHandler.java
new file mode 100644
index 0000000..eb5b11a
--- /dev/null
+++ b/plugin/icedteanp/java/sun/applet/PluginStreamHandler.java
@@ -0,0 +1,454 @@
+/* VoidPluginCallRequest -- represent Java-to-JavaScript requests
+ Copyright (C) 2008 Red Hat
+
+This file is part of IcedTea.
+
+IcedTea is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+IcedTea is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with IcedTea; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package sun.applet;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.StreamTokenizer;
+import java.net.MalformedURLException;
+import java.nio.charset.Charset;
+import java.util.Date;
+import java.util.LinkedList;
+
+import javax.swing.SwingUtilities;
+
+
+public class PluginStreamHandler {
+
+ private BufferedReader pluginInputReader;
+ private StreamTokenizer pluginInputTokenizer;
+ private BufferedWriter pluginOutputWriter;
+
+ private RequestQueue queue = new RequestQueue();
+
+ private JavaConsole console = new JavaConsole();
+
+ LinkedList<String> writeQueue = new LinkedList<String>();
+
+ PluginMessageConsumer consumer;
+ Boolean shuttingDown = false;
+
+ PluginAppletViewer pav;
+
+ static Date d = new Date();
+ static long startTime = d.getTime();
+ static long totalWait = 0;
+
+ public PluginStreamHandler(InputStream inputstream, OutputStream outputstream)
+ throws MalformedURLException, IOException
+ {
+
+ PluginDebug.debug("Current context CL=" + Thread.currentThread().getContextClassLoader());
+ try {
+ pav = (PluginAppletViewer) ClassLoader.getSystemClassLoader().loadClass("sun.applet.PluginAppletViewer").newInstance();
+ PluginDebug.debug("Loaded: " + pav + " CL=" + pav.getClass().getClassLoader());
+ } catch (InstantiationException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (IllegalAccessException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (ClassNotFoundException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+
+ PluginDebug.debug("Creating consumer...");
+ consumer = new PluginMessageConsumer(this);
+
+ // Set up input and output pipes. Use UTF-8 encoding.
+ pluginInputReader =
+ new BufferedReader(new InputStreamReader(inputstream,
+ Charset.forName("UTF-8")));
+ /*pluginInputTokenizer = new StreamTokenizer(pluginInputReader);
+ pluginInputTokenizer.resetSyntax();
+ pluginInputTokenizer.whitespaceChars('\u0000', '\u0000');
+ pluginInputTokenizer.wordChars('\u0001', '\u00FF');*/
+ pluginOutputWriter =
+ new BufferedWriter(new OutputStreamWriter
+ (outputstream, Charset.forName("UTF-8")));
+
+ /*
+ while(true) {
+ String message = read();
+ PluginDebug.debug(message);
+ handleMessage(message);
+ // TODO:
+ // write(queue.peek());
+ }
+ */
+ }
+
+ public void startProcessing() {
+
+ Thread listenerThread = new Thread() {
+
+ public void run() {
+
+ while (true) {
+
+ PluginDebug.debug("Waiting for data...");
+
+ long b4 = new Date().getTime();
+
+ String s = read();
+
+ long after = new Date().getTime();
+
+ totalWait += (after - b4);
+ //System.err.println("Total wait time: " + totalWait);
+
+ if (s != null) {
+ consumer.queue(s);
+ } else {
+ try {
+ // Close input/output channels to plugin.
+ pluginInputReader.close();
+ pluginOutputWriter.close();
+ } catch (IOException exception) {
+ // Deliberately ignore IOException caused by broken
+ // pipe since plugin may have already detached.
+ }
+ AppletSecurityContextManager.dumpStore(0);
+ PluginDebug.debug("APPLETVIEWER: exiting appletviewer");
+ System.exit(0);
+ }
+
+/*
+ int readChar = -1;
+ // blocking read, discard first character
+ try {
+ readChar = pluginInputReader.read();
+ } catch (IOException ioe) {
+ // plugin may have detached
+ }
+
+ // if not disconnected
+ if (readChar != -1) {
+ String s = read();
+ PluginDebug.debug("Got data, consuming " + s);
+ consumer.consume(s);
+ } else {
+ try {
+ // Close input/output channels to plugin.
+ pluginInputReader.close();
+ pluginOutputWriter.close();
+ } catch (IOException exception) {
+ // Deliberately ignore IOException caused by broken
+ // pipe since plugin may have already detached.
+ }
+ AppletSecurityContextManager.dumpStore(0);
+ PluginDebug.debug("APPLETVIEWER: exiting appletviewer");
+ System.exit(0);
+ }
+*/
+ }
+ }
+ };
+
+ listenerThread.start();
+ }
+
+ public void handleMessage(String message) throws PluginException {
+
+ int nextIndex = 0;
+ int reference = -1;
+ String src = null;
+ String[] privileges = null;
+ String rest = "";
+
+ String[] msgComponents = message.split(" ");
+
+ if (msgComponents.length < 2)
+ return;
+
+ if (msgComponents[0].startsWith("plugin")) {
+ handlePluginMessage(message);
+ return;
+ }
+
+ // type and identifier are guaranteed to be there
+ String type = msgComponents[0];
+ final int identifier = Integer.parseInt(msgComponents[1]);
+ nextIndex = 2;
+
+ // reference, src and privileges are optional components,
+ // and are guaranteed to be in that order, if they occur
+
+ // is there a reference ?
+ if (msgComponents[nextIndex].equals("reference")) {
+ reference = Integer.parseInt(msgComponents[nextIndex+1]);
+ nextIndex += 2;
+ }
+
+ // is there a src?
+ if (msgComponents[nextIndex].equals("src")) {
+ src = msgComponents[nextIndex+1];
+ nextIndex += 2;
+ }
+
+ // is there a privileges?
+ if (msgComponents[nextIndex].equals("privileges")) {
+ String privs = msgComponents[nextIndex+1];
+ privileges = privs.split(",");
+ nextIndex += 2;
+ }
+
+ // rest
+ for (int i=nextIndex; i < msgComponents.length; i++) {
+ rest += msgComponents[i];
+ rest += " ";
+ }
+
+ rest = rest.trim();
+
+ try {
+
+ PluginDebug.debug("Breakdown -- type: " + type + " identifier: " + identifier + " reference: " + reference + " src: " + src + " privileges: " + privileges + " rest: \"" + rest + "\"");
+
+ if (rest.contains("JavaScriptGetWindow")
+ || rest.contains("JavaScriptGetMember")
+ || rest.contains("JavaScriptSetMember")
+ || rest.contains("JavaScriptGetSlot")
+ || rest.contains("JavaScriptSetSlot")
+ || rest.contains("JavaScriptEval")
+ || rest.contains("JavaScriptRemoveMember")
+ || rest.contains("JavaScriptCall")
+ || rest.contains("JavaScriptFinalize")
+ || rest.contains("JavaScriptToString")) {
+
+ finishCallRequest("reference " + reference + " " + rest);
+ return;
+ }
+
+ final int freference = reference;
+ final String frest = rest;
+
+ if (type.equals("instance")) {
+ PluginAppletViewer.handleMessage(identifier, freference,frest);
+ } else if (type.equals("context")) {
+ PluginDebug.debug("Sending to PASC: " + identifier + "/" + reference + " and " + rest);
+ AppletSecurityContextManager.handleMessage(identifier, reference, src, privileges, rest);
+ }
+ } catch (Exception e) {
+ throw new PluginException(this, identifier, reference, e);
+ }
+ }
+
+ private void handlePluginMessage(String message) {
+ if (message.equals("plugin showconsole")) {
+ showConsole();
+ } else if (message.equals("plugin hideconsole")) {
+ hideConsole();
+ } else {
+ // else this is something that was specifically requested
+ finishCallRequest(message);
+ }
+ }
+
+ public void postCallRequest(PluginCallRequest request) {
+ synchronized(queue) {
+ queue.post(request);
+ }
+ }
+
+ private void finishCallRequest(String message) {
+ PluginDebug.debug ("DISPATCHCALLREQUESTS 1");
+ synchronized(queue) {
+ PluginDebug.debug ("DISPATCHCALLREQUESTS 2");
+ PluginCallRequest request = queue.pop();
+
+ // make sure we give the message to the right request
+ // in the queue.. for the love of God, MAKE SURE!
+
+ // first let's be efficient.. if there was only one
+ // request in queue, we're already set
+ if (queue.size() != 0) {
+
+ int size = queue.size();
+ int count = 0;
+
+ while (!request.serviceable(message)) {
+
+ PluginDebug.debug(request + " cannot service " + message);
+
+ // something is very wrong.. we have a message to
+ // process, but no one to service it
+ if (count >= size) {
+ throw new RuntimeException("Unable to find processor for message " + message);
+ }
+
+ // post request at the end of the queue
+ queue.post(request);
+
+ // Look at the next request
+ request = queue.pop();
+
+ count++;
+ }
+
+ }
+
+ PluginDebug.debug ("DISPATCHCALLREQUESTS 3");
+ if (request != null) {
+ PluginDebug.debug ("DISPATCHCALLREQUESTS 5");
+ synchronized(request) {
+ request.parseReturn(message);
+ request.notifyAll();
+ }
+ PluginDebug.debug ("DISPATCHCALLREQUESTS 6");
+ PluginDebug.debug ("DISPATCHCALLREQUESTS 7");
+ }
+ }
+ PluginDebug.debug ("DISPATCHCALLREQUESTS 8");
+ }
+
+ /**
+ * Read string from plugin.
+ *
+ * @return the read string
+ *
+ * @exception IOException if an error occurs
+ */
+ private String read()
+ {
+ String message = null;
+
+ try {
+ message = pluginInputReader.readLine();
+ PluginDebug.debug(" PIPE: appletviewer read: " + message);
+
+ if (message == null || message.equals("shutdown")) {
+ synchronized(shuttingDown) {
+ shuttingDown = true;
+ }
+ try {
+ // Close input/output channels to plugin.
+ pluginInputReader.close();
+ pluginOutputWriter.close();
+ } catch (IOException exception) {
+ // Deliberately ignore IOException caused by broken
+ // pipe since plugin may have already detached.
+ }
+ AppletSecurityContextManager.dumpStore(0);
+ PluginDebug.debug("APPLETVIEWER: exiting appletviewer");
+ System.exit(0);
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ return message;
+ }
+
+ /**
+ * Write string to plugin.
+ *
+ * @param message the message to write
+ *
+ * @exception IOException if an error occurs
+ */
+ public void write(String message)
+ {
+
+ PluginDebug.debug(" PIPE: appletviewer wrote: " + message);
+ synchronized(pluginOutputWriter) {
+ try {
+ pluginOutputWriter.write(message + "\n", 0, message.length());
+ pluginOutputWriter.write(0);
+ pluginOutputWriter.flush();
+ } catch (IOException e) {
+ // if we are shutting down, ignore write failures as
+ // pipe may have closed
+ synchronized(shuttingDown) {
+ if (!shuttingDown) {
+ e.printStackTrace();
+ }
+ }
+
+ // either ways, if the pipe is broken, there is nothing
+ // we can do anymore. Don't hang around.
+ PluginDebug.debug("Unable to write to PIPE. APPLETVIEWER exiting");
+ System.exit(1);
+ }
+ }
+
+ return;
+ /*
+ synchronized(writeQueue) {
+ writeQueue.add(message);
+ PluginDebug.debug(" PIPE: appletviewer wrote: " + message);
+ }
+ */
+
+ }
+
+ public boolean messageAvailable() {
+ return writeQueue.size() != 0;
+ }
+
+ public String getMessage() {
+ synchronized(writeQueue) {
+ String ret = writeQueue.size() > 0 ? writeQueue.poll() : "";
+ return ret;
+ }
+ }
+
+ private void showConsole() {
+ SwingUtilities.invokeLater(new Runnable() {
+ public void run() {
+ console.showConsole();
+ }
+ });
+ }
+
+ private void hideConsole() {
+ SwingUtilities.invokeLater(new Runnable() {
+ public void run() {
+ console.hideConsole();
+ }
+ });
+ }
+}
diff --git a/plugin/icedteanp/java/sun/applet/RequestQueue.java b/plugin/icedteanp/java/sun/applet/RequestQueue.java
new file mode 100644
index 0000000..87dc54f
--- /dev/null
+++ b/plugin/icedteanp/java/sun/applet/RequestQueue.java
@@ -0,0 +1,77 @@
+/* VoidPluginCallRequest -- represent Java-to-JavaScript requests
+ Copyright (C) 2008 Red Hat
+
+This file is part of IcedTea.
+
+IcedTea is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+IcedTea is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with IcedTea; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package sun.applet;
+
+
+public class RequestQueue {
+ PluginCallRequest head = null;
+ PluginCallRequest tail = null;
+ private int size = 0;
+
+ public void post(PluginCallRequest request) {
+ PluginDebug.debug("Securitymanager=" + System.getSecurityManager());
+ if (head == null) {
+ head = tail = request;
+ tail.setNext(null);
+ } else {
+ tail.setNext(request);
+ tail = request;
+ tail.setNext(null);
+ }
+
+ size++;
+ }
+
+ public PluginCallRequest pop() {
+ if (head == null)
+ return null;
+
+ PluginCallRequest ret = head;
+ head = head.getNext();
+ ret.setNext(null);
+
+ size--;
+
+ return ret;
+ }
+
+ public int size() {
+ return size;
+ }
+}
diff --git a/plugin/icedteanp/java/sun/applet/TestEnv.java b/plugin/icedteanp/java/sun/applet/TestEnv.java
new file mode 100644
index 0000000..08b74ce
--- /dev/null
+++ b/plugin/icedteanp/java/sun/applet/TestEnv.java
@@ -0,0 +1,172 @@
+/* TestEnv -- test JavaScript-to-Java calls
+ Copyright (C) 2008 Red Hat
+
+This file is part of IcedTea.
+
+IcedTea is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+IcedTea is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with IcedTea; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package sun.applet;
+
+public class TestEnv
+{
+ public static int intField = 103;
+ public int intInstanceField = 7822;
+ public String stringField = "hello";
+ // z <musical G clef> <chinese water>
+ public String complexStringField = "z\uD834\uDD1E\u6C34";
+
+ public static void TestIt() {
+ PluginDebug.debug("TestIt");
+ }
+
+ public static void TestItBool(boolean arg) {
+ PluginDebug.debug("TestItBool: " + arg);
+ }
+
+ public static void TestItByte(byte arg) {
+ PluginDebug.debug("TestItByte: " + arg);
+ }
+
+ public static void TestItChar(char arg) {
+ PluginDebug.debug("TestItChar: " + arg);
+ }
+
+ public static void TestItShort(short arg) {
+ PluginDebug.debug("TestItShort: " + arg);
+ }
+
+ public static void TestItInt(int arg) {
+ PluginDebug.debug("TestItInt: " + arg);
+ }
+
+ public static void TestItLong(long arg) {
+ PluginDebug.debug("TestItLong: " + arg);
+ }
+
+ public static void TestItFloat(float arg) {
+ PluginDebug.debug("TestItFloat: " + arg);
+ }
+
+ public static void TestItDouble(double arg) {
+ PluginDebug.debug("TestItDouble: " + arg);
+ }
+
+ public static void TestItObject(TestEnv arg) {
+ PluginDebug.debug("TestItObject: " + arg);
+ }
+
+ public static void TestItObjectString(String arg) {
+ PluginDebug.debug("TestItObjectString: " + arg);
+ }
+
+ public static void TestItIntArray(int[] arg) {
+ PluginDebug.debug("TestItIntArray: " + arg);
+ for (int i = 0; i < arg.length; i++)
+ PluginDebug.debug ("ELEMENT: " + i + " " + arg[i]);
+ }
+
+ public static void TestItObjectArray(String[] arg) {
+ PluginDebug.debug("TestItObjectArray: " + arg);
+ for (int i = 0; i < arg.length; i++)
+ PluginDebug.debug ("ELEMENT: " + i + " " + arg[i]);
+ }
+
+ public static void TestItObjectArrayMulti(String[][] arg) {
+ PluginDebug.debug("TestItObjectArrayMulti: " + arg);
+ for (int i = 0; i < arg.length; i++)
+ for (int j = 0; j < arg[i].length; j++)
+ PluginDebug.debug ("ELEMENT: " + i + " " + j + " " + arg[i][j]);
+ }
+
+ public static boolean TestItBoolReturnTrue() {
+ return true;
+ }
+
+ public static boolean TestItBoolReturnFalse() {
+ return false;
+ }
+
+ public static byte TestItByteReturn() {
+ return (byte) 0xfe;
+ }
+
+ public static char TestItCharReturn() {
+ return 'K';
+ }
+
+ public static char TestItCharUnicodeReturn() {
+ return '\u6C34';
+ }
+
+ public static short TestItShortReturn() {
+ return 23;
+ }
+
+ public static int TestItIntReturn() {
+ return 3445;
+ }
+
+ public static long TestItLongReturn() {
+ return 3242883;
+ }
+
+ public static float TestItFloatReturn() {
+ return 9.21E4f;
+ }
+
+ public static double TestItDoubleReturn() {
+ return 8.33E88;
+ }
+
+ public static Object TestItObjectReturn() {
+ return new String("Thomas");
+ }
+
+ public static int[] TestItIntArrayReturn() {
+ return new int[] { 6, 7, 8 };
+ }
+
+ public static String[] TestItObjectArrayReturn() {
+ return new String[] { "Thomas", "Brigitte" };
+ }
+
+ public static String[][] TestItObjectArrayMultiReturn() {
+ return new String[][] { {"Thomas", "Brigitte"},
+ {"Lindsay", "Michael"} };
+ }
+
+ public int TestItIntInstance(int arg) {
+ PluginDebug.debug("TestItIntInstance: " + this + " " + arg);
+ return 899;
+ }
+}
diff --git a/plugin/icedteanp/java/sun/applet/VoidPluginCallRequest.java b/plugin/icedteanp/java/sun/applet/VoidPluginCallRequest.java
new file mode 100644
index 0000000..0bacc6c
--- /dev/null
+++ b/plugin/icedteanp/java/sun/applet/VoidPluginCallRequest.java
@@ -0,0 +1,54 @@
+/* VoidPluginCallRequest -- represent Java-to-JavaScript requests
+ Copyright (C) 2008 Red Hat
+
+This file is part of IcedTea.
+
+IcedTea is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+IcedTea is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with IcedTea; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package sun.applet;
+
+
+public class VoidPluginCallRequest extends PluginCallRequest {
+ public VoidPluginCallRequest(String message, Long reference) {
+ super(message, reference);
+ PluginDebug.debug ("VoidPluginCall " + message);
+ }
+
+ public void parseReturn(String message) {
+ setDone(true);
+ }
+
+ public Object getObject() {
+ return null;
+ }
+}