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