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 (ObjectOutputStream os = new ObjectOutputStream( 672 new BufferedOutputStream(new FileOutputStream(file)))) { 673 674 showStatus(amh.getMessage("appletsave.err1", panel.applet.toString(), file.toString())); 675 os.writeObject(panel.applet); 676 } catch (IOException ex) { 677 System.err.println(amh.getMessage("appletsave.err2", ex)); 678 } finally { 679 panel.sendEvent(AppletPanel.APPLET_START); 680 } 681 return null; 682 } 683 }); 684 } 685 686 /** 687 * Clone the viewer and the applet. 688 */ 689 void appletClone() { 690 Point p = location(); 691 updateAtts(); 692 factory.createAppletViewer(p.x + XDELTA, p.y + YDELTA, 693 panel.documentURL, (Hashtable)panel.atts.clone()); 694 } 695 696 /** 697 * Show the applet tag. 698 */ 699 void appletTag() { 700 ByteArrayOutputStream out = new ByteArrayOutputStream(); 701 updateAtts(); 702 printTag(new PrintStream(out), panel.atts); 703 showStatus(amh.getMessage("applettag")); 704 705 Point p = location(); 706 new TextFrame(p.x + XDELTA, p.y + YDELTA, amh.getMessage("applettag.textframe"), out.toString()); 707 } 708 709 /** 710 * Show the applet info. 711 */ 712 void appletInfo() { 713 String str = panel.applet.getAppletInfo(); 714 if (str == null) { 715 str = amh.getMessage("appletinfo.applet"); 716 } 717 str += "\n\n"; 718 719 String atts[][] = panel.applet.getParameterInfo(); 720 if (atts != null) { 721 for (int i = 0 ; i < atts.length ; i++) { 722 str += atts[i][0] + " -- " + atts[i][1] + " -- " + atts[i][2] + "\n"; 723 } 724 } else { 725 str += amh.getMessage("appletinfo.param"); 726 } 727 728 Point p = location(); 729 new TextFrame(p.x + XDELTA, p.y + YDELTA, amh.getMessage("appletinfo.textframe"), str); 730 731 } 732 733 /** 734 * Show character encoding type 735 */ 736 void appletCharacterEncoding() { 737 showStatus(amh.getMessage("appletencoding", encoding)); 738 } 739 740 /** 741 * Edit the applet. 742 */ 743 void appletEdit() { 744 } 745 746 /** 747 * Print the applet. 748 */ 749 void appletPrint() { 750 PrinterJob pj = PrinterJob.getPrinterJob(); 751 752 if (pj != null) { 753 PrintRequestAttributeSet aset = new HashPrintRequestAttributeSet(); 754 if (pj.printDialog(aset)) { 755 pj.setPrintable(this); 756 try { 757 pj.print(aset); 758 statusMsgStream.println(amh.getMessage("appletprint.finish")); 759 } catch (PrinterException e) { 760 statusMsgStream.println(amh.getMessage("appletprint.fail")); 761 } 762 } else { 763 statusMsgStream.println(amh.getMessage("appletprint.cancel")); 764 } 765 } else { 766 statusMsgStream.println(amh.getMessage("appletprint.fail")); 767 } 768 } 769 770 public int print(Graphics graphics, PageFormat pf, int pageIndex) { 771 if (pageIndex > 0) { 772 return Printable.NO_SUCH_PAGE; 773 } else { 774 Graphics2D g2d = (Graphics2D)graphics; 775 g2d.translate(pf.getImageableX(), pf.getImageableY()); 776 panel.applet.printAll(graphics); 777 return Printable.PAGE_EXISTS; 778 } 779 } 780 781 /** 782 * Properties. 783 */ 784 static AppletProps props; 785 public static synchronized void networkProperties() { 786 if (props == null) { 787 props = new AppletProps(); 788 } 789 props.addNotify(); 790 props.setVisible(true); 791 } 792 793 /** 794 * Start the applet. 795 */ 796 void appletStart() { 797 panel.sendEvent(AppletPanel.APPLET_START); 798 } 799 800 /** 801 * Stop the applet. 802 */ 803 void appletStop() { 804 panel.sendEvent(AppletPanel.APPLET_STOP); 805 } 806 807 /** 808 * Shutdown a viewer. 809 * Stop, Destroy, Dispose and Quit a viewer 810 */ 811 private void appletShutdown(AppletPanel p) { 812 p.sendEvent(AppletPanel.APPLET_STOP); 813 p.sendEvent(AppletPanel.APPLET_DESTROY); 814 p.sendEvent(AppletPanel.APPLET_DISPOSE); 815 p.sendEvent(AppletPanel.APPLET_QUIT); 816 } 817 818 /** 819 * Close this viewer. 820 * Stop, Destroy, Dispose and Quit an AppletView, then 821 * reclaim resources and exit the program if this is 822 * the last applet. 823 */ 824 void appletClose() { 825 826 // The caller thread is event dispatch thread, so 827 // spawn a new thread to avoid blocking the event queue 828 // when calling appletShutdown. 829 // 830 final AppletPanel p = panel; 831 832 new Thread(new Runnable() 833 { 834 public void run() 835 { 836 appletShutdown(p); 837 appletPanels.removeElement(p); 838 dispose(); 839 840 if (countApplets() == 0) { 841 appletSystemExit(); 842 } 843 } 844 }).start(); 845 } 846 847 /** 848 * Exit the program. 849 * Exit from the program (if not stand alone) - do no clean-up 850 */ 851 private void appletSystemExit() { 852 if (factory.isStandalone()) 853 System.exit(0); 854 } 855 856 /** 857 * Quit all viewers. 858 * Shutdown all viewers properly then 859 * exit from the program (if not stand alone) 860 */ 861 protected void appletQuit() 862 { 863 // The caller thread is event dispatch thread, so 864 // spawn a new thread to avoid blocking the event queue 865 // when calling appletShutdown. 866 // 867 new Thread(new Runnable() 868 { 869 public void run() 870 { 871 for (Enumeration e = appletPanels.elements() ; e.hasMoreElements() ;) { 872 AppletPanel p = (AppletPanel)e.nextElement(); 873 appletShutdown(p); 874 } 875 appletSystemExit(); 876 } 877 }).start(); 878 } 879 880 /** 881 * Handle events. 882 */ 883 public void processUserAction(ActionEvent evt) { 884 885 String label = ((MenuItem)evt.getSource()).getLabel(); 886 887 if (amh.getMessage("menuitem.restart").equals(label)) { 888 appletRestart(); 889 return; 890 } 891 892 if (amh.getMessage("menuitem.reload").equals(label)) { 893 appletReload(); 894 return; 895 } 896 897 if (amh.getMessage("menuitem.clone").equals(label)) { 898 appletClone(); 899 return; 900 } 901 902 if (amh.getMessage("menuitem.stop").equals(label)) { 903 appletStop(); 904 return; 905 } 906 907 if (amh.getMessage("menuitem.save").equals(label)) { 908 appletSave(); 909 return; 910 } 911 912 if (amh.getMessage("menuitem.start").equals(label)) { 913 appletStart(); 914 return; 915 } 916 917 if (amh.getMessage("menuitem.tag").equals(label)) { 918 appletTag(); 919 return; 920 } 921 922 if (amh.getMessage("menuitem.info").equals(label)) { 923 appletInfo(); 924 return; 925 } 926 927 if (amh.getMessage("menuitem.encoding").equals(label)) { 928 appletCharacterEncoding(); 929 return; 930 } 931 932 if (amh.getMessage("menuitem.edit").equals(label)) { 933 appletEdit(); 934 return; 935 } 936 937 if (amh.getMessage("menuitem.print").equals(label)) { 938 appletPrint(); 939 return; 940 } 941 942 if (amh.getMessage("menuitem.props").equals(label)) { 943 networkProperties(); 944 return; 945 } 946 947 if (amh.getMessage("menuitem.close").equals(label)) { 948 appletClose(); 949 return; 950 } 951 952 if (factory.isStandalone() && amh.getMessage("menuitem.quit").equals(label)) { 953 appletQuit(); 954 return; 955 } 956 //statusMsgStream.println("evt = " + evt); 957 } 958 959 /** 960 * How many applets are running? 961 */ 962 963 public static int countApplets() { 964 return appletPanels.size(); 965 } 966 967 968 /** 969 * The current character. 970 */ 971 static int c; 972 973 /** 974 * Scan spaces. 975 */ 976 public static void skipSpace(Reader in) throws IOException { 977 while ((c >= 0) && 978 ((c == ' ') || (c == '\t') || (c == '\n') || (c == '\r'))) { 979 c = in.read(); 980 } 981 } 982 983 /** 984 * Scan identifier 985 */ 986 public static String scanIdentifier(Reader in) throws IOException { 987 StringBuffer buf = new StringBuffer(); 988 while (true) { 989 if (((c >= 'a') && (c <= 'z')) || 990 ((c >= 'A') && (c <= 'Z')) || 991 ((c >= '0') && (c <= '9')) || (c == '_')) { 992 buf.append((char)c); 993 c = in.read(); 994 } else { 995 return buf.toString(); 996 } 997 } 998 } 999 1000 /** 1001 * Scan tag 1002 */ 1003 public static Hashtable scanTag(Reader in) throws IOException { 1004 Hashtable atts = new Hashtable(); 1005 skipSpace(in); 1006 while (c >= 0 && c != '>') { 1007 String att = scanIdentifier(in); 1008 String val = ""; 1009 skipSpace(in); 1010 if (c == '=') { 1011 int quote = -1; 1012 c = in.read(); 1013 skipSpace(in); 1014 if ((c == '\'') || (c == '\"')) { 1015 quote = c; 1016 c = in.read(); 1017 } 1018 StringBuffer buf = new StringBuffer(); 1019 while ((c > 0) && 1020 (((quote < 0) && (c != ' ') && (c != '\t') && 1021 (c != '\n') && (c != '\r') && (c != '>')) 1022 || ((quote >= 0) && (c != quote)))) { 1023 buf.append((char)c); 1024 c = in.read(); 1025 } 1026 if (c == quote) { 1027 c = in.read(); 1028 } 1029 skipSpace(in); 1030 val = buf.toString(); 1031 } 1032 //statusMsgStream.println("PUT " + att + " = '" + val + "'"); 1033 if (! val.equals("")) { 1034 atts.put(att.toLowerCase(java.util.Locale.ENGLISH), val); 1035 } 1036 while (true) { 1037 if ((c == '>') || (c < 0) || 1038 ((c >= 'a') && (c <= 'z')) || 1039 ((c >= 'A') && (c <= 'Z')) || 1040 ((c >= '0') && (c <= '9')) || (c == '_')) 1041 break; 1042 c = in.read(); 1043 } 1044 //skipSpace(in); 1045 } 1046 return atts; 1047 } 1048 1049 /* values used for placement of AppletViewer's frames */ 1050 private static int x = 0; 1051 private static int y = 0; 1052 private static final int XDELTA = 30; 1053 private static final int YDELTA = XDELTA; 1054 1055 static String encoding = null; 1056 1057 static private Reader makeReader(InputStream is) { 1058 if (encoding != null) { 1059 try { 1060 return new BufferedReader(new InputStreamReader(is, encoding)); 1061 } catch (IOException x) { } 1062 } 1063 InputStreamReader r = new InputStreamReader(is); 1064 encoding = r.getEncoding(); 1065 return new BufferedReader(r); 1066 } 1067 1068 /** 1069 * Scan an html file for <applet> tags 1070 */ 1071 public static void parse(URL url, String enc) throws IOException { 1072 encoding = enc; 1073 parse(url, System.out, new StdAppletViewerFactory()); 1074 } 1075 1076 public static void parse(URL url) throws IOException { 1077 parse(url, System.out, new StdAppletViewerFactory()); 1078 } 1079 1080 public static void parse(URL url, PrintStream statusMsgStream, 1081 AppletViewerFactory factory) throws IOException { 1082 // <OBJECT> <EMBED> tag flags 1083 boolean isAppletTag = false; 1084 boolean isObjectTag = false; 1085 boolean isEmbedTag = false; 1086 1087 // warning messages 1088 String requiresNameWarning = amh.getMessage("parse.warning.requiresname"); 1089 String paramOutsideWarning = amh.getMessage("parse.warning.paramoutside"); 1090 String appletRequiresCodeWarning = amh.getMessage("parse.warning.applet.requirescode"); 1091 String appletRequiresHeightWarning = amh.getMessage("parse.warning.applet.requiresheight"); 1092 String appletRequiresWidthWarning = amh.getMessage("parse.warning.applet.requireswidth"); 1093 String objectRequiresCodeWarning = amh.getMessage("parse.warning.object.requirescode"); 1094 String objectRequiresHeightWarning = amh.getMessage("parse.warning.object.requiresheight"); 1095 String objectRequiresWidthWarning = amh.getMessage("parse.warning.object.requireswidth"); 1096 String embedRequiresCodeWarning = amh.getMessage("parse.warning.embed.requirescode"); 1097 String embedRequiresHeightWarning = amh.getMessage("parse.warning.embed.requiresheight"); 1098 String embedRequiresWidthWarning = amh.getMessage("parse.warning.embed.requireswidth"); 1099 String appNotLongerSupportedWarning = amh.getMessage("parse.warning.appnotLongersupported"); 1100 1101 java.net.URLConnection conn = url.openConnection(); 1102 Reader in = makeReader(conn.getInputStream()); 1103 /* The original URL may have been redirected - this 1104 * sets it to whatever URL/codebase we ended up getting 1105 */ 1106 url = conn.getURL(); 1107 1108 int ydisp = 1; 1109 Hashtable atts = null; 1110 1111 while(true) { 1112 c = in.read(); 1113 if (c == -1) 1114 break; 1115 1116 if (c == '<') { 1117 c = in.read(); 1118 if (c == '/') { 1119 c = in.read(); 1120 String nm = scanIdentifier(in); 1121 if (nm.equalsIgnoreCase("applet") || 1122 nm.equalsIgnoreCase("object") || 1123 nm.equalsIgnoreCase("embed")) { 1124 1125 // We can't test for a code tag until </OBJECT> 1126 // because it is a parameter, not an attribute. 1127 if(isObjectTag) { 1128 if (atts.get("code") == null && atts.get("object") == null) { 1129 statusMsgStream.println(objectRequiresCodeWarning); 1130 atts = null; 1131 } 1132 } 1133 1134 if (atts != null) { 1135 // XXX 5/18 In general this code just simply 1136 // shouldn't be part of parsing. It's presence 1137 // causes things to be a little too much of a 1138 // hack. 1139 factory.createAppletViewer(x, y, url, atts); 1140 x += XDELTA; 1141 y += YDELTA; 1142 // make sure we don't go too far! 1143 Dimension d = Toolkit.getDefaultToolkit().getScreenSize(); 1144 if ((x > d.width - 300) || (y > d.height - 300)) { 1145 x = 0; 1146 y = 2 * ydisp * YDELTA; 1147 ydisp++; 1148 } 1149 } 1150 atts = null; 1151 isAppletTag = false; 1152 isObjectTag = false; 1153 isEmbedTag = false; 1154 } 1155 } 1156 else { 1157 String nm = scanIdentifier(in); 1158 if (nm.equalsIgnoreCase("param")) { 1159 Hashtable t = scanTag(in); 1160 String att = (String)t.get("name"); 1161 if (att == null) { 1162 statusMsgStream.println(requiresNameWarning); 1163 } else { 1164 String val = (String)t.get("value"); 1165 if (val == null) { 1166 statusMsgStream.println(requiresNameWarning); 1167 } else if (atts != null) { 1168 atts.put(att.toLowerCase(), val); 1169 } else { 1170 statusMsgStream.println(paramOutsideWarning); 1171 } 1172 } 1173 } 1174 else if (nm.equalsIgnoreCase("applet")) { 1175 isAppletTag = true; 1176 atts = scanTag(in); 1177 if (atts.get("code") == null && atts.get("object") == null) { 1178 statusMsgStream.println(appletRequiresCodeWarning); 1179 atts = null; 1180 } else if (atts.get("width") == null) { 1181 statusMsgStream.println(appletRequiresWidthWarning); 1182 atts = null; 1183 } else if (atts.get("height") == null) { 1184 statusMsgStream.println(appletRequiresHeightWarning); 1185 atts = null; 1186 } 1187 } 1188 else if (nm.equalsIgnoreCase("object")) { 1189 isObjectTag = true; 1190 atts = scanTag(in); 1191 // The <OBJECT> attribute codebase isn't what 1192 // we want. If its defined, remove it. 1193 if(atts.get("codebase") != null) { 1194 atts.remove("codebase"); 1195 } 1196 1197 if (atts.get("width") == null) { 1198 statusMsgStream.println(objectRequiresWidthWarning); 1199 atts = null; 1200 } else if (atts.get("height") == null) { 1201 statusMsgStream.println(objectRequiresHeightWarning); 1202 atts = null; 1203 } 1204 } 1205 else if (nm.equalsIgnoreCase("embed")) { 1206 isEmbedTag = true; 1207 atts = scanTag(in); 1208 1209 if (atts.get("code") == null && atts.get("object") == null) { 1210 statusMsgStream.println(embedRequiresCodeWarning); 1211 atts = null; 1212 } else if (atts.get("width") == null) { 1213 statusMsgStream.println(embedRequiresWidthWarning); 1214 atts = null; 1215 } else if (atts.get("height") == null) { 1216 statusMsgStream.println(embedRequiresHeightWarning); 1217 atts = null; 1218 } 1219 } 1220 else if (nm.equalsIgnoreCase("app")) { 1221 statusMsgStream.println(appNotLongerSupportedWarning); 1222 Hashtable atts2 = scanTag(in); 1223 nm = (String)atts2.get("class"); 1224 if (nm != null) { 1225 atts2.remove("class"); 1226 atts2.put("code", nm + ".class"); 1227 } 1228 nm = (String)atts2.get("src"); 1229 if (nm != null) { 1230 atts2.remove("src"); 1231 atts2.put("codebase", nm); 1232 } 1233 if (atts2.get("width") == null) { 1234 atts2.put("width", "100"); 1235 } 1236 if (atts2.get("height") == null) { 1237 atts2.put("height", "100"); 1238 } 1239 printTag(statusMsgStream, atts2); 1240 statusMsgStream.println(); 1241 } 1242 } 1243 } 1244 } 1245 in.close(); 1246 } 1247 1248 /** 1249 * Old main entry point. 1250 * 1251 * @deprecated 1252 */ 1253 @Deprecated 1254 public static void main(String argv[]) { 1255 // re-route everything to the new main entry point 1256 Main.main(argv); 1257 } 1258 1259 private static AppletMessageHandler amh = new AppletMessageHandler("appletviewer"); 1260 1261 private static void checkConnect(URL url) 1262 { 1263 SecurityManager security = System.getSecurityManager(); 1264 if (security != null) { 1265 try { 1266 java.security.Permission perm = 1267 url.openConnection().getPermission(); 1268 if (perm != null) 1269 security.checkPermission(perm); 1270 else 1271 security.checkConnect(url.getHost(), url.getPort()); 1272 } catch (java.io.IOException ioe) { 1273 security.checkConnect(url.getHost(), url.getPort()); 1274 } 1275 } 1276 } 1277 } --- EOF ---