1 /* 2 * Copyright (c) 1995, 2008, Oracle and/or its affiliates. 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.applet; 27 28 import java.util.*; 29 import java.io.*; 30 import java.awt.*; 31 import java.awt.event.*; 32 import java.awt.print.*; 33 import javax.print.attribute.*; 34 import java.applet.*; 35 import java.net.URL; 36 import java.net.MalformedURLException; 37 import java.net.SocketPermission; 38 import sun.misc.Ref; 39 import java.security.AccessController; 40 import java.security.PrivilegedAction; 41 import java.lang.reflect.InvocationTargetException; 42 import java.lang.reflect.Method; 43 import sun.awt.SunToolkit; 44 import sun.awt.AppContext; 45 import java.lang.ref.WeakReference; 46 47 /** 48 * A frame to show the applet tag in. 49 */ 50 class TextFrame extends Frame { 51 52 /** 53 * Create the tag frame. 54 */ 55 TextFrame(int x, int y, String title, String text) { 56 setTitle(title); 57 TextArea txt = new TextArea(20, 60); 58 txt.setText(text); 59 txt.setEditable(false); 60 61 add("Center", txt); 62 63 Panel p = new Panel(); 64 add("South", p); 65 Button b = new Button(amh.getMessage("button.dismiss", "Dismiss")); 66 p.add(b); 67 68 class ActionEventListener implements ActionListener { 69 public void actionPerformed(ActionEvent evt) { 70 dispose(); 71 } 72 } 73 b.addActionListener(new ActionEventListener()); 74 75 pack(); 76 move(x, y); 77 setVisible(true); 78 79 WindowListener windowEventListener = new WindowAdapter() { 80 81 public void windowClosing(WindowEvent evt) { 82 dispose(); 83 } 84 }; 85 86 addWindowListener(windowEventListener); 87 } 88 private static AppletMessageHandler amh = new AppletMessageHandler("textframe"); 89 90 } 91 92 /** 93 * Lets us construct one using unix-style one shot behaviors 94 */ 95 96 class StdAppletViewerFactory implements AppletViewerFactory 97 { 98 public AppletViewer createAppletViewer(int x, int y, 99 URL doc, Hashtable atts) { 100 return new AppletViewer(x, y, doc, atts, System.out, this); 101 } 102 103 public MenuBar getBaseMenuBar() { 104 return new MenuBar(); 105 } 106 107 public boolean isStandalone() { 108 return true; 109 } 110 } 111 112 /** 113 * The applet viewer makes it possible to run a Java applet without using a browser. 114 * For details on the syntax that <B>appletviewer</B> supports, see 115 * <a href="../../../docs/tooldocs/appletviewertags.html">AppletViewer Tags</a>. 116 * (The document named appletviewertags.html in the JDK's docs/tooldocs directory, 117 * once the JDK docs have been installed.) 118 */ 119 public class AppletViewer extends Frame implements AppletContext, 120 Printable { 121 122 /** 123 * Some constants... 124 */ 125 private static String defaultSaveFile = "Applet.ser"; 126 127 /** 128 * The panel in which the applet is being displayed. 129 */ 130 AppletViewerPanel panel; 131 132 /** 133 * The status line. 134 */ 135 Label label; 136 137 /** 138 * output status messages to this stream 139 */ 140 141 PrintStream statusMsgStream; 142 143 /** 144 * For cloning 145 */ 146 AppletViewerFactory factory; 147 148 149 private final class UserActionListener implements ActionListener { 150 public void actionPerformed(ActionEvent evt) { 151 processUserAction(evt); 152 } 153 } 154 155 /** 156 * Create the applet viewer 157 */ 158 public AppletViewer(int x, int y, URL doc, Hashtable atts, 159 PrintStream statusMsgStream, AppletViewerFactory factory) { 160 this.factory = factory; 161 this.statusMsgStream = statusMsgStream; 162 setTitle(amh.getMessage("tool.title", atts.get("code"))); 163 164 MenuBar mb = factory.getBaseMenuBar(); 165 166 Menu m = new Menu(amh.getMessage("menu.applet")); 167 168 addMenuItem(m, "menuitem.restart"); 169 addMenuItem(m, "menuitem.reload"); 170 addMenuItem(m, "menuitem.stop"); 171 addMenuItem(m, "menuitem.save"); 172 addMenuItem(m, "menuitem.start"); 173 addMenuItem(m, "menuitem.clone"); 174 m.add(new MenuItem("-")); 175 addMenuItem(m, "menuitem.tag"); 176 addMenuItem(m, "menuitem.info"); 177 addMenuItem(m, "menuitem.edit").disable(); 178 addMenuItem(m, "menuitem.encoding"); 179 m.add(new MenuItem("-")); 180 addMenuItem(m, "menuitem.print"); 181 m.add(new MenuItem("-")); 182 addMenuItem(m, "menuitem.props"); 183 m.add(new MenuItem("-")); 184 addMenuItem(m, "menuitem.close"); 185 if (factory.isStandalone()) { 186 addMenuItem(m, "menuitem.quit"); 187 } 188 189 mb.add(m); 190 191 setMenuBar(mb); 192 193 add("Center", panel = new AppletViewerPanel(doc, atts)); 194 add("South", label = new Label(amh.getMessage("label.hello"))); 195 panel.init(); 196 appletPanels.addElement(panel); 197 198 pack(); 199 move(x, y); 200 setVisible(true); 201 202 WindowListener windowEventListener = new WindowAdapter() { 203 204 public void windowClosing(WindowEvent evt) { 205 appletClose(); 206 } 207 208 public void windowIconified(WindowEvent evt) { 209 appletStop(); 210 } 211 212 public void windowDeiconified(WindowEvent evt) { 213 appletStart(); 214 } 215 }; 216 217 class AppletEventListener implements AppletListener 218 { 219 final Frame frame; 220 221 public AppletEventListener(Frame frame) 222 { 223 this.frame = frame; 224 } 225 226 public void appletStateChanged(AppletEvent evt) 227 { 228 AppletPanel src = (AppletPanel)evt.getSource(); 229 230 switch (evt.getID()) { 231 case AppletPanel.APPLET_RESIZE: { 232 if(src != null) { 233 resize(preferredSize()); 234 validate(); 235 } 236 break; 237 } 238 case AppletPanel.APPLET_LOADING_COMPLETED: { 239 Applet a = src.getApplet(); // sun.applet.AppletPanel 240 241 // Fixed #4754451: Applet can have methods running on main 242 // thread event queue. 243 // 244 // The cause of this bug is that the frame of the applet 245 // is created in main thread group. Thus, when certain 246 // AWT/Swing events are generated, the events will be 247 // dispatched through the wrong event dispatch thread. 248 // 249 // To fix this, we rearrange the AppContext with the frame, 250 // so the proper event queue will be looked up. 251 // 252 // Swing also maintains a Frame list for the AppContext, 253 // so we will have to rearrange it as well. 254 // 255 if (a != null) 256 AppletPanel.changeFrameAppContext(frame, SunToolkit.targetToAppContext(a)); 257 else 258 AppletPanel.changeFrameAppContext(frame, AppContext.getAppContext()); 259 260 break; 261 } 262 } 263 } 264 }; 265 266 addWindowListener(windowEventListener); 267 panel.addAppletListener(new AppletEventListener(this)); 268 269 // Start the applet 270 showStatus(amh.getMessage("status.start")); 271 initEventQueue(); 272 } 273 274 // XXX 99/9/10 probably should be "private" 275 public MenuItem addMenuItem(Menu m, String s) { 276 MenuItem mItem = new MenuItem(amh.getMessage(s)); 277 mItem.addActionListener(new UserActionListener()); 278 return m.add(mItem); 279 } 280 281 /** 282 * Send the initial set of events to the appletviewer event queue. 283 * On start-up the current behaviour is to load the applet and call 284 * Applet.init() and Applet.start(). 285 */ 286 private void initEventQueue() { 287 // appletviewer.send.event is an undocumented and unsupported system 288 // property which is used exclusively for testing purposes. 289 String eventList = System.getProperty("appletviewer.send.event"); 290 291 if (eventList == null) { 292 // Add the standard events onto the event queue. 293 panel.sendEvent(AppletPanel.APPLET_LOAD); 294 panel.sendEvent(AppletPanel.APPLET_INIT); 295 panel.sendEvent(AppletPanel.APPLET_START); 296 } else { 297 // We're testing AppletViewer. Force the specified set of events 298 // onto the event queue, wait for the events to be processed, and 299 // exit. 300 301 // The list of events that will be executed is provided as a 302 // ","-separated list. No error-checking will be done on the list. 303 String [] events = splitSeparator(",", eventList); 304 305 for (int i = 0; i < events.length; i++) { 306 System.out.println("Adding event to queue: " + events[i]); 307 if (events[i].equals("dispose")) 308 panel.sendEvent(AppletPanel.APPLET_DISPOSE); 309 else if (events[i].equals("load")) 310 panel.sendEvent(AppletPanel.APPLET_LOAD); 311 else if (events[i].equals("init")) 312 panel.sendEvent(AppletPanel.APPLET_INIT); 313 else if (events[i].equals("start")) 314 panel.sendEvent(AppletPanel.APPLET_START); 315 else if (events[i].equals("stop")) 316 panel.sendEvent(AppletPanel.APPLET_STOP); 317 else if (events[i].equals("destroy")) 318 panel.sendEvent(AppletPanel.APPLET_DESTROY); 319 else if (events[i].equals("quit")) 320 panel.sendEvent(AppletPanel.APPLET_QUIT); 321 else if (events[i].equals("error")) 322 panel.sendEvent(AppletPanel.APPLET_ERROR); 323 else 324 // non-fatal error if we get an unrecognized event 325 System.out.println("Unrecognized event name: " + events[i]); 326 } 327 328 while (!panel.emptyEventQueue()) ; 329 appletSystemExit(); 330 } 331 } 332 333 /** 334 * Split a string based on the presence of a specified separator. Returns 335 * an array of arbitrary length. The end of each element in the array is 336 * indicated by the separator of the end of the string. If there is a 337 * separator immediately before the end of the string, the final element 338 * will be empty. None of the strings will contain the separator. Useful 339 * when separating strings such as "foo/bar/bas" using separator "/". 340 * 341 * @param sep The separator. 342 * @param s The string to split. 343 * @return An array of strings. Each string in the array is determined 344 * by the location of the provided sep in the original string, 345 * s. Whitespace not stripped. 346 */ 347 private String [] splitSeparator(String sep, String s) { 348 Vector v = new Vector(); 349 int tokenStart = 0; 350 int tokenEnd = 0; 351 352 while ((tokenEnd = s.indexOf(sep, tokenStart)) != -1) { 353 v.addElement(s.substring(tokenStart, tokenEnd)); 354 tokenStart = tokenEnd+1; 355 } 356 // Add the final element. 357 v.addElement(s.substring(tokenStart)); 358 359 String [] retVal = new String[v.size()]; 360 v.copyInto(retVal); 361 return retVal; 362 } 363 364 /* 365 * Methods for java.applet.AppletContext 366 */ 367 368 private static Map audioClips = new HashMap(); 369 370 /** 371 * Get an audio clip. 372 */ 373 public AudioClip getAudioClip(URL url) { 374 checkConnect(url); 375 synchronized (audioClips) { 376 AudioClip clip = (AudioClip)audioClips.get(url); 377 if (clip == null) { 378 audioClips.put(url, clip = new AppletAudioClip(url)); 379 } 380 return clip; 381 } 382 } 383 384 private static Map imageRefs = new HashMap(); 385 386 /** 387 * Get an image. 388 */ 389 public Image getImage(URL url) { 390 return getCachedImage(url); 391 } 392 393 static Image getCachedImage(URL url) { 394 // System.getSecurityManager().checkConnection(url.getHost(), url.getPort()); 395 return (Image)getCachedImageRef(url).get(); 396 } 397 398 /** 399 * Get an image ref. 400 */ 401 static Ref getCachedImageRef(URL url) { 402 synchronized (imageRefs) { 403 AppletImageRef ref = (AppletImageRef)imageRefs.get(url); 404 if (ref == null) { 405 ref = new AppletImageRef(url); 406 imageRefs.put(url, ref); 407 } 408 return ref; 409 } 410 } 411 412 /** 413 * Flush the image cache. 414 */ 415 static void flushImageCache() { 416 imageRefs.clear(); 417 } 418 419 static Vector appletPanels = new Vector(); 420 421 /** 422 * Get an applet by name. 423 */ 424 public Applet getApplet(String name) { 425 AppletSecurity security = (AppletSecurity)System.getSecurityManager(); 426 name = name.toLowerCase(); 427 SocketPermission panelSp = 428 new SocketPermission(panel.getCodeBase().getHost(), "connect"); 429 for (Enumeration e = appletPanels.elements() ; e.hasMoreElements() ;) { 430 AppletPanel p = (AppletPanel)e.nextElement(); 431 String param = p.getParameter("name"); 432 if (param != null) { 433 param = param.toLowerCase(); 434 } 435 if (name.equals(param) && 436 p.getDocumentBase().equals(panel.getDocumentBase())) { 437 438 SocketPermission sp = 439 new SocketPermission(p.getCodeBase().getHost(), "connect"); 440 441 if (panelSp.implies(sp)) { 442 return p.applet; 443 } 444 } 445 } 446 return null; 447 } 448 449 /** 450 * Return an enumeration of all the accessible 451 * applets on this page. 452 */ 453 public Enumeration getApplets() { 454 AppletSecurity security = (AppletSecurity)System.getSecurityManager(); 455 Vector v = new Vector(); 456 SocketPermission panelSp = 457 new SocketPermission(panel.getCodeBase().getHost(), "connect"); 458 459 for (Enumeration e = appletPanels.elements() ; e.hasMoreElements() ;) { 460 AppletPanel p = (AppletPanel)e.nextElement(); 461 if (p.getDocumentBase().equals(panel.getDocumentBase())) { 462 463 SocketPermission sp = 464 new SocketPermission(p.getCodeBase().getHost(), "connect"); 465 if (panelSp.implies(sp)) { 466 v.addElement(p.applet); 467 } 468 } 469 } 470 return v.elements(); 471 } 472 473 /** 474 * Ignore. 475 */ 476 public void showDocument(URL url) { 477 } 478 479 /** 480 * Ignore. 481 */ 482 public void showDocument(URL url, String target) { 483 } 484 485 /** 486 * Show status. 487 */ 488 public void showStatus(String status) { 489 label.setText(status); 490 } 491 492 public void setStream(String key, InputStream stream)throws IOException{ 493 // We do nothing. 494 } 495 496 public InputStream getStream(String key){ 497 // We do nothing. 498 return null; 499 } 500 501 public Iterator getStreamKeys(){ 502 // We do nothing. 503 return null; 504 } 505 506 /** 507 * System parameters. 508 */ 509 static Hashtable systemParam = new Hashtable(); 510 511 static { 512 systemParam.put("codebase", "codebase"); 513 systemParam.put("code", "code"); 514 systemParam.put("alt", "alt"); 515 systemParam.put("width", "width"); 516 systemParam.put("height", "height"); 517 systemParam.put("align", "align"); 518 systemParam.put("vspace", "vspace"); 519 systemParam.put("hspace", "hspace"); 520 } 521 522 /** 523 * Print the HTML tag. 524 */ 525 public static void printTag(PrintStream out, Hashtable atts) { 526 out.print("<applet"); 527 528 String v = (String)atts.get("codebase"); 529 if (v != null) { 530 out.print(" codebase=\"" + v + "\""); 531 } 532 533 v = (String)atts.get("code"); 534 if (v == null) { 535 v = "applet.class"; 536 } 537 out.print(" code=\"" + v + "\""); 538 v = (String)atts.get("width"); 539 if (v == null) { 540 v = "150"; 541 } 542 out.print(" width=" + v); 543 544 v = (String)atts.get("height"); 545 if (v == null) { 546 v = "100"; 547 } 548 out.print(" height=" + v); 549 550 v = (String)atts.get("name"); 551 if (v != null) { 552 out.print(" name=\"" + v + "\""); 553 } 554 out.println(">"); 555 556 // A very slow sorting algorithm 557 int len = atts.size(); 558 String params[] = new String[len]; 559 len = 0; 560 for (Enumeration e = atts.keys() ; e.hasMoreElements() ;) { 561 String param = (String)e.nextElement(); 562 int i = 0; 563 for (; i < len ; i++) { 564 if (params[i].compareTo(param) >= 0) { 565 break; 566 } 567 } 568 System.arraycopy(params, i, params, i + 1, len - i); 569 params[i] = param; 570 len++; 571 } 572 573 for (int i = 0 ; i < len ; i++) { 574 String param = params[i]; 575 if (systemParam.get(param) == null) { 576 out.println("<param name=" + param + 577 " value=\"" + atts.get(param) + "\">"); 578 } 579 } 580 out.println("</applet>"); 581 } 582 583 /** 584 * Make sure the atrributes are uptodate. 585 */ 586 public void updateAtts() { 587 Dimension d = panel.size(); 588 Insets in = panel.insets(); 589 panel.atts.put("width", 590 Integer.toString(d.width - (in.left + in.right))); 591 panel.atts.put("height", 592 Integer.toString(d.height - (in.top + in.bottom))); 593 } 594 595 /** 596 * Restart the applet. 597 */ 598 void appletRestart() { 599 panel.sendEvent(AppletPanel.APPLET_STOP); 600 panel.sendEvent(AppletPanel.APPLET_DESTROY); 601 panel.sendEvent(AppletPanel.APPLET_INIT); 602 panel.sendEvent(AppletPanel.APPLET_START); 603 } 604 605 /** 606 * Reload the applet. 607 */ 608 void appletReload() { 609 panel.sendEvent(AppletPanel.APPLET_STOP); 610 panel.sendEvent(AppletPanel.APPLET_DESTROY); 611 panel.sendEvent(AppletPanel.APPLET_DISPOSE); 612 613 /** 614 * Fixed #4501142: Classlaoder sharing policy doesn't 615 * take "archive" into account. This will be overridden 616 * by Java Plug-in. [stanleyh] 617 */ 618 AppletPanel.flushClassLoader(panel.getClassLoaderCacheKey()); 619 620 /* 621 * Make sure we don't have two threads running through the event queue 622 * at the same time. 623 */ 624 try { 625 panel.joinAppletThread(); 626 panel.release(); 627 } catch (InterruptedException e) { 628 return; // abort the reload 629 } 630 631 panel.createAppletThread(); 632 panel.sendEvent(AppletPanel.APPLET_LOAD); 633 panel.sendEvent(AppletPanel.APPLET_INIT); 634 panel.sendEvent(AppletPanel.APPLET_START); 635 } 636 637 /** 638 * Save the applet to a well known file (for now) as a serialized object 639 */ 640 void appletSave() { 641 AccessController.doPrivileged(new PrivilegedAction() { 642 643 public Object run() { 644 // XXX: this privileged block should be made smaller 645 // by initializing a private static variable with "user.dir" 646 647 // Applet needs to be stopped for serialization to succeed. 648 // Since panel.sendEvent only queues the event, there is a 649 // chance that the event will not be processed before 650 // serialization begins. However, by sending the event before 651 // FileDialog is created, enough time is given such that this 652 // situation is unlikely to ever occur. 653 654 panel.sendEvent(AppletPanel.APPLET_STOP); 655 FileDialog fd = new FileDialog(AppletViewer.this, 656 amh.getMessage("appletsave.filedialogtitle"), 657 FileDialog.SAVE); 658 // needed for a bug under Solaris... 659 fd.setDirectory(System.getProperty("user.dir")); 660 fd.setFile(defaultSaveFile); 661 fd.show(); 662 String fname = fd.getFile(); 663 if (fname == null) { 664 // Restart applet if Save is cancelled. 665 panel.sendEvent(AppletPanel.APPLET_START); 666 return null; // cancelled 667 } 668 String dname = fd.getDirectory(); 669 File file = new File(dname, fname); 670 671 try (FileOutputStream fos = new FileOutputStream(file); 672 BufferedOutputStream bos = new BufferedOutputStream(fos); 673 ObjectOutputStream os = new ObjectOutputStream(bos)) { 674 675 showStatus(amh.getMessage("appletsave.err1", panel.applet.toString(), file.toString())); 676 os.writeObject(panel.applet); 677 } catch (IOException ex) { 678 System.err.println(amh.getMessage("appletsave.err2", ex)); 679 } finally { 680 panel.sendEvent(AppletPanel.APPLET_START); 681 } 682 return null; 683 } 684 }); 685 } 686 687 /** 688 * Clone the viewer and the applet. 689 */ 690 void appletClone() { 691 Point p = location(); 692 updateAtts(); 693 factory.createAppletViewer(p.x + XDELTA, p.y + YDELTA, 694 panel.documentURL, (Hashtable)panel.atts.clone()); 695 } 696 697 /** 698 * Show the applet tag. 699 */ 700 void appletTag() { 701 ByteArrayOutputStream out = new ByteArrayOutputStream(); 702 updateAtts(); 703 printTag(new PrintStream(out), panel.atts); 704 showStatus(amh.getMessage("applettag")); 705 706 Point p = location(); 707 new TextFrame(p.x + XDELTA, p.y + YDELTA, amh.getMessage("applettag.textframe"), out.toString()); 708 } 709 710 /** 711 * Show the applet info. 712 */ 713 void appletInfo() { 714 String str = panel.applet.getAppletInfo(); 715 if (str == null) { 716 str = amh.getMessage("appletinfo.applet"); 717 } 718 str += "\n\n"; 719 720 String atts[][] = panel.applet.getParameterInfo(); 721 if (atts != null) { 722 for (int i = 0 ; i < atts.length ; i++) { 723 str += atts[i][0] + " -- " + atts[i][1] + " -- " + atts[i][2] + "\n"; 724 } 725 } else { 726 str += amh.getMessage("appletinfo.param"); 727 } 728 729 Point p = location(); 730 new TextFrame(p.x + XDELTA, p.y + YDELTA, amh.getMessage("appletinfo.textframe"), str); 731 732 } 733 734 /** 735 * Show character encoding type 736 */ 737 void appletCharacterEncoding() { 738 showStatus(amh.getMessage("appletencoding", encoding)); 739 } 740 741 /** 742 * Edit the applet. 743 */ 744 void appletEdit() { 745 } 746 747 /** 748 * Print the applet. 749 */ 750 void appletPrint() { 751 PrinterJob pj = PrinterJob.getPrinterJob(); 752 753 if (pj != null) { 754 PrintRequestAttributeSet aset = new HashPrintRequestAttributeSet(); 755 if (pj.printDialog(aset)) { 756 pj.setPrintable(this); 757 try { 758 pj.print(aset); 759 statusMsgStream.println(amh.getMessage("appletprint.finish")); 760 } catch (PrinterException e) { 761 statusMsgStream.println(amh.getMessage("appletprint.fail")); 762 } 763 } else { 764 statusMsgStream.println(amh.getMessage("appletprint.cancel")); 765 } 766 } else { 767 statusMsgStream.println(amh.getMessage("appletprint.fail")); 768 } 769 } 770 771 public int print(Graphics graphics, PageFormat pf, int pageIndex) { 772 if (pageIndex > 0) { 773 return Printable.NO_SUCH_PAGE; 774 } else { 775 Graphics2D g2d = (Graphics2D)graphics; 776 g2d.translate(pf.getImageableX(), pf.getImageableY()); 777 panel.applet.printAll(graphics); 778 return Printable.PAGE_EXISTS; 779 } 780 } 781 782 /** 783 * Properties. 784 */ 785 static AppletProps props; 786 public static synchronized void networkProperties() { 787 if (props == null) { 788 props = new AppletProps(); 789 } 790 props.addNotify(); 791 props.setVisible(true); 792 } 793 794 /** 795 * Start the applet. 796 */ 797 void appletStart() { 798 panel.sendEvent(AppletPanel.APPLET_START); 799 } 800 801 /** 802 * Stop the applet. 803 */ 804 void appletStop() { 805 panel.sendEvent(AppletPanel.APPLET_STOP); 806 } 807 808 /** 809 * Shutdown a viewer. 810 * Stop, Destroy, Dispose and Quit a viewer 811 */ 812 private void appletShutdown(AppletPanel p) { 813 p.sendEvent(AppletPanel.APPLET_STOP); 814 p.sendEvent(AppletPanel.APPLET_DESTROY); 815 p.sendEvent(AppletPanel.APPLET_DISPOSE); 816 p.sendEvent(AppletPanel.APPLET_QUIT); 817 } 818 819 /** 820 * Close this viewer. 821 * Stop, Destroy, Dispose and Quit an AppletView, then 822 * reclaim resources and exit the program if this is 823 * the last applet. 824 */ 825 void appletClose() { 826 827 // The caller thread is event dispatch thread, so 828 // spawn a new thread to avoid blocking the event queue 829 // when calling appletShutdown. 830 // 831 final AppletPanel p = panel; 832 833 new Thread(new Runnable() 834 { 835 public void run() 836 { 837 appletShutdown(p); 838 appletPanels.removeElement(p); 839 dispose(); 840 841 if (countApplets() == 0) { 842 appletSystemExit(); 843 } 844 } 845 }).start(); 846 } 847 848 /** 849 * Exit the program. 850 * Exit from the program (if not stand alone) - do no clean-up 851 */ 852 private void appletSystemExit() { 853 if (factory.isStandalone()) 854 System.exit(0); 855 } 856 857 /** 858 * Quit all viewers. 859 * Shutdown all viewers properly then 860 * exit from the program (if not stand alone) 861 */ 862 protected void appletQuit() 863 { 864 // The caller thread is event dispatch thread, so 865 // spawn a new thread to avoid blocking the event queue 866 // when calling appletShutdown. 867 // 868 new Thread(new Runnable() 869 { 870 public void run() 871 { 872 for (Enumeration e = appletPanels.elements() ; e.hasMoreElements() ;) { 873 AppletPanel p = (AppletPanel)e.nextElement(); 874 appletShutdown(p); 875 } 876 appletSystemExit(); 877 } 878 }).start(); 879 } 880 881 /** 882 * Handle events. 883 */ 884 public void processUserAction(ActionEvent evt) { 885 886 String label = ((MenuItem)evt.getSource()).getLabel(); 887 888 if (amh.getMessage("menuitem.restart").equals(label)) { 889 appletRestart(); 890 return; 891 } 892 893 if (amh.getMessage("menuitem.reload").equals(label)) { 894 appletReload(); 895 return; 896 } 897 898 if (amh.getMessage("menuitem.clone").equals(label)) { 899 appletClone(); 900 return; 901 } 902 903 if (amh.getMessage("menuitem.stop").equals(label)) { 904 appletStop(); 905 return; 906 } 907 908 if (amh.getMessage("menuitem.save").equals(label)) { 909 appletSave(); 910 return; 911 } 912 913 if (amh.getMessage("menuitem.start").equals(label)) { 914 appletStart(); 915 return; 916 } 917 918 if (amh.getMessage("menuitem.tag").equals(label)) { 919 appletTag(); 920 return; 921 } 922 923 if (amh.getMessage("menuitem.info").equals(label)) { 924 appletInfo(); 925 return; 926 } 927 928 if (amh.getMessage("menuitem.encoding").equals(label)) { 929 appletCharacterEncoding(); 930 return; 931 } 932 933 if (amh.getMessage("menuitem.edit").equals(label)) { 934 appletEdit(); 935 return; 936 } 937 938 if (amh.getMessage("menuitem.print").equals(label)) { 939 appletPrint(); 940 return; 941 } 942 943 if (amh.getMessage("menuitem.props").equals(label)) { 944 networkProperties(); 945 return; 946 } 947 948 if (amh.getMessage("menuitem.close").equals(label)) { 949 appletClose(); 950 return; 951 } 952 953 if (factory.isStandalone() && amh.getMessage("menuitem.quit").equals(label)) { 954 appletQuit(); 955 return; 956 } 957 //statusMsgStream.println("evt = " + evt); 958 } 959 960 /** 961 * How many applets are running? 962 */ 963 964 public static int countApplets() { 965 return appletPanels.size(); 966 } 967 968 969 /** 970 * The current character. 971 */ 972 static int c; 973 974 /** 975 * Scan spaces. 976 */ 977 public static void skipSpace(Reader in) throws IOException { 978 while ((c >= 0) && 979 ((c == ' ') || (c == '\t') || (c == '\n') || (c == '\r'))) { 980 c = in.read(); 981 } 982 } 983 984 /** 985 * Scan identifier 986 */ 987 public static String scanIdentifier(Reader in) throws IOException { 988 StringBuffer buf = new StringBuffer(); 989 while (true) { 990 if (((c >= 'a') && (c <= 'z')) || 991 ((c >= 'A') && (c <= 'Z')) || 992 ((c >= '0') && (c <= '9')) || (c == '_')) { 993 buf.append((char)c); 994 c = in.read(); 995 } else { 996 return buf.toString(); 997 } 998 } 999 } 1000 1001 /** 1002 * Scan tag 1003 */ 1004 public static Hashtable scanTag(Reader in) throws IOException { 1005 Hashtable atts = new Hashtable(); 1006 skipSpace(in); 1007 while (c >= 0 && c != '>') { 1008 String att = scanIdentifier(in); 1009 String val = ""; 1010 skipSpace(in); 1011 if (c == '=') { 1012 int quote = -1; 1013 c = in.read(); 1014 skipSpace(in); 1015 if ((c == '\'') || (c == '\"')) { 1016 quote = c; 1017 c = in.read(); 1018 } 1019 StringBuffer buf = new StringBuffer(); 1020 while ((c > 0) && 1021 (((quote < 0) && (c != ' ') && (c != '\t') && 1022 (c != '\n') && (c != '\r') && (c != '>')) 1023 || ((quote >= 0) && (c != quote)))) { 1024 buf.append((char)c); 1025 c = in.read(); 1026 } 1027 if (c == quote) { 1028 c = in.read(); 1029 } 1030 skipSpace(in); 1031 val = buf.toString(); 1032 } 1033 //statusMsgStream.println("PUT " + att + " = '" + val + "'"); 1034 if (! val.equals("")) { 1035 atts.put(att.toLowerCase(java.util.Locale.ENGLISH), val); 1036 } 1037 while (true) { 1038 if ((c == '>') || (c < 0) || 1039 ((c >= 'a') && (c <= 'z')) || 1040 ((c >= 'A') && (c <= 'Z')) || 1041 ((c >= '0') && (c <= '9')) || (c == '_')) 1042 break; 1043 c = in.read(); 1044 } 1045 //skipSpace(in); 1046 } 1047 return atts; 1048 } 1049 1050 /* values used for placement of AppletViewer's frames */ 1051 private static int x = 0; 1052 private static int y = 0; 1053 private static final int XDELTA = 30; 1054 private static final int YDELTA = XDELTA; 1055 1056 static String encoding = null; 1057 1058 static private Reader makeReader(InputStream is) { 1059 if (encoding != null) { 1060 try { 1061 return new BufferedReader(new InputStreamReader(is, encoding)); 1062 } catch (IOException x) { } 1063 } 1064 InputStreamReader r = new InputStreamReader(is); 1065 encoding = r.getEncoding(); 1066 return new BufferedReader(r); 1067 } 1068 1069 /** 1070 * Scan an html file for <applet> tags 1071 */ 1072 public static void parse(URL url, String enc) throws IOException { 1073 encoding = enc; 1074 parse(url, System.out, new StdAppletViewerFactory()); 1075 } 1076 1077 public static void parse(URL url) throws IOException { 1078 parse(url, System.out, new StdAppletViewerFactory()); 1079 } 1080 1081 public static void parse(URL url, PrintStream statusMsgStream, 1082 AppletViewerFactory factory) throws IOException { 1083 // <OBJECT> <EMBED> tag flags 1084 boolean isAppletTag = false; 1085 boolean isObjectTag = false; 1086 boolean isEmbedTag = false; 1087 1088 // warning messages 1089 String requiresNameWarning = amh.getMessage("parse.warning.requiresname"); 1090 String paramOutsideWarning = amh.getMessage("parse.warning.paramoutside"); 1091 String appletRequiresCodeWarning = amh.getMessage("parse.warning.applet.requirescode"); 1092 String appletRequiresHeightWarning = amh.getMessage("parse.warning.applet.requiresheight"); 1093 String appletRequiresWidthWarning = amh.getMessage("parse.warning.applet.requireswidth"); 1094 String objectRequiresCodeWarning = amh.getMessage("parse.warning.object.requirescode"); 1095 String objectRequiresHeightWarning = amh.getMessage("parse.warning.object.requiresheight"); 1096 String objectRequiresWidthWarning = amh.getMessage("parse.warning.object.requireswidth"); 1097 String embedRequiresCodeWarning = amh.getMessage("parse.warning.embed.requirescode"); 1098 String embedRequiresHeightWarning = amh.getMessage("parse.warning.embed.requiresheight"); 1099 String embedRequiresWidthWarning = amh.getMessage("parse.warning.embed.requireswidth"); 1100 String appNotLongerSupportedWarning = amh.getMessage("parse.warning.appnotLongersupported"); 1101 1102 java.net.URLConnection conn = url.openConnection(); 1103 Reader in = makeReader(conn.getInputStream()); 1104 /* The original URL may have been redirected - this 1105 * sets it to whatever URL/codebase we ended up getting 1106 */ 1107 url = conn.getURL(); 1108 1109 int ydisp = 1; 1110 Hashtable atts = null; 1111 1112 while(true) { 1113 c = in.read(); 1114 if (c == -1) 1115 break; 1116 1117 if (c == '<') { 1118 c = in.read(); 1119 if (c == '/') { 1120 c = in.read(); 1121 String nm = scanIdentifier(in); 1122 if (nm.equalsIgnoreCase("applet") || 1123 nm.equalsIgnoreCase("object") || 1124 nm.equalsIgnoreCase("embed")) { 1125 1126 // We can't test for a code tag until </OBJECT> 1127 // because it is a parameter, not an attribute. 1128 if(isObjectTag) { 1129 if (atts.get("code") == null && atts.get("object") == null) { 1130 statusMsgStream.println(objectRequiresCodeWarning); 1131 atts = null; 1132 } 1133 } 1134 1135 if (atts != null) { 1136 // XXX 5/18 In general this code just simply 1137 // shouldn't be part of parsing. It's presence 1138 // causes things to be a little too much of a 1139 // hack. 1140 factory.createAppletViewer(x, y, url, atts); 1141 x += XDELTA; 1142 y += YDELTA; 1143 // make sure we don't go too far! 1144 Dimension d = Toolkit.getDefaultToolkit().getScreenSize(); 1145 if ((x > d.width - 300) || (y > d.height - 300)) { 1146 x = 0; 1147 y = 2 * ydisp * YDELTA; 1148 ydisp++; 1149 } 1150 } 1151 atts = null; 1152 isAppletTag = false; 1153 isObjectTag = false; 1154 isEmbedTag = false; 1155 } 1156 } 1157 else { 1158 String nm = scanIdentifier(in); 1159 if (nm.equalsIgnoreCase("param")) { 1160 Hashtable t = scanTag(in); 1161 String att = (String)t.get("name"); 1162 if (att == null) { 1163 statusMsgStream.println(requiresNameWarning); 1164 } else { 1165 String val = (String)t.get("value"); 1166 if (val == null) { 1167 statusMsgStream.println(requiresNameWarning); 1168 } else if (atts != null) { 1169 atts.put(att.toLowerCase(), val); 1170 } else { 1171 statusMsgStream.println(paramOutsideWarning); 1172 } 1173 } 1174 } 1175 else if (nm.equalsIgnoreCase("applet")) { 1176 isAppletTag = true; 1177 atts = scanTag(in); 1178 if (atts.get("code") == null && atts.get("object") == null) { 1179 statusMsgStream.println(appletRequiresCodeWarning); 1180 atts = null; 1181 } else if (atts.get("width") == null) { 1182 statusMsgStream.println(appletRequiresWidthWarning); 1183 atts = null; 1184 } else if (atts.get("height") == null) { 1185 statusMsgStream.println(appletRequiresHeightWarning); 1186 atts = null; 1187 } 1188 } 1189 else if (nm.equalsIgnoreCase("object")) { 1190 isObjectTag = true; 1191 atts = scanTag(in); 1192 // The <OBJECT> attribute codebase isn't what 1193 // we want. If its defined, remove it. 1194 if(atts.get("codebase") != null) { 1195 atts.remove("codebase"); 1196 } 1197 1198 if (atts.get("width") == null) { 1199 statusMsgStream.println(objectRequiresWidthWarning); 1200 atts = null; 1201 } else if (atts.get("height") == null) { 1202 statusMsgStream.println(objectRequiresHeightWarning); 1203 atts = null; 1204 } 1205 } 1206 else if (nm.equalsIgnoreCase("embed")) { 1207 isEmbedTag = true; 1208 atts = scanTag(in); 1209 1210 if (atts.get("code") == null && atts.get("object") == null) { 1211 statusMsgStream.println(embedRequiresCodeWarning); 1212 atts = null; 1213 } else if (atts.get("width") == null) { 1214 statusMsgStream.println(embedRequiresWidthWarning); 1215 atts = null; 1216 } else if (atts.get("height") == null) { 1217 statusMsgStream.println(embedRequiresHeightWarning); 1218 atts = null; 1219 } 1220 } 1221 else if (nm.equalsIgnoreCase("app")) { 1222 statusMsgStream.println(appNotLongerSupportedWarning); 1223 Hashtable atts2 = scanTag(in); 1224 nm = (String)atts2.get("class"); 1225 if (nm != null) { 1226 atts2.remove("class"); 1227 atts2.put("code", nm + ".class"); 1228 } 1229 nm = (String)atts2.get("src"); 1230 if (nm != null) { 1231 atts2.remove("src"); 1232 atts2.put("codebase", nm); 1233 } 1234 if (atts2.get("width") == null) { 1235 atts2.put("width", "100"); 1236 } 1237 if (atts2.get("height") == null) { 1238 atts2.put("height", "100"); 1239 } 1240 printTag(statusMsgStream, atts2); 1241 statusMsgStream.println(); 1242 } 1243 } 1244 } 1245 } 1246 in.close(); 1247 } 1248 1249 /** 1250 * Old main entry point. 1251 * 1252 * @deprecated 1253 */ 1254 @Deprecated 1255 public static void main(String argv[]) { 1256 // re-route everything to the new main entry point 1257 Main.main(argv); 1258 } 1259 1260 private static AppletMessageHandler amh = new AppletMessageHandler("appletviewer"); 1261 1262 private static void checkConnect(URL url) 1263 { 1264 SecurityManager security = System.getSecurityManager(); 1265 if (security != null) { 1266 try { 1267 java.security.Permission perm = 1268 url.openConnection().getPermission(); 1269 if (perm != null) 1270 security.checkPermission(perm); 1271 else 1272 security.checkConnect(url.getHost(), url.getPort()); 1273 } catch (java.io.IOException ioe) { 1274 security.checkConnect(url.getHost(), url.getPort()); 1275 } 1276 } 1277 } 1278 }