Logo Search packages:      
Sourcecode: icedtea-web version File versions  Download package

ApplicationInstance.java

// 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:jmaxwell@users.sourceforge.net">Jon A. Maxwell (JAM)</a> - initial author
 * @version $Revision: 1.15 $
 */
00051 public class ApplicationInstance {

    // todo: should attempt to unload the environment variables
    // installed by the application.


    /** the file */
00058     private JNLPFile file;

    /** the thread group */
00061     private ThreadGroup group;

    /** the classloader */
00064     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
     */
00074     private AppContext appContext;

    /** whether the application has stopped running */
00077     private boolean stopped = false;

    /** weak list of windows opened by the application */
00080     private WeakList weakWindows = new WeakList();

    /** list of application listeners  */
00083     private EventListenerList listeners = new EventListenerList();

        /** whether or not this application is signed */
00086         private boolean isSigned = false;

    /**
     * Create an application instance for the file. This should be done in the
     * appropriate {@link ThreadGroup} only.
     */
00092     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
     */
00103     public void addApplicationListener(ApplicationListener listener) {
        listeners.add(ApplicationListener.class, listener);
    }

    /**
     * Remove an Application Listener
     */
00110     public void removeApplicationListener(ApplicationListener listener) {
        listeners.remove(ApplicationListener.class, listener);
    }

    /**
     * Notify listeners that the application has been terminated.
     */
00117     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).
     */
00133     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
     */

00147     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).
     */
00176     public void finalize() {
        destroy();
    }

    /**
     * Install the environment variables.
     */
00183     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.
     */
00211     public JNLPFile getJNLPFile() {
        return file;
    }

    /**
     * Returns the application title.
     */
00218     public String getTitle() {
        return file.getTitle();
    }

    /**
     * Returns whether the application is running.
     */
00225     public boolean isRunning() {
        return !stopped;
    }

    /**
     * Stop the application and destroy its resources.
     */
00232     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
     */
00280     public ThreadGroup getThreadGroup() throws IllegalStateException {
        if (stopped)
            throw new IllegalStateException();

        return group;
    }

    /**
     * Returns the classloader.
     *
     * @throws IllegalStateException if the app is not running
     */
00292     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.
     */
00303     protected void addWindow(Window window) {
        weakWindows.add(window);
        weakWindows.trimToSize();
    }

        /**
         * Returns whether or not this jar is signed.
         */
00311         public boolean isSigned() {
                return isSigned;
        }

    public AppContext getAppContext() {
        return appContext;
    }

}

Generated by  Doxygen 1.6.0   Back to index