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