jdk/src/share/classes/sun/applet/AppletPanel.java
changeset 2 90ce3da70b43
child 438 2ae294e4518c
equal deleted inserted replaced
0:fd16c54261b3 2:90ce3da70b43
       
     1 /*
       
     2  * Copyright 1995-2007 Sun Microsystems, Inc.  All Rights Reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.  Sun designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Sun in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
       
    22  * CA 95054 USA or visit www.sun.com if you need additional information or
       
    23  * have any questions.
       
    24  */
       
    25 
       
    26 package sun.applet;
       
    27 
       
    28 import java.applet.*;
       
    29 import java.awt.*;
       
    30 import java.awt.event.*;
       
    31 import java.awt.image.ColorModel;
       
    32 import java.awt.image.MemoryImageSource;
       
    33 import java.io.*;
       
    34 import java.lang.ref.WeakReference;
       
    35 import java.lang.reflect.InvocationTargetException;
       
    36 import java.lang.reflect.Method;
       
    37 import java.net.InetAddress;
       
    38 import java.net.JarURLConnection;
       
    39 import java.net.MalformedURLException;
       
    40 import java.net.SocketPermission;
       
    41 import java.net.URL;
       
    42 import java.net.UnknownHostException;
       
    43 import java.security.*;
       
    44 import java.util.*;
       
    45 import java.util.Collections;
       
    46 import java.util.Locale;
       
    47 import java.util.WeakHashMap;
       
    48 import javax.swing.SwingUtilities;
       
    49 import sun.awt.AppContext;
       
    50 import sun.awt.EmbeddedFrame;
       
    51 import sun.awt.SunToolkit;
       
    52 import sun.misc.MessageUtils;
       
    53 import sun.misc.PerformanceLogger;
       
    54 import sun.misc.Queue;
       
    55 import sun.security.util.SecurityConstants;
       
    56 
       
    57 /**
       
    58  * Applet panel class. The panel manages and manipulates the
       
    59  * applet as it is being loaded. It forks a separate thread in a new
       
    60  * thread group to call the applet's init(), start(), stop(), and
       
    61  * destroy() methods.
       
    62  *
       
    63  * @author      Arthur van Hoff
       
    64  */
       
    65 public
       
    66 abstract class AppletPanel extends Panel implements AppletStub, Runnable {
       
    67 
       
    68     /**
       
    69      * The applet (if loaded).
       
    70      */
       
    71     Applet applet;
       
    72 
       
    73     /**
       
    74      * Applet will allow initialization.  Should be
       
    75      * set to false if loading a serialized applet
       
    76      * that was pickled in the init=true state.
       
    77      */
       
    78     protected boolean doInit = true;
       
    79 
       
    80 
       
    81     /**
       
    82      * The classloader for the applet.
       
    83      */
       
    84     AppletClassLoader loader;
       
    85 
       
    86     /* applet event ids */
       
    87     public final static int APPLET_DISPOSE = 0;
       
    88     public final static int APPLET_LOAD = 1;
       
    89     public final static int APPLET_INIT = 2;
       
    90     public final static int APPLET_START = 3;
       
    91     public final static int APPLET_STOP = 4;
       
    92     public final static int APPLET_DESTROY = 5;
       
    93     public final static int APPLET_QUIT = 6;
       
    94     public final static int APPLET_ERROR = 7;
       
    95 
       
    96     /* send to the parent to force relayout */
       
    97     public final static int APPLET_RESIZE = 51234;
       
    98 
       
    99     /* sent to a (distant) parent to indicate that the applet is being
       
   100      * loaded or as completed loading
       
   101      */
       
   102     public final static int APPLET_LOADING = 51235;
       
   103     public final static int APPLET_LOADING_COMPLETED = 51236;
       
   104 
       
   105     /**
       
   106      * The current status. One of:
       
   107      *    APPLET_DISPOSE,
       
   108      *    APPLET_LOAD,
       
   109      *    APPLET_INIT,
       
   110      *    APPLET_START,
       
   111      *    APPLET_STOP,
       
   112      *    APPLET_DESTROY,
       
   113      *    APPLET_ERROR.
       
   114      */
       
   115     protected int status;
       
   116 
       
   117     /**
       
   118      * The thread for the applet.
       
   119      */
       
   120     Thread handler;
       
   121 
       
   122 
       
   123     /**
       
   124      * The initial applet size.
       
   125      */
       
   126     Dimension defaultAppletSize = new Dimension(10, 10);
       
   127 
       
   128     /**
       
   129      * The current applet size.
       
   130      */
       
   131     Dimension currentAppletSize = new Dimension(10, 10);
       
   132 
       
   133     MessageUtils mu = new MessageUtils();
       
   134 
       
   135     /**
       
   136      * The thread to use during applet loading
       
   137      */
       
   138 
       
   139     Thread loaderThread = null;
       
   140 
       
   141     /**
       
   142      * Flag to indicate that a loading has been cancelled
       
   143      */
       
   144     boolean loadAbortRequest = false;
       
   145 
       
   146     /* abstract classes */
       
   147     abstract protected String getCode();
       
   148     abstract protected String getJarFiles();
       
   149     abstract protected String getSerializedObject();
       
   150 
       
   151     abstract public int    getWidth();
       
   152     abstract public int    getHeight();
       
   153     abstract public boolean hasInitialFocus();
       
   154 
       
   155     private static int threadGroupNumber = 0;
       
   156 
       
   157     protected void setupAppletAppContext() {
       
   158         // do nothing
       
   159     }
       
   160 
       
   161     /*
       
   162      * Creates a thread to run the applet. This method is called
       
   163      * each time an applet is loaded and reloaded.
       
   164      */
       
   165     synchronized void createAppletThread() {
       
   166         // Create a thread group for the applet, and start a new
       
   167         // thread to load the applet.
       
   168         String nm = "applet-" + getCode();
       
   169         loader = getClassLoader(getCodeBase(), getClassLoaderCacheKey());
       
   170         loader.grab(); // Keep this puppy around!
       
   171 
       
   172         // 4668479: Option to turn off codebase lookup in AppletClassLoader
       
   173         // during resource requests. [stanley.ho]
       
   174         String param = getParameter("codebase_lookup");
       
   175 
       
   176         if (param != null && param.equals("false"))
       
   177             loader.setCodebaseLookup(false);
       
   178         else
       
   179             loader.setCodebaseLookup(true);
       
   180 
       
   181 
       
   182         ThreadGroup appletGroup = loader.getThreadGroup();
       
   183 
       
   184         handler = new Thread(appletGroup, this, "thread " + nm);
       
   185         // set the context class loader for this thread
       
   186         AccessController.doPrivileged(new PrivilegedAction() {
       
   187                 public Object run() {
       
   188                     handler.setContextClassLoader(loader);
       
   189                     return null;
       
   190                 }
       
   191             });
       
   192         handler.start();
       
   193     }
       
   194 
       
   195     void joinAppletThread() throws InterruptedException {
       
   196         if (handler != null) {
       
   197             handler.join();
       
   198             handler = null;
       
   199         }
       
   200     }
       
   201 
       
   202     void release() {
       
   203         if (loader != null) {
       
   204             loader.release();
       
   205             loader = null;
       
   206         }
       
   207     }
       
   208 
       
   209     /**
       
   210      * Construct an applet viewer and start the applet.
       
   211      */
       
   212     public void init() {
       
   213         try {
       
   214             // Get the width (if any)
       
   215             defaultAppletSize.width = getWidth();
       
   216             currentAppletSize.width = defaultAppletSize.width;
       
   217 
       
   218             // Get the height (if any)
       
   219             defaultAppletSize.height = getHeight();
       
   220             currentAppletSize.height = defaultAppletSize.height;
       
   221 
       
   222         } catch (NumberFormatException e) {
       
   223             // Turn on the error flag and let TagAppletPanel
       
   224             // do the right thing.
       
   225             status = APPLET_ERROR;
       
   226             showAppletStatus("badattribute.exception");
       
   227             showAppletLog("badattribute.exception");
       
   228             showAppletException(e);
       
   229         }
       
   230 
       
   231         setLayout(new BorderLayout());
       
   232 
       
   233         createAppletThread();
       
   234     }
       
   235 
       
   236     /**
       
   237      * Minimum size
       
   238      */
       
   239     public Dimension minimumSize() {
       
   240         return new Dimension(defaultAppletSize.width,
       
   241                              defaultAppletSize.height);
       
   242     }
       
   243 
       
   244     /**
       
   245      * Preferred size
       
   246      */
       
   247     public Dimension preferredSize() {
       
   248         return new Dimension(currentAppletSize.width,
       
   249                              currentAppletSize.height);
       
   250     }
       
   251 
       
   252     private AppletListener listeners;
       
   253 
       
   254     /**
       
   255      * AppletEvent Queue
       
   256      */
       
   257     private Queue queue = null;
       
   258 
       
   259 
       
   260     synchronized public void addAppletListener(AppletListener l) {
       
   261         listeners = AppletEventMulticaster.add(listeners, l);
       
   262     }
       
   263 
       
   264     synchronized public void removeAppletListener(AppletListener l) {
       
   265         listeners = AppletEventMulticaster.remove(listeners, l);
       
   266     }
       
   267 
       
   268     /**
       
   269      * Dispatch event to the listeners..
       
   270      */
       
   271     public void dispatchAppletEvent(int id, Object argument) {
       
   272         //System.out.println("SEND= " + id);
       
   273         if (listeners != null) {
       
   274             AppletEvent evt = new AppletEvent(this, id, argument);
       
   275             listeners.appletStateChanged(evt);
       
   276         }
       
   277     }
       
   278 
       
   279     /**
       
   280      * Send an event. Queue it for execution by the handler thread.
       
   281      */
       
   282     public void sendEvent(int id) {
       
   283         synchronized(this) {
       
   284             if (queue == null) {
       
   285                 //System.out.println("SEND0= " + id);
       
   286                 queue = new Queue();
       
   287             }
       
   288             Integer eventId = new Integer(id);
       
   289             queue.enqueue(eventId);
       
   290             notifyAll();
       
   291         }
       
   292         if (id == APPLET_QUIT) {
       
   293             try {
       
   294                 joinAppletThread(); // Let the applet event handler exit
       
   295             } catch (InterruptedException e) {
       
   296             }
       
   297 
       
   298             // AppletClassLoader.release() must be called by a Thread
       
   299             // not within the applet's ThreadGroup
       
   300             if (loader == null)
       
   301                 loader = getClassLoader(getCodeBase(), getClassLoaderCacheKey());
       
   302             release();
       
   303         }
       
   304     }
       
   305 
       
   306     /**
       
   307      * Get an event from the queue.
       
   308      */
       
   309     synchronized AppletEvent getNextEvent() throws InterruptedException {
       
   310         while (queue == null || queue.isEmpty()) {
       
   311             wait();
       
   312         }
       
   313         Integer eventId = (Integer)queue.dequeue();
       
   314         return new AppletEvent(this, eventId.intValue(), null);
       
   315     }
       
   316 
       
   317     boolean emptyEventQueue() {
       
   318         if ((queue == null) || (queue.isEmpty()))
       
   319             return true;
       
   320         else
       
   321             return false;
       
   322     }
       
   323 
       
   324     /**
       
   325      * This kludge is specific to get over AccessControlException thrown during
       
   326      * Applet.stop() or destroy() when static thread is suspended.  Set a flag
       
   327      * in AppletClassLoader to indicate that an
       
   328      * AccessControlException for RuntimePermission "modifyThread" or
       
   329      * "modifyThreadGroup" had occurred.
       
   330      */
       
   331      private void setExceptionStatus(AccessControlException e) {
       
   332      Permission p = e.getPermission();
       
   333      if (p instanceof RuntimePermission) {
       
   334          if (p.getName().startsWith("modifyThread")) {
       
   335              if (loader == null)
       
   336                  loader = getClassLoader(getCodeBase(), getClassLoaderCacheKey());
       
   337              loader.setExceptionStatus();
       
   338          }
       
   339      }
       
   340      }
       
   341 
       
   342     /**
       
   343      * Execute applet events.
       
   344      * Here is the state transition diagram
       
   345      *
       
   346      *   Note: (XXX) is the action
       
   347      *         APPLET_XXX is the state
       
   348      *  (applet code loaded) --> APPLET_LOAD -- (applet init called)--> APPLET_INIT -- (
       
   349      *   applet start called) --> APPLET_START -- (applet stop called) -->APPLET_STOP --(applet
       
   350      *   destroyed called) --> APPLET_DESTROY -->(applet gets disposed) -->
       
   351      *   APPLET_DISPOSE -->....
       
   352      *
       
   353      * In the legacy lifecycle model. The applet gets loaded, inited and started. So it stays
       
   354      * in the APPLET_START state unless the applet goes away(refresh page or leave the page).
       
   355      * So the applet stop method called and the applet enters APPLET_STOP state. Then if the applet
       
   356      * is revisited, it will call applet start method and enter the APPLET_START state and stay there.
       
   357      *
       
   358      * In the modern lifecycle model. When the applet first time visited, it is same as legacy lifecycle
       
   359      * model. However, when the applet page goes away. It calls applet stop method and enters APPLET_STOP
       
   360      * state and then applet destroyed method gets called and enters APPLET_DESTROY state.
       
   361      *
       
   362      * This code is also called by AppletViewer. In AppletViewer "Restart" menu, the applet is jump from
       
   363      * APPLET_STOP to APPLET_DESTROY and to APPLET_INIT .
       
   364      *
       
   365      * Also, the applet can jump from APPLET_INIT state to APPLET_DESTROY (in Netscape/Mozilla case).
       
   366          * Same as APPLET_LOAD to
       
   367      * APPLET_DISPOSE since all of this are triggered by browser.
       
   368      *
       
   369      *
       
   370      */
       
   371     public void run() {
       
   372 
       
   373         Thread curThread = Thread.currentThread();
       
   374         if (curThread == loaderThread) {
       
   375             // if we are in the loader thread, cause
       
   376             // loading to occur.  We may exit this with
       
   377             // status being APPLET_DISPOSE, APPLET_ERROR,
       
   378             // or APPLET_LOAD
       
   379             runLoader();
       
   380             return;
       
   381         }
       
   382 
       
   383         boolean disposed = false;
       
   384         while (!disposed && !curThread.isInterrupted()) {
       
   385             AppletEvent evt;
       
   386             try {
       
   387                 evt = getNextEvent();
       
   388             } catch (InterruptedException e) {
       
   389                 showAppletStatus("bail");
       
   390                 return;
       
   391             }
       
   392 
       
   393             //showAppletStatus("EVENT = " + evt.getID());
       
   394             try {
       
   395                 switch (evt.getID()) {
       
   396                   case APPLET_LOAD:
       
   397                       if (!okToLoad()) {
       
   398                           break;
       
   399                       }
       
   400                       // This complexity allows loading of applets to be
       
   401                       // interruptable.  The actual thread loading runs
       
   402                       // in a separate thread, so it can be interrupted
       
   403                       // without harming the applet thread.
       
   404                       // So that we don't have to worry about
       
   405                       // concurrency issues, the main applet thread waits
       
   406                       // until the loader thread terminates.
       
   407                       // (one way or another).
       
   408                       if (loaderThread == null) {
       
   409                           // REMIND: do we want a name?
       
   410                           //System.out.println("------------------- loading applet");
       
   411                           setLoaderThread(new Thread(this));
       
   412                           loaderThread.start();
       
   413                           // we get to go to sleep while this runs
       
   414                           loaderThread.join();
       
   415                           setLoaderThread(null);
       
   416                       } else {
       
   417                           // REMIND: issue an error -- this case should never
       
   418                           // occur.
       
   419                       }
       
   420                       break;
       
   421 
       
   422                   case APPLET_INIT:
       
   423                     // AppletViewer "Restart" will jump from destroy method to
       
   424                     // init, that is why we need to check status w/ APPLET_DESTROY
       
   425                       if (status != APPLET_LOAD && status != APPLET_DESTROY) {
       
   426                           showAppletStatus("notloaded");
       
   427                           break;
       
   428                       }
       
   429                       applet.resize(defaultAppletSize);
       
   430                       if (doInit) {
       
   431                           if (PerformanceLogger.loggingEnabled()) {
       
   432                               PerformanceLogger.setTime("Applet Init");
       
   433                               PerformanceLogger.outputLog();
       
   434                           }
       
   435                           applet.init();
       
   436                       }
       
   437 
       
   438                       //Need the default(fallback) font to be created in this AppContext
       
   439                       Font f = getFont();
       
   440                       if (f == null ||
       
   441                           "dialog".equals(f.getFamily().toLowerCase(Locale.ENGLISH)) &&
       
   442                           f.getSize() == 12 && f.getStyle() == Font.PLAIN) {
       
   443                           setFont(new Font(Font.DIALOG, Font.PLAIN, 12));
       
   444                       }
       
   445 
       
   446                       doInit = true;    // allow restarts
       
   447 
       
   448                       // Validate the applet in event dispatch thread
       
   449                       // to avoid deadlock.
       
   450                       try {
       
   451                           final AppletPanel p = this;
       
   452 
       
   453                           SwingUtilities.invokeAndWait(new Runnable() {
       
   454                                   public void run() {
       
   455                                       p.validate();
       
   456                                   }
       
   457                               });
       
   458                       }
       
   459                       catch(InterruptedException ie) {
       
   460                       }
       
   461                       catch(InvocationTargetException ite) {
       
   462                       }
       
   463 
       
   464                       status = APPLET_INIT;
       
   465                       showAppletStatus("inited");
       
   466                       break;
       
   467 
       
   468                   case APPLET_START:
       
   469                   {
       
   470                       if (status != APPLET_INIT && status != APPLET_STOP) {
       
   471                           showAppletStatus("notinited");
       
   472                           break;
       
   473                       }
       
   474                       applet.resize(currentAppletSize);
       
   475                       applet.start();
       
   476 
       
   477                       // Validate and show the applet in event dispatch thread
       
   478                       // to avoid deadlock.
       
   479                       try {
       
   480                           final AppletPanel p = this;
       
   481                           final Applet a = applet;
       
   482 
       
   483                           SwingUtilities.invokeAndWait(new Runnable() {
       
   484                                   public void run() {
       
   485                                       p.validate();
       
   486                                       a.setVisible(true);
       
   487 
       
   488                                       // Fix for BugTraq ID 4041703.
       
   489                                       // Set the default focus for an applet.
       
   490                                       if (hasInitialFocus())
       
   491                                         setDefaultFocus();
       
   492                                   }
       
   493                               });
       
   494                       }
       
   495                       catch(InterruptedException ie) {
       
   496                       }
       
   497                       catch(InvocationTargetException ite) {
       
   498                       }
       
   499 
       
   500                       status = APPLET_START;
       
   501                       showAppletStatus("started");
       
   502                       break;
       
   503                   }
       
   504 
       
   505                 case APPLET_STOP:
       
   506                     if (status != APPLET_START) {
       
   507                         showAppletStatus("notstarted");
       
   508                         break;
       
   509                     }
       
   510                     status = APPLET_STOP;
       
   511 
       
   512                     // Hide the applet in event dispatch thread
       
   513                     // to avoid deadlock.
       
   514                     try {
       
   515                         final Applet a = applet;
       
   516 
       
   517                         SwingUtilities.invokeAndWait(new Runnable() {
       
   518                                 public void run()
       
   519                                 {
       
   520                                     a.setVisible(false);
       
   521                                 }
       
   522                             });
       
   523                     }
       
   524                     catch(InterruptedException ie) {
       
   525                     }
       
   526                     catch(InvocationTargetException ite) {
       
   527                     }
       
   528 
       
   529 
       
   530                     // During Applet.stop(), any AccessControlException on an involved Class remains in
       
   531                     // the "memory" of the AppletClassLoader.  If the same instance of the ClassLoader is
       
   532                     // reused, the same exception will occur during class loading.  Set the AppletClassLoader's
       
   533                     // exceptionStatusSet flag to allow recognition of what had happened
       
   534                     // when reusing AppletClassLoader object.
       
   535                     try {
       
   536                         applet.stop();
       
   537                     } catch (java.security.AccessControlException e) {
       
   538                         setExceptionStatus(e);
       
   539                         // rethrow exception to be handled as it normally would be.
       
   540                         throw e;
       
   541                     }
       
   542                     showAppletStatus("stopped");
       
   543                     break;
       
   544 
       
   545                 case APPLET_DESTROY:
       
   546                     if (status != APPLET_STOP && status != APPLET_INIT) {
       
   547                         showAppletStatus("notstopped");
       
   548                         break;
       
   549                     }
       
   550                     status = APPLET_DESTROY;
       
   551 
       
   552                     // During Applet.destroy(), any AccessControlException on an involved Class remains in
       
   553                     // the "memory" of the AppletClassLoader.  If the same instance of the ClassLoader is
       
   554                     // reused, the same exception will occur during class loading.  Set the AppletClassLoader's
       
   555                     // exceptionStatusSet flag to allow recognition of what had happened
       
   556                     // when reusing AppletClassLoader object.
       
   557                     try {
       
   558                         applet.destroy();
       
   559                     } catch (java.security.AccessControlException e) {
       
   560                         setExceptionStatus(e);
       
   561                         // rethrow exception to be handled as it normally would be.
       
   562                         throw e;
       
   563                     }
       
   564                     showAppletStatus("destroyed");
       
   565                     break;
       
   566 
       
   567                 case APPLET_DISPOSE:
       
   568                     if (status != APPLET_DESTROY && status != APPLET_LOAD) {
       
   569                         showAppletStatus("notdestroyed");
       
   570                         break;
       
   571                     }
       
   572                     status = APPLET_DISPOSE;
       
   573 
       
   574                     try
       
   575                     {
       
   576                         final Applet a = applet;
       
   577 
       
   578                         EventQueue.invokeAndWait(new Runnable()
       
   579                         {
       
   580                             public void run()
       
   581                             {
       
   582                                 remove(a);
       
   583                             }
       
   584                         });
       
   585                     }
       
   586                     catch(InterruptedException ie)
       
   587                     {
       
   588                     }
       
   589                     catch(InvocationTargetException ite)
       
   590                     {
       
   591                     }
       
   592                     applet = null;
       
   593                     showAppletStatus("disposed");
       
   594                     disposed = true;
       
   595                     break;
       
   596 
       
   597                 case APPLET_QUIT:
       
   598                     return;
       
   599                 }
       
   600             } catch (Exception e) {
       
   601                 status = APPLET_ERROR;
       
   602                 if (e.getMessage() != null) {
       
   603                     showAppletStatus("exception2", e.getClass().getName(),
       
   604                                      e.getMessage());
       
   605                 } else {
       
   606                     showAppletStatus("exception", e.getClass().getName());
       
   607                 }
       
   608                 showAppletException(e);
       
   609             } catch (ThreadDeath e) {
       
   610                 showAppletStatus("death");
       
   611                 return;
       
   612             } catch (Error e) {
       
   613                 status = APPLET_ERROR;
       
   614                 if (e.getMessage() != null) {
       
   615                     showAppletStatus("error2", e.getClass().getName(),
       
   616                                      e.getMessage());
       
   617                 } else {
       
   618                     showAppletStatus("error", e.getClass().getName());
       
   619                 }
       
   620                 showAppletException(e);
       
   621             }
       
   622             clearLoadAbortRequest();
       
   623         }
       
   624     }
       
   625 
       
   626     /**
       
   627      * Gets most recent focus owner component associated with the given window.
       
   628      * It does that without calling Window.getMostRecentFocusOwner since it
       
   629      * provides its own logic contradicting with setDefautlFocus. Instead, it
       
   630      * calls KeyboardFocusManager directly.
       
   631      */
       
   632     private Component getMostRecentFocusOwnerForWindow(Window w) {
       
   633         Method meth = (Method)AccessController.doPrivileged(new PrivilegedAction() {
       
   634                 public Object run() {
       
   635                     Method meth = null;
       
   636                     try {
       
   637                         meth = KeyboardFocusManager.class.getDeclaredMethod("getMostRecentFocusOwner", new Class[] {Window.class});
       
   638                         meth.setAccessible(true);
       
   639                     } catch (Exception e) {
       
   640                         // Must never happen
       
   641                         e.printStackTrace();
       
   642                     }
       
   643                     return meth;
       
   644                 }
       
   645             });
       
   646         if (meth != null) {
       
   647             // Meth refers static method
       
   648             try {
       
   649                 return (Component)meth.invoke(null, new Object[] {w});
       
   650             } catch (Exception e) {
       
   651                 // Must never happen
       
   652                 e.printStackTrace();
       
   653             }
       
   654         }
       
   655         // Will get here if exception was thrown or meth is null
       
   656         return w.getMostRecentFocusOwner();
       
   657     }
       
   658 
       
   659     /*
       
   660      * Fix for BugTraq ID 4041703.
       
   661      * Set the focus to a reasonable default for an Applet.
       
   662      */
       
   663     private void setDefaultFocus() {
       
   664         Component toFocus = null;
       
   665         Container parent = getParent();
       
   666 
       
   667         if(parent != null) {
       
   668             if (parent instanceof Window) {
       
   669                 toFocus = getMostRecentFocusOwnerForWindow((Window)parent);
       
   670                 if (toFocus == parent || toFocus == null) {
       
   671                     toFocus = parent.getFocusTraversalPolicy().
       
   672                         getInitialComponent((Window)parent);
       
   673                 }
       
   674             } else if (parent.isFocusCycleRoot()) {
       
   675                 toFocus = parent.getFocusTraversalPolicy().
       
   676                     getDefaultComponent(parent);
       
   677             }
       
   678         }
       
   679 
       
   680         if (toFocus != null) {
       
   681             if (parent instanceof EmbeddedFrame) {
       
   682                 ((EmbeddedFrame)parent).synthesizeWindowActivation(true);
       
   683             }
       
   684             // EmbeddedFrame might have focus before the applet was added.
       
   685             // Thus after its activation the most recent focus owner will be
       
   686             // restored. We need the applet's initial focusabled component to
       
   687             // be focused here.
       
   688             toFocus.requestFocusInWindow();
       
   689         }
       
   690     }
       
   691 
       
   692     /**
       
   693      * Load the applet into memory.
       
   694      * Runs in a seperate (and interruptible) thread from the rest of the
       
   695      * applet event processing so that it can be gracefully interrupted from
       
   696      * things like HotJava.
       
   697      */
       
   698     private void runLoader() {
       
   699         if (status != APPLET_DISPOSE) {
       
   700             showAppletStatus("notdisposed");
       
   701             return;
       
   702         }
       
   703 
       
   704         dispatchAppletEvent(APPLET_LOADING, null);
       
   705 
       
   706         // REMIND -- might be cool to visually indicate loading here --
       
   707         // maybe do animation?
       
   708         status = APPLET_LOAD;
       
   709 
       
   710         // Create a class loader
       
   711         loader = getClassLoader(getCodeBase(), getClassLoaderCacheKey());
       
   712 
       
   713         // Load the archives if present.
       
   714         // REMIND - this probably should be done in a separate thread,
       
   715         // or at least the additional archives (epll).
       
   716 
       
   717         String code = getCode();
       
   718 
       
   719         // setup applet AppContext
       
   720         // this must be called before loadJarFiles
       
   721         setupAppletAppContext();
       
   722 
       
   723         try {
       
   724             loadJarFiles(loader);
       
   725             applet = createApplet(loader);
       
   726         } catch (ClassNotFoundException e) {
       
   727             status = APPLET_ERROR;
       
   728             showAppletStatus("notfound", code);
       
   729             showAppletLog("notfound", code);
       
   730             showAppletException(e);
       
   731             return;
       
   732         } catch (InstantiationException e) {
       
   733             status = APPLET_ERROR;
       
   734             showAppletStatus("nocreate", code);
       
   735             showAppletLog("nocreate", code);
       
   736             showAppletException(e);
       
   737             return;
       
   738         } catch (IllegalAccessException e) {
       
   739             status = APPLET_ERROR;
       
   740             showAppletStatus("noconstruct", code);
       
   741             showAppletLog("noconstruct", code);
       
   742             showAppletException(e);
       
   743             // sbb -- I added a return here
       
   744             return;
       
   745         } catch (Exception e) {
       
   746             status = APPLET_ERROR;
       
   747             showAppletStatus("exception", e.getMessage());
       
   748             showAppletException(e);
       
   749             return;
       
   750         } catch (ThreadDeath e) {
       
   751             status = APPLET_ERROR;
       
   752             showAppletStatus("death");
       
   753             return;
       
   754         } catch (Error e) {
       
   755             status = APPLET_ERROR;
       
   756             showAppletStatus("error", e.getMessage());
       
   757             showAppletException(e);
       
   758             return;
       
   759         } finally {
       
   760             // notify that loading is no longer going on
       
   761             dispatchAppletEvent(APPLET_LOADING_COMPLETED, null);
       
   762         }
       
   763 
       
   764         // Fixed #4508194: NullPointerException thrown during
       
   765         // quick page switch
       
   766         //
       
   767         if (applet != null)
       
   768         {
       
   769             // Stick it in the frame
       
   770             applet.setStub(this);
       
   771             applet.hide();
       
   772             add("Center", applet);
       
   773             showAppletStatus("loaded");
       
   774             validate();
       
   775         }
       
   776     }
       
   777 
       
   778     protected Applet createApplet(final AppletClassLoader loader) throws ClassNotFoundException,
       
   779                                                                          IllegalAccessException, IOException, InstantiationException, InterruptedException {
       
   780         final String serName = getSerializedObject();
       
   781         String code = getCode();
       
   782 
       
   783         if (code != null && serName != null) {
       
   784             System.err.println(amh.getMessage("runloader.err"));
       
   785 //          return null;
       
   786             throw new InstantiationException("Either \"code\" or \"object\" should be specified, but not both.");
       
   787         }
       
   788         if (code == null && serName == null) {
       
   789             String msg = "nocode";
       
   790             status = APPLET_ERROR;
       
   791             showAppletStatus(msg);
       
   792             showAppletLog(msg);
       
   793             repaint();
       
   794         }
       
   795         if (code != null) {
       
   796             applet = (Applet)loader.loadCode(code).newInstance();
       
   797             doInit = true;
       
   798         } else {
       
   799             // serName is not null;
       
   800             InputStream is = (InputStream)
       
   801                 java.security.AccessController.doPrivileged(
       
   802                                                             new java.security.PrivilegedAction() {
       
   803                                                                 public Object run() {
       
   804                                                                     return loader.getResourceAsStream(serName);
       
   805                                                                 }
       
   806                                                             });
       
   807             ObjectInputStream ois =
       
   808                 new AppletObjectInputStream(is, loader);
       
   809             Object serObject = ois.readObject();
       
   810             applet = (Applet) serObject;
       
   811             doInit = false; // skip over the first init
       
   812         }
       
   813 
       
   814         // Determine the JDK level that the applet targets.
       
   815         // This is critical for enabling certain backward
       
   816         // compatibility switch if an applet is a JDK 1.1
       
   817         // applet. [stanley.ho]
       
   818         findAppletJDKLevel(applet);
       
   819 
       
   820         if (Thread.interrupted()) {
       
   821             try {
       
   822                 status = APPLET_DISPOSE; // APPLET_ERROR?
       
   823                 applet = null;
       
   824                 // REMIND: This may not be exactly the right thing: the
       
   825                 // status is set by the stop button and not necessarily
       
   826                 // here.
       
   827                 showAppletStatus("death");
       
   828             } finally {
       
   829                 Thread.currentThread().interrupt(); // resignal interrupt
       
   830             }
       
   831             return null;
       
   832         }
       
   833         return applet;
       
   834     }
       
   835 
       
   836     protected void loadJarFiles(AppletClassLoader loader) throws IOException,
       
   837                                                                  InterruptedException {
       
   838         // Load the archives if present.
       
   839         // REMIND - this probably should be done in a separate thread,
       
   840         // or at least the additional archives (epll).
       
   841         String jarFiles = getJarFiles();
       
   842 
       
   843         if (jarFiles != null) {
       
   844             StringTokenizer st = new StringTokenizer(jarFiles, ",", false);
       
   845             while(st.hasMoreTokens()) {
       
   846                 String tok = st.nextToken().trim();
       
   847                 try {
       
   848                     loader.addJar(tok);
       
   849                 } catch (IllegalArgumentException e) {
       
   850                     // bad archive name
       
   851                     continue;
       
   852                 }
       
   853             }
       
   854         }
       
   855     }
       
   856 
       
   857     /**
       
   858      * Request that the loading of the applet be stopped.
       
   859      */
       
   860     protected synchronized void stopLoading() {
       
   861         // REMIND: fill in the body
       
   862         if (loaderThread != null) {
       
   863             //System.out.println("Interrupting applet loader thread: " + loaderThread);
       
   864             loaderThread.interrupt();
       
   865         } else {
       
   866             setLoadAbortRequest();
       
   867         }
       
   868     }
       
   869 
       
   870 
       
   871     protected synchronized boolean okToLoad() {
       
   872         return !loadAbortRequest;
       
   873     }
       
   874 
       
   875     protected synchronized void clearLoadAbortRequest() {
       
   876         loadAbortRequest = false;
       
   877     }
       
   878 
       
   879     protected synchronized void setLoadAbortRequest() {
       
   880         loadAbortRequest = true;
       
   881     }
       
   882 
       
   883 
       
   884     private synchronized void setLoaderThread(Thread loaderThread) {
       
   885         this.loaderThread = loaderThread;
       
   886     }
       
   887 
       
   888     /**
       
   889      * Return true when the applet has been started.
       
   890      */
       
   891     public boolean isActive() {
       
   892         return status == APPLET_START;
       
   893     }
       
   894 
       
   895 
       
   896     private EventQueue appEvtQ = null;
       
   897     /**
       
   898      * Is called when the applet wants to be resized.
       
   899      */
       
   900     public void appletResize(int width, int height) {
       
   901         currentAppletSize.width = width;
       
   902         currentAppletSize.height = height;
       
   903         final Dimension currentSize = new Dimension(currentAppletSize.width,
       
   904                                                     currentAppletSize.height);
       
   905 
       
   906         if(loader != null) {
       
   907             AppContext appCtxt = loader.getAppContext();
       
   908             if(appCtxt != null)
       
   909                 appEvtQ = (java.awt.EventQueue)appCtxt.get(AppContext.EVENT_QUEUE_KEY);
       
   910         }
       
   911 
       
   912         final AppletPanel ap = this;
       
   913         if (appEvtQ != null){
       
   914             appEvtQ.postEvent(new InvocationEvent(Toolkit.getDefaultToolkit(),
       
   915                                                   new Runnable(){
       
   916                                                       public void run(){
       
   917                                                           if(ap != null)
       
   918                                                           {
       
   919                                                               ap.dispatchAppletEvent(APPLET_RESIZE, currentSize);
       
   920                                                           }
       
   921                                                       }
       
   922                                                   }));
       
   923         }
       
   924     }
       
   925 
       
   926     public void setBounds(int x, int y, int width, int height) {
       
   927         super.setBounds(x, y, width, height);
       
   928         currentAppletSize.width = width;
       
   929         currentAppletSize.height = height;
       
   930     }
       
   931 
       
   932     public Applet getApplet() {
       
   933         return applet;
       
   934     }
       
   935 
       
   936     /**
       
   937      * Status line. Called by the AppletPanel to provide
       
   938      * feedback on the Applet's state.
       
   939      */
       
   940     protected void showAppletStatus(String status) {
       
   941         getAppletContext().showStatus(amh.getMessage(status));
       
   942     }
       
   943 
       
   944     protected void showAppletStatus(String status, Object arg) {
       
   945         getAppletContext().showStatus(amh.getMessage(status, arg));
       
   946     }
       
   947     protected void showAppletStatus(String status, Object arg1, Object arg2) {
       
   948         getAppletContext().showStatus(amh.getMessage(status, arg1, arg2));
       
   949     }
       
   950 
       
   951     /**
       
   952      * Called by the AppletPanel to print to the log.
       
   953      */
       
   954     protected void showAppletLog(String msg) {
       
   955         System.out.println(amh.getMessage(msg));
       
   956     }
       
   957 
       
   958     protected void showAppletLog(String msg, Object arg) {
       
   959         System.out.println(amh.getMessage(msg, arg));
       
   960     }
       
   961 
       
   962     /**
       
   963      * Called by the AppletPanel to provide
       
   964      * feedback when an exception has happened.
       
   965      */
       
   966     protected void showAppletException(Throwable t) {
       
   967         t.printStackTrace();
       
   968         repaint();
       
   969     }
       
   970 
       
   971     /**
       
   972      * Get caching key for classloader cache
       
   973      */
       
   974     public String getClassLoaderCacheKey()
       
   975     {
       
   976         /**
       
   977          * Fixed #4501142: Classlaoder sharing policy doesn't
       
   978          * take "archive" into account. This will be overridden
       
   979          * by Java Plug-in.                     [stanleyh]
       
   980          */
       
   981         return getCodeBase().toString();
       
   982     }
       
   983 
       
   984     /**
       
   985      * The class loaders
       
   986      */
       
   987     private static HashMap classloaders = new HashMap();
       
   988 
       
   989     /**
       
   990      * Flush a class loader.
       
   991      */
       
   992     public static synchronized void flushClassLoader(String key) {
       
   993         classloaders.remove(key);
       
   994     }
       
   995 
       
   996     /**
       
   997      * Flush all class loaders.
       
   998      */
       
   999     public static synchronized void flushClassLoaders() {
       
  1000         classloaders = new HashMap();
       
  1001     }
       
  1002 
       
  1003     /**
       
  1004      * This method actually creates an AppletClassLoader.
       
  1005      *
       
  1006      * It can be override by subclasses (such as the Plug-in)
       
  1007      * to provide different classloaders.
       
  1008      */
       
  1009     protected AppletClassLoader createClassLoader(final URL codebase) {
       
  1010         return new AppletClassLoader(codebase);
       
  1011     }
       
  1012 
       
  1013     /**
       
  1014      * Get a class loader. Create in a restricted context
       
  1015      */
       
  1016     synchronized AppletClassLoader getClassLoader(final URL codebase, final String key) {
       
  1017         AppletClassLoader c = (AppletClassLoader)classloaders.get(key);
       
  1018         if (c == null) {
       
  1019             AccessControlContext acc =
       
  1020                 getAccessControlContext(codebase);
       
  1021             c = (AppletClassLoader)
       
  1022                 AccessController.doPrivileged(new PrivilegedAction() {
       
  1023                         public Object run() {
       
  1024                             AppletClassLoader ac = createClassLoader(codebase);
       
  1025                             /* Should the creation of the classloader be
       
  1026                              * within the class synchronized block?  Since
       
  1027                              * this class is used by the plugin, take care
       
  1028                              * to avoid deadlocks, or specialize
       
  1029                              * AppletPanel within the plugin.  It may take
       
  1030                              * an arbitrary amount of time to create a
       
  1031                              * class loader (involving getting Jar files
       
  1032                              * etc.) and may block unrelated applets from
       
  1033                              * finishing createAppletThread (due to the
       
  1034                              * class synchronization). If
       
  1035                              * createAppletThread does not finish quickly,
       
  1036                              * the applet cannot process other messages,
       
  1037                              * particularly messages such as destroy
       
  1038                              * (which timeout when called from the browser).
       
  1039                              */
       
  1040                             synchronized (getClass()) {
       
  1041                                 AppletClassLoader res =
       
  1042                                     (AppletClassLoader)classloaders.get(key);
       
  1043                                 if (res == null) {
       
  1044                                     classloaders.put(key, ac);
       
  1045                                     return ac;
       
  1046                                 } else {
       
  1047                                     return res;
       
  1048                                 }
       
  1049                             }
       
  1050                         }
       
  1051                     },acc);
       
  1052         }
       
  1053         return c;
       
  1054     }
       
  1055 
       
  1056     /**
       
  1057      * get the context for the AppletClassLoader we are creating.
       
  1058      * the context is granted permission to create the class loader,
       
  1059      * connnect to the codebase, and whatever else the policy grants
       
  1060      * to all codebases.
       
  1061      */
       
  1062     private AccessControlContext getAccessControlContext(final URL codebase) {
       
  1063 
       
  1064         PermissionCollection perms = (PermissionCollection)
       
  1065             AccessController.doPrivileged(new PrivilegedAction() {
       
  1066                     public Object run() {
       
  1067                         Policy p = java.security.Policy.getPolicy();
       
  1068                         if (p != null) {
       
  1069                             return p.getPermissions(new CodeSource(null,
       
  1070                                                                    (java.security.cert.Certificate[]) null));
       
  1071                         } else {
       
  1072                             return null;
       
  1073                         }
       
  1074                     }
       
  1075                 });
       
  1076 
       
  1077         if (perms == null)
       
  1078             perms = new Permissions();
       
  1079 
       
  1080         //XXX: this is needed to be able to create the classloader itself!
       
  1081 
       
  1082         perms.add(SecurityConstants.CREATE_CLASSLOADER_PERMISSION);
       
  1083 
       
  1084         Permission p;
       
  1085         java.net.URLConnection urlConnection = null;
       
  1086         try {
       
  1087             urlConnection = codebase.openConnection();
       
  1088             p = urlConnection.getPermission();
       
  1089         } catch (java.io.IOException ioe) {
       
  1090             p = null;
       
  1091         }
       
  1092 
       
  1093         if (p != null)
       
  1094             perms.add(p);
       
  1095 
       
  1096         if (p instanceof FilePermission) {
       
  1097 
       
  1098             String path = p.getName();
       
  1099 
       
  1100             int endIndex = path.lastIndexOf(File.separatorChar);
       
  1101 
       
  1102             if (endIndex != -1) {
       
  1103                 path = path.substring(0, endIndex+1);
       
  1104 
       
  1105                 if (path.endsWith(File.separator)) {
       
  1106                     path += "-";
       
  1107                 }
       
  1108                 perms.add(new FilePermission(path,
       
  1109                                              SecurityConstants.FILE_READ_ACTION));
       
  1110             }
       
  1111         } else {
       
  1112             URL locUrl = codebase;
       
  1113             if (urlConnection instanceof JarURLConnection) {
       
  1114                 locUrl = ((JarURLConnection)urlConnection).getJarFileURL();
       
  1115             }
       
  1116             String host = locUrl.getHost();
       
  1117             if (host != null && (host.length() > 0))
       
  1118                 perms.add(new SocketPermission(host,
       
  1119                                                SecurityConstants.SOCKET_CONNECT_ACCEPT_ACTION));
       
  1120         }
       
  1121 
       
  1122         ProtectionDomain domain =
       
  1123             new ProtectionDomain(new CodeSource(codebase,
       
  1124                                                 (java.security.cert.Certificate[]) null), perms);
       
  1125         AccessControlContext acc =
       
  1126             new AccessControlContext(new ProtectionDomain[] { domain });
       
  1127 
       
  1128         return acc;
       
  1129     }
       
  1130 
       
  1131     public Thread getAppletHandlerThread() {
       
  1132         return handler;
       
  1133     }
       
  1134 
       
  1135     public int getAppletWidth() {
       
  1136         return currentAppletSize.width;
       
  1137     }
       
  1138 
       
  1139     public int getAppletHeight() {
       
  1140         return currentAppletSize.height;
       
  1141     }
       
  1142 
       
  1143     public static void changeFrameAppContext(Frame frame, AppContext newAppContext)
       
  1144     {
       
  1145         // Fixed #4754451: Applet can have methods running on main
       
  1146         // thread event queue.
       
  1147         //
       
  1148         // The cause of this bug is that the frame of the applet
       
  1149         // is created in main thread group. Thus, when certain
       
  1150         // AWT/Swing events are generated, the events will be
       
  1151         // dispatched through the wrong event dispatch thread.
       
  1152         //
       
  1153         // To fix this, we rearrange the AppContext with the frame,
       
  1154         // so the proper event queue will be looked up.
       
  1155         //
       
  1156         // Swing also maintains a Frame list for the AppContext,
       
  1157         // so we will have to rearrange it as well.
       
  1158 
       
  1159         // Check if frame's AppContext has already been set properly
       
  1160         AppContext oldAppContext = SunToolkit.targetToAppContext(frame);
       
  1161 
       
  1162         if (oldAppContext == newAppContext)
       
  1163             return;
       
  1164 
       
  1165         // Synchronization on Window.class is needed for locking the
       
  1166         // critical section of the window list in AppContext.
       
  1167         synchronized (Window.class)
       
  1168         {
       
  1169             WeakReference weakRef = null;
       
  1170             // Remove frame from the Window list in wrong AppContext
       
  1171             {
       
  1172                 // Lookup current frame's AppContext
       
  1173                 Vector<WeakReference<Window>> windowList = (Vector<WeakReference<Window>>)oldAppContext.get(Window.class);
       
  1174                 if (windowList != null) {
       
  1175                     for (WeakReference ref : windowList) {
       
  1176                         if (ref.get() == frame) {
       
  1177                             weakRef = ref;
       
  1178                             break;
       
  1179                         }
       
  1180                     }
       
  1181                     // Remove frame from wrong AppContext
       
  1182                     if (weakRef != null)
       
  1183                         windowList.remove(weakRef);
       
  1184                 }
       
  1185             }
       
  1186 
       
  1187             // Put the frame into the applet's AppContext map
       
  1188             SunToolkit.insertTargetMapping(frame, newAppContext);
       
  1189 
       
  1190             // Insert frame into the Window list in the applet's AppContext map
       
  1191             {
       
  1192                 Vector<WeakReference<Window>> windowList = (Vector)newAppContext.get(Window.class);
       
  1193                 if (windowList == null) {
       
  1194                     windowList = new Vector<WeakReference<Window>>();
       
  1195                     newAppContext.put(Window.class, windowList);
       
  1196                 }
       
  1197                 // use the same weakRef here as it is used elsewhere
       
  1198                 windowList.add(weakRef);
       
  1199             }
       
  1200         }
       
  1201     }
       
  1202 
       
  1203     // Flag to indicate if applet is targeted for JDK 1.1.
       
  1204     private boolean jdk11Applet = false;
       
  1205 
       
  1206     // Flag to indicate if applet is targeted for JDK 1.2.
       
  1207     private boolean jdk12Applet = false;
       
  1208 
       
  1209     /**
       
  1210      * Determine JDK level of an applet.
       
  1211      */
       
  1212     private void findAppletJDKLevel(Applet applet)
       
  1213     {
       
  1214         // To determine the JDK level of an applet, the
       
  1215         // most reliable way is to check the major version
       
  1216         // of the applet class file.
       
  1217 
       
  1218         // synchronized on applet class object, so calling from
       
  1219         // different instances of the same applet will be
       
  1220         // serialized.
       
  1221         Class appletClass = applet.getClass();
       
  1222 
       
  1223         synchronized(appletClass)  {
       
  1224             // Determine if the JDK level of an applet has been
       
  1225             // checked before.
       
  1226             Boolean jdk11Target = (Boolean) loader.isJDK11Target(appletClass);
       
  1227             Boolean jdk12Target = (Boolean) loader.isJDK12Target(appletClass);
       
  1228 
       
  1229             // if applet JDK level has been checked before, retrieve
       
  1230             // value and return.
       
  1231             if (jdk11Target != null || jdk12Target != null) {
       
  1232                 jdk11Applet = (jdk11Target == null) ? false : jdk11Target.booleanValue();
       
  1233                 jdk12Applet = (jdk12Target == null) ? false : jdk12Target.booleanValue();
       
  1234                 return;
       
  1235             }
       
  1236 
       
  1237             String name = appletClass.getName();
       
  1238 
       
  1239             // first convert any '.' to '/'
       
  1240             name = name.replace('.', '/');
       
  1241 
       
  1242             // append .class
       
  1243             final String resourceName = name + ".class";
       
  1244 
       
  1245             InputStream is = null;
       
  1246             byte[] classHeader = new byte[8];
       
  1247 
       
  1248             try {
       
  1249                 is = (InputStream) java.security.AccessController.doPrivileged(
       
  1250                     new java.security.PrivilegedAction() {
       
  1251                         public Object run() {
       
  1252                             return loader.getResourceAsStream(resourceName);
       
  1253                         }
       
  1254                     });
       
  1255 
       
  1256                 // Read the first 8 bytes of the class file
       
  1257                 int byteRead = is.read(classHeader, 0, 8);
       
  1258                 is.close();
       
  1259 
       
  1260                 // return if the header is not read in entirely
       
  1261                 // for some reasons.
       
  1262                 if (byteRead != 8)
       
  1263                     return;
       
  1264             }
       
  1265             catch (IOException e)   {
       
  1266                 return;
       
  1267             }
       
  1268 
       
  1269             // Check major version in class file header
       
  1270             int major_version = readShort(classHeader, 6);
       
  1271 
       
  1272             // Major version in class file is as follows:
       
  1273             //   45 - JDK 1.1
       
  1274             //   46 - JDK 1.2
       
  1275             //   47 - JDK 1.3
       
  1276             //   48 - JDK 1.4
       
  1277             //   49 - JDK 1.5
       
  1278             if (major_version < 46)
       
  1279                 jdk11Applet = true;
       
  1280             else if (major_version == 46)
       
  1281                 jdk12Applet = true;
       
  1282 
       
  1283             // Store applet JDK level in AppContext for later lookup,
       
  1284             // e.g. page switch.
       
  1285             loader.setJDK11Target(appletClass, jdk11Applet);
       
  1286             loader.setJDK12Target(appletClass, jdk12Applet);
       
  1287         }
       
  1288     }
       
  1289 
       
  1290     /**
       
  1291      * Return true if applet is targeted to JDK 1.1.
       
  1292      */
       
  1293     protected boolean isJDK11Applet()   {
       
  1294         return jdk11Applet;
       
  1295     }
       
  1296 
       
  1297     /**
       
  1298      * Return true if applet is targeted to JDK1.2.
       
  1299      */
       
  1300     protected boolean isJDK12Applet()   {
       
  1301         return jdk12Applet;
       
  1302     }
       
  1303 
       
  1304     /**
       
  1305      * Read short from byte array.
       
  1306      */
       
  1307     private int readShort(byte[] b, int off)    {
       
  1308         int hi = readByte(b[off]);
       
  1309         int lo = readByte(b[off + 1]);
       
  1310         return (hi << 8) | lo;
       
  1311     }
       
  1312 
       
  1313     private int readByte(byte b) {
       
  1314         return ((int)b) & 0xFF;
       
  1315     }
       
  1316 
       
  1317 
       
  1318     private static AppletMessageHandler amh = new AppletMessageHandler("appletpanel");
       
  1319 }