| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to you under the Apache License, |
| * Version 2.0 (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.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.apache.pivot.wtk; |
| |
| import java.applet.Applet; |
| import java.awt.Graphics; |
| import java.io.File; |
| import java.io.UnsupportedEncodingException; |
| import java.net.MalformedURLException; |
| import java.net.URL; |
| import java.net.URLDecoder; |
| import java.util.Locale; |
| |
| import netscape.javascript.JSObject; |
| |
| import org.apache.pivot.collections.ArrayList; |
| import org.apache.pivot.collections.HashMap; |
| import org.apache.pivot.collections.immutable.ImmutableMap; |
| |
| /** |
| * Application context used to execute applications in a web browser. |
| */ |
| @SuppressWarnings("restriction") |
| public final class BrowserApplicationContext extends ApplicationContext { |
| /** |
| * Applet used to host applications in a web browser. <p> This applet |
| * supports the following parameters: <ul> |
| * <li><tt>application_class_name</tt> - the class name of the application |
| * to launch.</li> <li><tt>startup_properties</tt> - startup properties to |
| * be passed to the application. Properties use HTTP query string syntax; |
| * e.g. "a=1&b=2".</li> <li><tt>system_properties</tt> - system properties |
| * to set at startup. Properties use HTTP query string syntax; e.g. |
| * "a=1&b=2" (trusted applets only).</li> </ul> |
| */ |
| public static final class HostApplet extends Applet { |
| private static final long serialVersionUID = -7710026348576806673L; |
| |
| private class InitCallback implements Runnable { |
| public InitCallback() { |
| } |
| |
| @Override |
| public void run() { |
| // Set the origin |
| URL codeBase = getCodeBase(); |
| if (codeBase != null) { |
| if (codeBase.getProtocol().equals("file")) { |
| File userHome = null; |
| try { |
| userHome = new File(System.getProperty("user.home")); |
| } catch (SecurityException exception) { |
| // No-op |
| } |
| |
| if (userHome != null) { |
| try { |
| origin = userHome.toURI().toURL(); |
| } catch (MalformedURLException exception) { |
| // No-op |
| } |
| } |
| } else { |
| try { |
| origin = new URL(codeBase.getProtocol(), codeBase.getHost(), |
| codeBase.getPort(), ""); |
| } catch (MalformedURLException exception) { |
| // No-op |
| } |
| } |
| } |
| |
| // Load properties specified in the system properties parameter |
| String systemPropertiesParameter = getParameter(SYSTEM_PROPERTIES_PARAMETER); |
| if (systemPropertiesParameter != null) { |
| String[] arguments = systemPropertiesParameter.split("&"); |
| |
| String language = null; |
| String region = null; |
| |
| for (int i = 0, n = arguments.length; i < n; i++) { |
| String argument = arguments[i]; |
| String[] property = argument.split("="); |
| |
| if (property.length == 2) { |
| String key = property[0].trim(); |
| String value; |
| try { |
| value = URLDecoder.decode(property[1].trim(), "UTF-8"); |
| } catch (UnsupportedEncodingException exception) { |
| throw new RuntimeException(exception); |
| } |
| |
| if (key.equals("user.language")) { |
| language = value; |
| } else if (key.equals("user.region")) { |
| region = value; |
| } else { |
| System.setProperty(key, value); |
| } |
| } else { |
| System.err.println(argument + " is not a valid system property."); |
| } |
| } |
| |
| if (language != null) { |
| Locale.setDefault((region == null) ? new Locale(language) : new Locale( |
| language, region)); |
| } |
| } |
| |
| // Load properties specified in the startup properties parameter |
| HostApplet.this.startupProperties = new HashMap<>(); |
| |
| String startupPropertiesParameter = getParameter(STARTUP_PROPERTIES_PARAMETER); |
| if (startupPropertiesParameter != null) { |
| String[] arguments = startupPropertiesParameter.split("&"); |
| |
| for (int i = 0, n = arguments.length; i < n; i++) { |
| String argument = arguments[i]; |
| String[] property = argument.split("="); |
| |
| if (property.length == 2) { |
| String key = property[0].trim(); |
| String value; |
| try { |
| value = URLDecoder.decode(property[1].trim(), "UTF-8"); |
| } catch (UnsupportedEncodingException exception) { |
| throw new RuntimeException(exception); |
| } |
| HostApplet.this.startupProperties.put(key, value); |
| } else { |
| System.err.println(argument + " is not a valid startup property."); |
| } |
| } |
| } |
| |
| // Create the display host |
| HostApplet.this.displayHost = new DisplayHost(); |
| setLayout(new java.awt.BorderLayout()); |
| add(HostApplet.this.displayHost); |
| |
| // Add the display to the display list |
| displays.add(HostApplet.this.displayHost.getDisplay()); |
| |
| // Disable focus traversal keys |
| setFocusTraversalKeysEnabled(false); |
| |
| // Let pivot manage the focus inside the applet, where we have |
| // only one AWT component |
| setFocusTraversalPolicyProvider(true); |
| setFocusCycleRoot(true); |
| setFocusTraversalPolicy(new java.awt.FocusTraversalPolicy() { |
| @Override |
| public java.awt.Component getLastComponent(java.awt.Container aContainer) { |
| return null; |
| } |
| |
| @Override |
| public java.awt.Component getFirstComponent(java.awt.Container aContainer) { |
| return null; |
| } |
| |
| @Override |
| public java.awt.Component getDefaultComponent(java.awt.Container aContainer) { |
| return null; |
| } |
| |
| @Override |
| public java.awt.Component getComponentBefore(java.awt.Container aContainer, |
| java.awt.Component aComponent) { |
| return HostApplet.this.displayHost; |
| } |
| |
| @Override |
| public java.awt.Component getComponentAfter(java.awt.Container aContainer, |
| java.awt.Component aComponent) { |
| return HostApplet.this.displayHost; |
| } |
| }); |
| |
| // Clear the background |
| setBackground(null); |
| |
| // Start the timer and add this applet to the host applet list |
| if (hostApplets.getLength() == 0) { |
| createTimer(); |
| } |
| |
| hostApplets.add(HostApplet.this); |
| |
| // Load the application |
| String applicationClassName = getParameter(APPLICATION_CLASS_NAME_PARAMETER); |
| if (applicationClassName == null) { |
| System.err.println(APPLICATION_CLASS_NAME_PARAMETER + " parameter is required."); |
| } else { |
| try { |
| Class<?> applicationClass = Class.forName(applicationClassName); |
| HostApplet.this.application = (Application) applicationClass.newInstance(); |
| } catch (Throwable throwable) { |
| throwable.printStackTrace(); |
| } |
| } |
| } |
| } |
| |
| private class StartCallback implements Runnable { |
| public StartCallback() { |
| } |
| |
| @Override |
| public void run() { |
| // Start the application |
| if (HostApplet.this.application != null) { |
| // Add the application to the application list |
| applications.add(HostApplet.this.application); |
| |
| try { |
| HostApplet.this.application.startup( |
| HostApplet.this.displayHost.getDisplay(), new ImmutableMap<>( |
| HostApplet.this.startupProperties)); |
| } catch (Throwable exception) { |
| handleUncaughtException(exception); |
| } |
| } |
| } |
| } |
| |
| private class StopCallback implements Runnable { |
| public StopCallback() { |
| } |
| |
| @Override |
| public void run() { |
| if (HostApplet.this.application != null) { |
| try { |
| HostApplet.this.application.shutdown(false); |
| } catch (Throwable exception) { |
| handleUncaughtException(exception); |
| } finally { |
| // Remove the application from the application list |
| applications.remove(HostApplet.this.application); |
| HostApplet.this.application = null; |
| } |
| } |
| } |
| } |
| |
| private class DestroyCallback implements Runnable { |
| public DestroyCallback() { |
| } |
| |
| @Override |
| public void run() { |
| // Remove the display from the display list |
| displays.remove(HostApplet.this.displayHost.getDisplay()); |
| |
| // Remove this applet from the host applets list and stop the |
| // timer |
| hostApplets.remove(HostApplet.this); |
| |
| if (hostApplets.getLength() == 0) { |
| destroyTimer(); |
| } |
| } |
| } |
| |
| private DisplayHost displayHost = null; |
| private Application application = null; |
| private HashMap<String, String> startupProperties = null; |
| |
| public static final String APPLICATION_CLASS_NAME_PARAMETER = "application_class_name"; |
| public static final String STARTUP_PROPERTIES_PARAMETER = "startup_properties"; |
| public static final String SYSTEM_PROPERTIES_PARAMETER = "system_properties"; |
| |
| public Application getApplication() { |
| return this.application; |
| } |
| |
| @Override |
| public void init() { |
| InitCallback initCallback = new InitCallback(); |
| |
| if (java.awt.EventQueue.isDispatchThread()) { |
| initCallback.run(); |
| } else { |
| queueCallback(initCallback, true); |
| } |
| } |
| |
| @Override |
| public void start() { |
| StartCallback startCallback = new StartCallback(); |
| |
| if (java.awt.EventQueue.isDispatchThread()) { |
| startCallback.run(); |
| } else { |
| queueCallback(startCallback, true); |
| } |
| } |
| |
| @Override |
| public void stop() { |
| StopCallback stopCallback = new StopCallback(); |
| |
| if (java.awt.EventQueue.isDispatchThread()) { |
| stopCallback.run(); |
| } else { |
| queueCallback(stopCallback, true); |
| } |
| } |
| |
| @Override |
| public void destroy() { |
| DestroyCallback destroyCallback = new DestroyCallback(); |
| |
| if (java.awt.EventQueue.isDispatchThread()) { |
| destroyCallback.run(); |
| } else { |
| queueCallback(destroyCallback, true); |
| } |
| } |
| |
| @Override |
| public void update(Graphics graphics) { |
| paint(graphics); |
| } |
| |
| } |
| |
| private static ArrayList<HostApplet> hostApplets = new ArrayList<>(); |
| |
| public static boolean isActive() { |
| return (hostApplets.getLength() > 0); |
| } |
| |
| /** |
| * Retrieves a named application. |
| * |
| * @param name The name of the applet hosting the application. |
| * @return The application being run in the given applet (if any). |
| * @throws IllegalArgumentException if the name is {@code null}. |
| */ |
| public static Application getApplication(String name) { |
| if (name == null) { |
| throw new IllegalArgumentException("name is null."); |
| } |
| |
| Application application = null; |
| for (HostApplet hostApplet : hostApplets) { |
| if (hostApplet.getName().equals(name)) { |
| application = hostApplet.getApplication(); |
| break; |
| } |
| } |
| |
| return application; |
| } |
| |
| /** |
| * Evaluates a script in the page context and returns the result. |
| * |
| * @param script The script to be run. |
| * @param application The application used to find the correct applet. |
| * @return The result of the script evaluation. |
| */ |
| public static Object eval(String script, Application application) { |
| if (application == null) { |
| throw new IllegalArgumentException("application is null."); |
| } |
| |
| HostApplet applicationHostApplet = null; |
| for (HostApplet hostApplet : hostApplets) { |
| if (hostApplet.getApplication() == application) { |
| applicationHostApplet = hostApplet; |
| break; |
| } |
| } |
| |
| if (applicationHostApplet == null) { |
| throw new IllegalArgumentException("No applet is hosting the given application."); |
| } |
| |
| try { |
| JSObject window = JSObject.getWindow(applicationHostApplet); |
| return window.eval(script); |
| } catch (Throwable throwable) { |
| throw new UnsupportedOperationException(throwable); |
| } |
| } |
| |
| } |