diff options
Diffstat (limited to 'netx/net/sourceforge/jnlp/runtime/ApplicationInstance.java')
-rw-r--r-- | netx/net/sourceforge/jnlp/runtime/ApplicationInstance.java | 319 |
1 files changed, 319 insertions, 0 deletions
diff --git a/netx/net/sourceforge/jnlp/runtime/ApplicationInstance.java b/netx/net/sourceforge/jnlp/runtime/ApplicationInstance.java new file mode 100644 index 0000000..95ccb1e --- /dev/null +++ b/netx/net/sourceforge/jnlp/runtime/ApplicationInstance.java @@ -0,0 +1,319 @@ +// Copyright (C) 2001-2003 Jon A. Maxwell (JAM) +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + +package net.sourceforge.jnlp.runtime; + +import java.awt.Window; +import java.net.URL; +import java.security.AccessControlContext; +import java.security.AccessController; +import java.security.CodeSource; +import java.security.PrivilegedAction; +import java.security.ProtectionDomain; + +import javax.swing.event.EventListenerList; + +import sun.awt.AppContext; + +import net.sourceforge.jnlp.JNLPFile; +import net.sourceforge.jnlp.PropertyDesc; +import net.sourceforge.jnlp.SecurityDesc; +import net.sourceforge.jnlp.ShortcutDesc; +import net.sourceforge.jnlp.event.ApplicationEvent; +import net.sourceforge.jnlp.event.ApplicationListener; +import net.sourceforge.jnlp.security.SecurityWarningDialog.AccessType; +import net.sourceforge.jnlp.services.ServiceUtil; +import net.sourceforge.jnlp.util.WeakList; +import net.sourceforge.jnlp.util.XDesktopEntry; + +/** + * Represents a running instance of an application described in a + * JNLPFile. This class provides a way to track the application's + * resources and destroy the application.<p> + * + * @author <a href="mailto:[email protected]">Jon A. Maxwell (JAM)</a> - initial author + * @version $Revision: 1.15 $ + */ +public class ApplicationInstance { + + // todo: should attempt to unload the environment variables + // installed by the application. + + + /** the file */ + private JNLPFile file; + + /** the thread group */ + private ThreadGroup group; + + /** the classloader */ + private ClassLoader loader; + + /** + * Every application/applet gets its own AppContext. This allows us to do + * things like have two different look and feels for two different applets + * (running in the same VM), allows untrusted programs to manipulate the + * event queue (safely) and (possibly) more.<p> + * + * It is set to the AppContext which created this ApplicationInstance + */ + private AppContext appContext; + + /** whether the application has stopped running */ + private boolean stopped = false; + + /** weak list of windows opened by the application */ + private WeakList weakWindows = new WeakList(); + + /** list of application listeners */ + private EventListenerList listeners = new EventListenerList(); + + /** whether or not this application is signed */ + private boolean isSigned = false; + + /** + * Create an application instance for the file. This should be done in the + * appropriate {@link ThreadGroup} only. + */ + public ApplicationInstance(JNLPFile file, ThreadGroup group, ClassLoader loader) { + this.file = file; + this.group = group; + this.loader = loader; + this.isSigned = ((JNLPClassLoader) loader).getSigning(); + this.appContext = AppContext.getAppContext(); + } + + /** + * Add an Application listener + */ + public void addApplicationListener(ApplicationListener listener) { + listeners.add(ApplicationListener.class, listener); + } + + /** + * Remove an Application Listener + */ + public void removeApplicationListener(ApplicationListener listener) { + listeners.remove(ApplicationListener.class, listener); + } + + /** + * Notify listeners that the application has been terminated. + */ + protected void fireDestroyed() { + Object list[] = listeners.getListenerList(); + ApplicationEvent event = null; + + for (int i=list.length-1; i>0; i-=2) { // last to first required + if (event == null) + event = new ApplicationEvent(this); + + ((ApplicationListener)list[i]).applicationDestroyed(event); + } + } + + /** + * Initialize the application's environment (installs + * environment variables, etc). + */ + public void initialize() { + installEnvironment(); + + //Fixme: -Should check whether a desktop entry already exists for + // for this jnlp file, and do nothing if it exists. + // -If no href is specified in the jnlp tag, it should + // default to using the one passed in as an argument. + addMenuAndDesktopEntries(); + } + + /** + * Creates menu and desktop entries if required by the jnlp file + */ + + private void addMenuAndDesktopEntries() { + XDesktopEntry entry = new XDesktopEntry(file); + ShortcutDesc sd = file.getInformation().getShortcut(); + + if (sd != null && sd.onDesktop()) { + if (ServiceUtil.checkAccess(this, AccessType.CREATE_DESTKOP_SHORTCUT)) { + entry.createDesktopShortcut(); + } + } + + if (sd != null && sd.getMenu() != null) { + /* + * Sun's WebStart implementation doesnt seem to do anything under GNOME + */ + if (JNLPRuntime.isDebug()) { + System.err.println("ApplicationInstance.addMenuAndDesktopEntries():" + + " Adding menu entries NOT IMPLEMENTED"); + } + } + + } + + /** + * Releases the application's resources before it is collected. + * Only collectable if classloader and thread group are + * also collectable so basically is almost never called (an + * application would have to close its windows and exit its + * threads but not call System.exit). + */ + public void finalize() { + destroy(); + } + + /** + * Install the environment variables. + */ + void installEnvironment() { + final PropertyDesc props[] = file.getResources().getProperties(); + + CodeSource cs = new CodeSource((URL) null, (java.security.cert.Certificate [])null); + + JNLPClassLoader loader = (JNLPClassLoader) this.loader; + SecurityDesc s = loader.getSecurity(); + + ProtectionDomain pd = new ProtectionDomain(cs, s.getPermissions(), null, null); + + // Add to hashmap + AccessControlContext acc = new AccessControlContext(new ProtectionDomain[] {pd}); + + PrivilegedAction installProps = new PrivilegedAction() { + public Object run() { + for (int i=0; i < props.length; i++) { + System.setProperty(props[i].getKey(), props[i].getValue()); + } + + return null; + } + }; + AccessController.doPrivileged(installProps, acc); + } + + /** + * Returns the JNLP file for this task. + */ + public JNLPFile getJNLPFile() { + return file; + } + + /** + * Returns the application title. + */ + public String getTitle() { + return file.getTitle(); + } + + /** + * Returns whether the application is running. + */ + public boolean isRunning() { + return !stopped; + } + + /** + * Stop the application and destroy its resources. + */ + public void destroy() { + if (stopped) + return; + + try { + // destroy resources + for (int i=0; i < weakWindows.size(); i++) { + Window w = (Window) weakWindows.get(i); + if (w != null) + w.dispose(); + } + + weakWindows.clear(); + + // interrupt threads + Thread threads[] = new Thread[ group.activeCount() * 2 ]; + int nthreads = group.enumerate(threads); + for (int i=0; i < nthreads; i++) { + if (JNLPRuntime.isDebug()) + System.out.println("Interrupt thread: "+threads[i]); + + threads[i].interrupt(); + } + + // then stop + Thread.currentThread().yield(); + nthreads = group.enumerate(threads); + for (int i=0; i < nthreads; i++) { + if (JNLPRuntime.isDebug()) + System.out.println("Stop thread: "+threads[i]); + + threads[i].stop(); + } + + // then destroy - except Thread.destroy() not implemented in jdk + + } + finally { + stopped = true; + fireDestroyed(); + } + } + + /** + * Returns the thread group. + * + * @throws IllegalStateException if the app is not running + */ + public ThreadGroup getThreadGroup() throws IllegalStateException { + if (stopped) + throw new IllegalStateException(); + + return group; + } + + /** + * Returns the classloader. + * + * @throws IllegalStateException if the app is not running + */ + public ClassLoader getClassLoader() throws IllegalStateException { + if (stopped) + throw new IllegalStateException(); + + return loader; + } + + /** + * Adds a window that this application opened. When the + * application is disposed, these windows will also be disposed. + */ + protected void addWindow(Window window) { + weakWindows.add(window); + weakWindows.trimToSize(); + } + + /** + * Returns whether or not this jar is signed. + */ + public boolean isSigned() { + return isSigned; + } + + public AppContext getAppContext() { + return appContext; + } + +} |