Showing the changes to java/pkg/sun/tools/jconsole/JConsole.java (1 of 18352 files). Show all
Unified · Split
| @@ -0,0 +1,1112 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2004, 2006, 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.tools.jconsole; | ||
| 27 | |||
| 28 | import java.awt.*; | ||
| 29 | import java.awt.event.*; | ||
| 30 | import java.beans.*; | ||
| 31 | import java.io.*; | ||
| 32 | import java.lang.reflect.InvocationTargetException; | ||
| 33 | import java.net.*; | ||
| 34 | import java.util.*; | ||
| 35 | import java.util.List; | ||
| 36 | |||
| 37 | import javax.swing.*; | ||
| 38 | import javax.swing.border.*; | ||
| 39 | import javax.swing.event.*; | ||
| 40 | import javax.swing.plaf.*; | ||
| 41 | import javax.management.remote.JMXServiceURL; | ||
| 42 | import javax.management.remote.JMXConnector; | ||
| 43 | import javax.security.auth.login.FailedLoginException; | ||
| 44 | import javax.net.ssl.SSLHandshakeException; | ||
| 45 | |||
| 46 | import com.sun.tools.jconsole.JConsolePlugin; | ||
| 47 | |||
| 48 | import sun.net.util.IPAddressUtil; | ||
| 49 | |||
| 50 | import static sun.tools.jconsole.Resources.*; | ||
| 51 | import static sun.tools.jconsole.Utilities.*; | ||
| 52 | |||
| 53 | @SuppressWarnings("serial") | ||
| 54 | public class JConsole extends JFrame | ||
| 55 | implements ActionListener, InternalFrameListener { | ||
| 56 | |||
| 57 | static /*final*/ boolean IS_GTK; | ||
| 58 | static /*final*/ boolean IS_WIN; | ||
| 59 | |||
| 60 | static { | ||
| 61 | // Apply the system L&F if it is GTK or Windows, and | ||
| 62 | // the L&F is not specified using a system property. | ||
| 63 | if (System.getProperty("swing.defaultlaf") == null) { | ||
| 64 | String systemLaF = UIManager.getSystemLookAndFeelClassName(); | ||
| 65 | if (systemLaF.equals("com.sun.java.swing.plaf.gtk.GTKLookAndFeel") || | ||
| 66 | systemLaF.equals("com.sun.java.swing.plaf.windows.WindowsLookAndFeel")) { | ||
| 67 | |||
| 68 | try { | ||
| 69 | UIManager.setLookAndFeel(systemLaF); | ||
| 70 | } catch (Exception e) { | ||
| 71 | System.err.println(Resources.getText("JConsole: ", e.getMessage())); | ||
| 72 | } | ||
| 73 | } | ||
| 74 | } | ||
| 75 | |||
| 76 | updateLafValues(); | ||
| 77 | } | ||
| 78 | |||
| 79 | |||
| 80 | static void updateLafValues() { | ||
| 81 | String lafName = UIManager.getLookAndFeel().getClass().getName(); | ||
| 82 | IS_GTK = lafName.equals("com.sun.java.swing.plaf.gtk.GTKLookAndFeel"); | ||
| 83 | IS_WIN = lafName.equals("com.sun.java.swing.plaf.windows.WindowsLookAndFeel"); | ||
| 84 | |||
| 85 | //BorderedComponent.updateLafValues(); | ||
| 86 | } | ||
| 87 | |||
| 88 | |||
| 89 | private final static String title = | ||
| 90 | Resources.getText("Java Monitoring & Management Console"); | ||
| 91 | public final static String ROOT_URL = | ||
| 92 | "service:jmx:"; | ||
| 93 | |||
| 94 | private static int updateInterval = 4000; | ||
| 95 | private static String pluginPath = ""; | ||
| 96 | |||
| 97 | private JMenuBar menuBar; | ||
| 98 | private JMenuItem hotspotMI, connectMI, exitMI; | ||
| 99 | private WindowMenu windowMenu; | ||
| 100 | private JMenuItem tileMI, cascadeMI, minimizeAllMI, restoreAllMI; | ||
| 101 | private JMenuItem userGuideMI, aboutMI; | ||
| 102 | |||
| 103 | private JButton connectButton; | ||
| 104 | private JDesktopPane desktop; | ||
| 105 | private ConnectDialog connectDialog; | ||
| 106 | private CreateMBeanDialog createDialog; | ||
| 107 | |||
| 108 | private ArrayList<VMInternalFrame> windows = | ||
| 109 | new ArrayList<VMInternalFrame>(); | ||
| 110 | |||
| 111 | private int frameLoc = 5; | ||
| 112 | static boolean debug; | ||
| 113 | |||
| 114 | public JConsole(boolean hotspot) { | ||
| 115 | super(title); | ||
| 116 | |||
| 117 | setRootPane(new FixedJRootPane()); | ||
| 118 | setAccessibleDescription(this, | ||
| 119 | getText("JConsole.accessibleDescription")); | ||
| 120 | setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); | ||
| 121 | |||
| 122 | menuBar = new JMenuBar(); | ||
| 123 | setJMenuBar(menuBar); | ||
| 124 | |||
| 125 | // TODO: Use Actions ! | ||
| 126 | |||
| 127 | JMenu connectionMenu = new JMenu(getText("Connection")); | ||
| 128 | connectionMenu.setMnemonic(getMnemonicInt("Connection")); | ||
| 129 | menuBar.add(connectionMenu); | ||
| 130 | if(hotspot) { | ||
| 131 | hotspotMI = new JMenuItem(getText("Hotspot MBeans...")); | ||
| 132 | hotspotMI.setMnemonic(getMnemonicInt("Hotspot MBeans...")); | ||
| 133 | hotspotMI.setAccelerator(KeyStroke. | ||
| 134 | getKeyStroke(KeyEvent.VK_H, | ||
| 135 | InputEvent.CTRL_MASK)); | ||
| 136 | hotspotMI.addActionListener(this); | ||
| 137 | connectionMenu.add(hotspotMI); | ||
| 138 | |||
| 139 | connectionMenu.addSeparator(); | ||
| 140 | } | ||
| 141 | |||
| 142 | connectMI = new JMenuItem(Resources.getText("New Connection...")); | ||
| 143 | connectMI.setMnemonic(getMnemonicInt("New Connection...")); | ||
| 144 | connectMI.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N, | ||
| 145 | InputEvent.CTRL_MASK)); | ||
| 146 | connectMI.addActionListener(this); | ||
| 147 | connectionMenu.add(connectMI); | ||
| 148 | |||
| 149 | connectionMenu.addSeparator(); | ||
| 150 | |||
| 151 | exitMI = new JMenuItem(Resources.getText("Exit")); | ||
| 152 | exitMI.setMnemonic(getMnemonicInt("Exit")); | ||
| 153 | exitMI.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F4, | ||
| 154 | InputEvent.ALT_MASK)); | ||
| 155 | exitMI.addActionListener(this); | ||
| 156 | connectionMenu.add(exitMI); | ||
| 157 | |||
| 158 | |||
| 159 | JMenu helpMenu = new JMenu(getText("HelpMenu.title")); | ||
| 160 | helpMenu.setMnemonic(getMnemonicInt("HelpMenu.title")); | ||
| 161 | menuBar.add(helpMenu); | ||
| 162 | |||
| 163 | if (AboutDialog.isBrowseSupported()) { | ||
| 164 | userGuideMI = new JMenuItem(getText("HelpMenu.UserGuide.title")); | ||
| 165 | userGuideMI.setMnemonic(getMnemonicInt("HelpMenu.UserGuide.title")); | ||
| 166 | userGuideMI.addActionListener(this); | ||
| 167 | helpMenu.add(userGuideMI); | ||
| 168 | helpMenu.addSeparator(); | ||
| 169 | } | ||
| 170 | aboutMI = new JMenuItem(getText("HelpMenu.About.title")); | ||
| 171 | aboutMI.setMnemonic(getMnemonicInt("HelpMenu.About.title")); | ||
| 172 | aboutMI.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F1, 0)); | ||
| 173 | aboutMI.addActionListener(this); | ||
| 174 | helpMenu.add(aboutMI); | ||
| 175 | } | ||
| 176 | |||
| 177 | public JDesktopPane getDesktopPane() { | ||
| 178 | return desktop; | ||
| 179 | } | ||
| 180 | |||
| 181 | public List<VMInternalFrame> getInternalFrames() { | ||
| 182 | return windows; | ||
| 183 | } | ||
| 184 | |||
| 185 | private void createMDI() { | ||
| 186 | // Restore title - we now show connection name on internal frames | ||
| 187 | setTitle(title); | ||
| 188 | |||
| 189 | Container cp = getContentPane(); | ||
| 190 | Component oldCenter = | ||
| 191 | ((BorderLayout)cp.getLayout()). | ||
| 192 | getLayoutComponent(BorderLayout.CENTER); | ||
| 193 | |||
| 194 | windowMenu = new WindowMenu(Resources.getText("Window")); | ||
| 195 | windowMenu.setMnemonic(getMnemonicInt("Window")); | ||
| 196 | // Add Window menu before Help menu | ||
| 197 | menuBar.add(windowMenu, menuBar.getComponentCount() - 1); | ||
| 198 | |||
| 199 | desktop = new JDesktopPane(); | ||
| 200 | desktop.setBackground(new Color(235, 245, 255)); | ||
| 201 | |||
| 202 | cp.add(desktop, BorderLayout.CENTER); | ||
| 203 | |||
| 204 | if (oldCenter instanceof VMPanel) { | ||
| 205 | addFrame((VMPanel)oldCenter); | ||
| 206 | } | ||
| 207 | } | ||
| 208 | |||
| 209 | private class WindowMenu extends JMenu { | ||
| 210 | VMInternalFrame[] windowMenuWindows = new VMInternalFrame[0]; | ||
| 211 | int separatorPosition; | ||
| 212 | |||
| 213 | // The width value of viewR is used to truncate long menu items. | ||
| 214 | // The rest are placeholders and are ignored for this purpose. | ||
| 215 | Rectangle viewR = new Rectangle(0, 0, 400, 20); | ||
| 216 | Rectangle textR = new Rectangle(0, 0, 0, 0); | ||
| 217 | Rectangle iconR = new Rectangle(0, 0, 0, 0); | ||
| 218 | |||
| 219 | WindowMenu(String text) { | ||
| 220 | super(text); | ||
| 221 | |||
| 222 | cascadeMI = new JMenuItem(Resources.getText("Cascade")); | ||
| 223 | cascadeMI.setMnemonic(getMnemonicInt("Cascade")); | ||
| 224 | cascadeMI.addActionListener(JConsole.this); | ||
| 225 | add(cascadeMI); | ||
| 226 | |||
| 227 | tileMI = new JMenuItem(Resources.getText("Tile")); | ||
| 228 | tileMI.setMnemonic(getMnemonicInt("Tile")); | ||
| 229 | tileMI.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_T, | ||
| 230 | InputEvent.CTRL_MASK)); | ||
| 231 | tileMI.addActionListener(JConsole.this); | ||
| 232 | add(tileMI); | ||
| 233 | |||
| 234 | minimizeAllMI = new JMenuItem(Resources.getText("Minimize All")); | ||
| 235 | minimizeAllMI.setMnemonic(getMnemonicInt("Minimize All")); | ||
| 236 | minimizeAllMI.addActionListener(JConsole.this); | ||
| 237 | add(minimizeAllMI); | ||
| 238 | |||
| 239 | restoreAllMI = new JMenuItem(Resources.getText("Restore All")); | ||
| 240 | restoreAllMI.setMnemonic(getMnemonicInt("Restore All")); | ||
| 241 | restoreAllMI.addActionListener(JConsole.this); | ||
| 242 | add(restoreAllMI); | ||
| 243 | |||
| 244 | separatorPosition = getMenuComponentCount(); | ||
| 245 | } | ||
| 246 | |||
| 247 | private void add(VMInternalFrame vmIF) { | ||
| 248 | if (separatorPosition == getMenuComponentCount()) { | ||
| 249 | addSeparator(); | ||
| 250 | } | ||
| 251 | |||
| 252 | int index = -1; | ||
| 253 | int position = separatorPosition + 1; | ||
| 254 | int n = windowMenuWindows.length; | ||
| 255 | |||
| 256 | for (int i = 0; i < n; i++) { | ||
| 257 | if (windowMenuWindows[i] != null) { | ||
| 258 | // Slot is in use, try next | ||
| 259 | position++; | ||
| 260 | } else { | ||
| 261 | // Found a free slot | ||
| 262 | index = i; | ||
| 263 | break; | ||
| 264 | } | ||
| 265 | } | ||
| 266 | |||
| 267 | if (index == -1) { | ||
| 268 | // Create a slot at the end | ||
| 269 | VMInternalFrame[] newArray = new VMInternalFrame[n + 1]; | ||
| 270 | System.arraycopy(windowMenuWindows, 0, newArray, 0, n); | ||
| 271 | windowMenuWindows = newArray; | ||
| 272 | index = n; | ||
| 273 | } | ||
| 274 | |||
| 275 | windowMenuWindows[index] = vmIF; | ||
| 276 | |||
| 277 | String indexString = "" + (index+1); | ||
| 278 | String vmName = vmIF.getVMPanel().getDisplayName(); | ||
| 279 | // Maybe truncate menu item string and end with "..." | ||
| 280 | String text = | ||
| 281 | SwingUtilities.layoutCompoundLabel(this, | ||
| 282 | getGraphics().getFontMetrics(getFont()), | ||
| 283 | indexString + " " + vmName, | ||
| 284 | null, 0, 0, 0, 0, | ||
| 285 | viewR, iconR, textR, 0); | ||
| 286 | JMenuItem mi = new JMenuItem(text); | ||
| 287 | if (text.endsWith("...")) { | ||
| 288 | mi.setToolTipText(vmName); | ||
| 289 | } | ||
| 290 | |||
| 291 | // Set mnemonic using last digit of number | ||
| 292 | int nDigits = indexString.length(); | ||
| 293 | mi.setMnemonic(indexString.charAt(nDigits-1)); | ||
| 294 | mi.setDisplayedMnemonicIndex(nDigits-1); | ||
| 295 | |||
| 296 | mi.putClientProperty("JConsole.vmIF", vmIF); | ||
| 297 | mi.addActionListener(JConsole.this); | ||
| 298 | vmIF.putClientProperty("JConsole.menuItem", mi); | ||
| 299 | add(mi, position); | ||
| 300 | } | ||
| 301 | |||
| 302 | private void remove(VMInternalFrame vmIF) { | ||
| 303 | for (int i = 0; i < windowMenuWindows.length; i++) { | ||
| 304 | if (windowMenuWindows[i] == vmIF) { | ||
| 305 | windowMenuWindows[i] = null; | ||
| 306 | } | ||
| 307 | } | ||
| 308 | JMenuItem mi = (JMenuItem)vmIF.getClientProperty("JConsole.menuItem"); | ||
| 309 | remove(mi); | ||
| 310 | mi.putClientProperty("JConsole.vmIF", null); | ||
| 311 | vmIF.putClientProperty("JConsole.menuItem", null); | ||
| 312 | |||
| 313 | if (separatorPosition == getMenuComponentCount() - 1) { | ||
| 314 | remove(getMenuComponent(getMenuComponentCount() - 1)); | ||
| 315 | } | ||
| 316 | } | ||
| 317 | } | ||
| 318 | |||
| 319 | public void actionPerformed(ActionEvent ev) { | ||
| 320 | Object src = ev.getSource(); | ||
| 321 | if (src == hotspotMI) { | ||
| 322 | showCreateMBeanDialog(); | ||
| 323 | } | ||
| 324 | |||
| 325 | if (src == connectButton || src == connectMI) { | ||
| 326 | VMPanel vmPanel = null; | ||
| 327 | JInternalFrame vmIF = desktop.getSelectedFrame(); | ||
| 328 | if (vmIF instanceof VMInternalFrame) { | ||
| 329 | vmPanel = ((VMInternalFrame)vmIF).getVMPanel(); | ||
| 330 | } | ||
| 331 | String hostName = ""; | ||
| 332 | String url = ""; | ||
| 333 | if (vmPanel != null) { | ||
| 334 | hostName = vmPanel.getHostName(); | ||
| 335 | if(vmPanel.getUrl() != null) | ||
| 336 | url = vmPanel.getUrl(); | ||
| 337 | } | ||
| 338 | showConnectDialog(url, hostName, 0, null, null, null); | ||
| 339 | } else if (src == tileMI) { | ||
| 340 | tileWindows(); | ||
| 341 | } else if (src == cascadeMI) { | ||
| 342 | cascadeWindows(); | ||
| 343 | } else if (src == minimizeAllMI) { | ||
| 344 | for (VMInternalFrame vmIF : windows) { | ||
| 345 | try { | ||
| 346 | vmIF.setIcon(true); | ||
| 347 | } catch (PropertyVetoException ex) { | ||
| 348 | // Ignore | ||
| 349 | } | ||
| 350 | } | ||
| 351 | } else if (src == restoreAllMI) { | ||
| 352 | for (VMInternalFrame vmIF : windows) { | ||
| 353 | try { | ||
| 354 | vmIF.setIcon(false); | ||
| 355 | } catch (PropertyVetoException ex) { | ||
| 356 | // Ignore | ||
| 357 | } | ||
| 358 | } | ||
| 359 | } else if (src == exitMI) { | ||
| 360 | System.exit(0); | ||
| 361 | } else if (src == userGuideMI) { | ||
| 362 | AboutDialog.browseUserGuide(this); | ||
| 363 | } else if (src == aboutMI) { | ||
| 364 | AboutDialog.showAboutDialog(this); | ||
| 365 | } else if (src instanceof JMenuItem) { | ||
| 366 | JMenuItem mi = (JMenuItem)src; | ||
| 367 | VMInternalFrame vmIF = (VMInternalFrame)mi. | ||
| 368 | getClientProperty("JConsole.vmIF"); | ||
| 369 | if (vmIF != null) { | ||
| 370 | try { | ||
| 371 | vmIF.setIcon(false); | ||
| 372 | vmIF.setSelected(true); | ||
| 373 | } catch (PropertyVetoException ex) { | ||
| 374 | // Ignore | ||
| 375 | } | ||
| 376 | vmIF.moveToFront(); | ||
| 377 | } | ||
| 378 | } | ||
| 379 | } | ||
| 380 | |||
| 381 | |||
| 382 | public void tileWindows() { | ||
| 383 | int w = -1; | ||
| 384 | int h = -1; | ||
| 385 | int n = 0; | ||
| 386 | for (VMInternalFrame vmIF : windows) { | ||
| 387 | if (!vmIF.isIcon()) { | ||
| 388 | n++; | ||
| 389 | if (w == -1) { | ||
| 390 | try { | ||
| 391 | vmIF.setMaximum(true); | ||
| 392 | w = vmIF.getWidth(); | ||
| 393 | h = vmIF.getHeight(); | ||
| 394 | } catch (PropertyVetoException ex) { | ||
| 395 | // Ignore | ||
| 396 | } | ||
| 397 | } | ||
| 398 | } | ||
| 399 | } | ||
| 400 | if (n > 0 && w > 0 && h > 0) { | ||
| 401 | int rows = (int)Math.ceil(Math.sqrt(n)); | ||
| 402 | int cols = n / rows; | ||
| 403 | if (rows * cols < n) cols++; | ||
| 404 | int x = 0; | ||
| 405 | int y = 0; | ||
| 406 | w /= cols; | ||
| 407 | h /= rows; | ||
| 408 | int col = 0; | ||
| 409 | for (VMInternalFrame vmIF : windows) { | ||
| 410 | if (!vmIF.isIcon()) { | ||
| 411 | try { | ||
| 412 | vmIF.setMaximum(n==1); | ||
| 413 | } catch (PropertyVetoException ex) { | ||
| 414 | // Ignore | ||
| 415 | } | ||
| 416 | if (n > 1) { | ||
| 417 | vmIF.setBounds(x, y, w, h); | ||
| 418 | } | ||
| 419 | if (col < cols-1) { | ||
| 420 | col++; | ||
| 421 | x += w; | ||
| 422 | } else { | ||
| 423 | col = 0; | ||
| 424 | x = 0; | ||
| 425 | y += h; | ||
| 426 | } | ||
| 427 | } | ||
| 428 | } | ||
| 429 | } | ||
| 430 | } | ||
| 431 | |||
| 432 | public void cascadeWindows() { | ||
| 433 | int n = 0; | ||
| 434 | int w = -1; | ||
| 435 | int h = -1; | ||
| 436 | for (VMInternalFrame vmIF : windows) { | ||
| 437 | if (!vmIF.isIcon()) { | ||
| 438 | try { | ||
| 439 | vmIF.setMaximum(false); | ||
| 440 | } catch (PropertyVetoException ex) { | ||
| 441 | // Ignore | ||
| 442 | } | ||
| 443 | n++; | ||
| 444 | vmIF.pack(); | ||
| 445 | if (w == -1) { | ||
| 446 | try { | ||
| 447 | w = vmIF.getWidth(); | ||
| 448 | h = vmIF.getHeight(); | ||
| 449 | vmIF.setMaximum(true); | ||
| 450 | w = vmIF.getWidth() - w; | ||
| 451 | h = vmIF.getHeight() - h; | ||
| 452 | vmIF.pack(); | ||
| 453 | } catch (PropertyVetoException ex) { | ||
| 454 | // Ignore | ||
| 455 | } | ||
| 456 | } | ||
| 457 | } | ||
| 458 | } | ||
| 459 | int x = 0; | ||
| 460 | int y = 0; | ||
| 461 | int dX = (n > 1) ? (w / (n - 1)) : 0; | ||
| 462 | int dY = (n > 1) ? (h / (n - 1)) : 0; | ||
| 463 | for (VMInternalFrame vmIF : windows) { | ||
| 464 | if (!vmIF.isIcon()) { | ||
| 465 | vmIF.setLocation(x, y); | ||
| 466 | vmIF.moveToFront(); | ||
| 467 | x += dX; | ||
| 468 | y += dY; | ||
| 469 | } | ||
| 470 | } | ||
| 471 | } | ||
| 472 | |||
| 473 | // Call on EDT | ||
| 474 | void addHost(String hostName, int port, | ||
| 475 | String userName, String password) { | ||
| 476 | addHost(hostName, port, userName, password, false); | ||
| 477 | } | ||
| 478 | |||
| 479 | // Call on EDT | ||
| 480 | void addVmid(LocalVirtualMachine lvm) { | ||
| 481 | addVmid(lvm, false); | ||
| 482 | } | ||
| 483 | |||
| 484 | // Call on EDT | ||
| 485 | void addVmid(final LocalVirtualMachine lvm, final boolean tile) { | ||
| 486 | new Thread("JConsole.addVmid") { | ||
| 487 | public void run() { | ||
| 488 | try { | ||
| 489 | addProxyClient(ProxyClient.getProxyClient(lvm), tile); | ||
| 490 | } catch (final SecurityException ex) { | ||
| 491 | failed(ex, null, null, null); | ||
| 492 | } catch (final IOException ex) { | ||
| 493 | failed(ex, null, null, null); | ||
| 494 | } | ||
| 495 | } | ||
| 496 | }.start(); | ||
| 497 | } | ||
| 498 | |||
| 499 | // Call on EDT | ||
| 500 | void addUrl(final String url, | ||
| 501 | final String userName, | ||
| 502 | final String password, | ||
| 503 | final boolean tile) { | ||
| 504 | new Thread("JConsole.addUrl") { | ||
| 505 | public void run() { | ||
| 506 | try { | ||
| 507 | addProxyClient(ProxyClient.getProxyClient(url, userName, password), | ||
| 508 | tile); | ||
| 509 | } catch (final MalformedURLException ex) { | ||
| 510 | failed(ex, url, userName, password); | ||
| 511 | } catch (final SecurityException ex) { | ||
| 512 | failed(ex, url, userName, password); | ||
| 513 | } catch (final IOException ex) { | ||
| 514 | failed(ex, url, userName, password); | ||
| 515 | } | ||
| 516 | } | ||
| 517 | }.start(); | ||
| 518 | } | ||
| 519 | |||
| 520 | |||
| 521 | // Call on EDT | ||
| 522 | void addHost(final String hostName, final int port, | ||
| 523 | final String userName, final String password, | ||
| 524 | final boolean tile) { | ||
| 525 | new Thread("JConsole.addHost") { | ||
| 526 | public void run() { | ||
| 527 | try { | ||
| 528 | addProxyClient(ProxyClient.getProxyClient(hostName, port, | ||
| 529 | userName, password), | ||
| 530 | tile); | ||
| 531 | } catch (final IOException ex) { | ||
| 532 | dbgStackTrace(ex); | ||
| 533 | SwingUtilities.invokeLater(new Runnable() { | ||
| 534 | public void run() { | ||
| 535 | showConnectDialog(null, hostName, port, | ||
| 536 | userName, password, errorMessage(ex)); | ||
| 537 | } | ||
| 538 | }); | ||
| 539 | } | ||
| 540 | } | ||
| 541 | }.start(); | ||
| 542 | } | ||
| 543 | |||
| 544 | |||
| 545 | // Call on worker thread | ||
| 546 | void addProxyClient(final ProxyClient proxyClient, final boolean tile) { | ||
| 547 | SwingUtilities.invokeLater(new Runnable() { | ||
| 548 | public void run() { | ||
| 549 | VMPanel vmPanel = new VMPanel(proxyClient, updateInterval); | ||
| 550 | addFrame(vmPanel); | ||
| 551 | |||
| 552 | if (tile) { | ||
| 553 | SwingUtilities.invokeLater(new Runnable() { | ||
| 554 | public void run() { | ||
| 555 | tileWindows(); | ||
| 556 | } | ||
| 557 | }); | ||
| 558 | } | ||
| 559 | vmPanel.connect(); | ||
| 560 | } | ||
| 561 | }); | ||
| 562 | } | ||
| 563 | |||
| 564 | |||
| 565 | // Call on worker thread | ||
| 566 | private void failed(final Exception ex, | ||
| 567 | final String url, | ||
| 568 | final String userName, | ||
| 569 | final String password) { | ||
| 570 | SwingUtilities.invokeLater(new Runnable() { | ||
| 571 | public void run() { | ||
| 572 | dbgStackTrace(ex); | ||
| 573 | showConnectDialog(url, | ||
| 574 | null, | ||
| 575 | -1, | ||
| 576 | userName, | ||
| 577 | password, | ||
| 578 | errorMessage(ex)); | ||
| 579 | } | ||
| 580 | }); | ||
| 581 | } | ||
| 582 | |||
| 583 | |||
| 584 | private VMInternalFrame addFrame(VMPanel vmPanel) { | ||
| 585 | final VMInternalFrame vmIF = new VMInternalFrame(vmPanel); | ||
| 586 | |||
| 587 | for (VMInternalFrame f : windows) { | ||
| 588 | try { | ||
| 589 | f.setMaximum(false); | ||
| 590 | } catch (PropertyVetoException ex) { | ||
| 591 | // Ignore | ||
| 592 | } | ||
| 593 | } | ||
| 594 | desktop.add(vmIF); | ||
| 595 | |||
| 596 | vmIF.setLocation(frameLoc, frameLoc); | ||
| 597 | frameLoc += 30; | ||
| 598 | vmIF.setVisible(true); | ||
| 599 | windows.add(vmIF); | ||
| 600 | if (windows.size() == 1) { | ||
| 601 | try { | ||
| 602 | vmIF.setMaximum(true); | ||
| 603 | } catch (PropertyVetoException ex) { | ||
| 604 | // Ignore | ||
| 605 | } | ||
| 606 | } | ||
| 607 | vmIF.addInternalFrameListener(this); | ||
| 608 | windowMenu.add(vmIF); | ||
| 609 | |||
| 610 | return vmIF; | ||
| 611 | } | ||
| 612 | |||
| 613 | private void showConnectDialog(String url, | ||
| 614 | String hostName, | ||
| 615 | int port, | ||
| 616 | String userName, | ||
| 617 | String password, | ||
| 618 | String msg) { | ||
| 619 | if (connectDialog == null) { | ||
| 620 | connectDialog = new ConnectDialog(this); | ||
| 621 | } | ||
| 622 | connectDialog.setConnectionParameters(url, | ||
| 623 | hostName, | ||
| 624 | port, | ||
| 625 | userName, | ||
| 626 | password, | ||
| 627 | msg); | ||
| 628 | |||
| 629 | connectDialog.refresh(); | ||
| 630 | connectDialog.setVisible(true); | ||
| 631 | try { | ||
| 632 | // Bring to front of other dialogs | ||
| 633 | connectDialog.setSelected(true); | ||
| 634 | } catch (PropertyVetoException e) { | ||
| 635 | } | ||
| 636 | } | ||
| 637 | |||
| 638 | private void showCreateMBeanDialog() { | ||
| 639 | if (createDialog == null) { | ||
| 640 | createDialog = new CreateMBeanDialog(this); | ||
| 641 | } | ||
| 642 | createDialog.setVisible(true); | ||
| 643 | try { | ||
| 644 | // Bring to front of other dialogs | ||
| 645 | createDialog.setSelected(true); | ||
| 646 | } catch (PropertyVetoException e) { | ||
| 647 | } | ||
| 648 | } | ||
| 649 | |||
| 650 | private void removeVMInternalFrame(VMInternalFrame vmIF) { | ||
| 651 | windowMenu.remove(vmIF); | ||
| 652 | desktop.remove(vmIF); | ||
| 653 | desktop.repaint(); | ||
| 654 | vmIF.getVMPanel().cleanUp(); | ||
| 655 | vmIF.dispose(); | ||
| 656 | } | ||
| 657 | |||
| 658 | private boolean isProxyClientUsed(ProxyClient client) { | ||
| 659 | for(VMInternalFrame frame : windows) { | ||
| 660 | ProxyClient cli = frame.getVMPanel().getProxyClient(false); | ||
| 661 | if(client == cli) | ||
| 662 | return true; | ||
| 663 | } | ||
| 664 | return false; | ||
| 665 | } | ||
| 666 | |||
| 667 | static boolean isValidRemoteString(String txt) { | ||
| 668 | boolean valid = false; | ||
| 669 | if (txt != null) { | ||
| 670 | txt = txt.trim(); | ||
| 671 | if (txt.startsWith(ROOT_URL)) { | ||
| 672 | if (txt.length() > ROOT_URL.length()) { | ||
| 673 | valid = true; | ||
| 674 | } | ||
| 675 | } else { | ||
| 676 | //--------------------------------------- | ||
| 677 | // Supported host and port combinations: | ||
| 678 | // hostname:port | ||
| 679 | // IPv4Address:port | ||
| 680 | // [IPv6Address]:port | ||
| 681 | //--------------------------------------- | ||
| 682 | |||
| 683 | // Is literal IPv6 address? | ||
| 684 | // | ||
| 685 | if (txt.startsWith("[")) { | ||
| 686 | int index = txt.indexOf("]:"); | ||
| 687 | if (index != -1) { | ||
| 688 | // Extract literal IPv6 address | ||
| 689 | // | ||
| 690 | String address = txt.substring(1, index); | ||
| 691 | if (IPAddressUtil.isIPv6LiteralAddress(address)) { | ||
| 692 | // Extract port | ||
| 693 | // | ||
| 694 | try { | ||
| 695 | String portStr = txt.substring(index + 2); | ||
| 696 | int port = Integer.parseInt(portStr); | ||
| 697 | if (port >= 0 && port <= 0xFFFF) { | ||
| 698 | valid = true; | ||
| 699 | } | ||
| 700 | } catch (NumberFormatException ex) { | ||
| 701 | valid = false; | ||
| 702 | } | ||
| 703 | } | ||
| 704 | } | ||
| 705 | } else { | ||
| 706 | String[] s = txt.split(":"); | ||
| 707 | if (s.length == 2) { | ||
| 708 | try { | ||
| 709 | int port = Integer.parseInt(s[1]); | ||
| 710 | if (port >= 0 && port <= 0xFFFF) { | ||
| 711 | valid = true; | ||
| 712 | } | ||
| 713 | } catch (NumberFormatException ex) { | ||
| 714 | valid = false; | ||
| 715 | } | ||
| 716 | } | ||
| 717 | } | ||
| 718 | } | ||
| 719 | } | ||
| 720 | return valid; | ||
| 721 | } | ||
| 722 | |||
| 723 | private String errorMessage(Exception ex) { | ||
| 724 | String msg = Resources.getText("Connection failed"); | ||
| 725 | if (ex instanceof IOException || ex instanceof SecurityException) { | ||
| 726 | Throwable cause = null; | ||
| 727 | Throwable c = ex.getCause(); | ||
| 728 | while (c != null) { | ||
| 729 | cause = c; | ||
| 730 | c = c.getCause(); | ||
| 731 | } | ||
| 732 | if (cause instanceof ConnectException) { | ||
| 733 | return msg + ": " + cause.getMessage(); | ||
| 734 | } else if (cause instanceof UnknownHostException) { | ||
| 735 | return Resources.getText("Unknown Host", cause.getMessage()); | ||
| 736 | } else if (cause instanceof NoRouteToHostException) { | ||
| 737 | return msg + ": " + cause.getMessage(); | ||
| 738 | } else if (cause instanceof FailedLoginException) { | ||
| 739 | return msg + ": " + cause.getMessage(); | ||
| 740 | } else if (cause instanceof SSLHandshakeException) { | ||
| 741 | return msg + ": "+ cause.getMessage(); | ||
| 742 | } | ||
| 743 | } else if (ex instanceof MalformedURLException) { | ||
| 744 | return Resources.getText("Invalid URL", ex.getMessage()); | ||
| 745 | } | ||
| 746 | return msg + ": " + ex.getMessage(); | ||
| 747 | } | ||
| 748 | |||
| 749 | |||
| 750 | // InternalFrameListener interface | ||
| 751 | |||
| 752 | public void internalFrameClosing(InternalFrameEvent e) { | ||
| 753 | VMInternalFrame vmIF = (VMInternalFrame)e.getInternalFrame(); | ||
| 754 | removeVMInternalFrame(vmIF); | ||
| 755 | windows.remove(vmIF); | ||
| 756 | ProxyClient client = vmIF.getVMPanel().getProxyClient(false); | ||
| 757 | if(!isProxyClientUsed(client)) | ||
| 758 | client.markAsDead(); | ||
| 759 | if (windows.size() == 0) { | ||
| 760 | showConnectDialog("", "", 0, null, null, null); | ||
| 761 | } | ||
| 762 | } | ||
| 763 | |||
| 764 | public void internalFrameOpened(InternalFrameEvent e) {} | ||
| 765 | public void internalFrameClosed(InternalFrameEvent e) {} | ||
| 766 | public void internalFrameIconified(InternalFrameEvent e) {} | ||
| 767 | public void internalFrameDeiconified(InternalFrameEvent e) {} | ||
| 768 | public void internalFrameActivated(InternalFrameEvent e) {} | ||
| 769 | public void internalFrameDeactivated(InternalFrameEvent e) {} | ||
| 770 | |||
| 771 | |||
| 772 | private static void usage() { | ||
| 773 | System.err.println(Resources.getText("zz usage text", "jconsole")); | ||
| 774 | } | ||
| 775 | |||
| 776 | private static void mainInit(final List<String> urls, | ||
| 777 | final List<String> hostNames, | ||
| 778 | final List<Integer> ports, | ||
| 779 | final List<LocalVirtualMachine> vmids, | ||
| 780 | final ProxyClient proxyClient, | ||
| 781 | final boolean noTile, | ||
| 782 | final boolean hotspot) { | ||
| 783 | |||
| 784 | |||
| 785 | // Always create Swing GUI on the Event Dispatching Thread | ||
| 786 | SwingUtilities.invokeLater(new Runnable() { | ||
| 787 | public void run() { | ||
| 788 | JConsole jConsole = new JConsole(hotspot); | ||
| 789 | |||
| 790 | // Center the window on screen, taking into account screen | ||
| 791 | // size and insets. | ||
| 792 | Toolkit toolkit = Toolkit.getDefaultToolkit(); | ||
| 793 | GraphicsConfiguration gc = jConsole.getGraphicsConfiguration(); | ||
| 794 | Dimension scrSize = toolkit.getScreenSize(); | ||
| 795 | Insets scrInsets = toolkit.getScreenInsets(gc); | ||
| 796 | Rectangle scrBounds = | ||
| 797 | new Rectangle(scrInsets.left, scrInsets.top, | ||
| 798 | scrSize.width - scrInsets.left - scrInsets.right, | ||
| 799 | scrSize.height - scrInsets.top - scrInsets.bottom); | ||
| 800 | int w = Math.min(900, scrBounds.width); | ||
| 801 | int h = Math.min(750, scrBounds.height); | ||
| 802 | jConsole.setBounds(scrBounds.x + (scrBounds.width - w) / 2, | ||
| 803 | scrBounds.y + (scrBounds.height - h) / 2, | ||
| 804 | w, h); | ||
| 805 | |||
| 806 | jConsole.setVisible(true); | ||
| 807 | jConsole.createMDI(); | ||
| 808 | |||
| 809 | for (int i = 0; i < hostNames.size(); i++) { | ||
| 810 | jConsole.addHost(hostNames.get(i), ports.get(i), | ||
| 811 | null, null, | ||
| 812 | (i == hostNames.size() - 1) ? | ||
| 813 | !noTile : false); | ||
| 814 | } | ||
| 815 | |||
| 816 | for (int i = 0; i < urls.size(); i++) { | ||
| 817 | jConsole.addUrl(urls.get(i), | ||
| 818 | null, | ||
| 819 | null, | ||
| 820 | (i == urls.size() - 1) ? | ||
| 821 | !noTile : false); | ||
| 822 | } | ||
| 823 | |||
| 824 | for (int i = 0; i < vmids.size(); i++) { | ||
| 825 | jConsole.addVmid(vmids.get(i), | ||
| 826 | (i == vmids.size() - 1) ? | ||
| 827 | !noTile : false); | ||
| 828 | } | ||
| 829 | |||
| 830 | if (vmids.size() == 0 && | ||
| 831 | hostNames.size() == 0 && | ||
| 832 | urls.size() == 0) { | ||
| 833 | jConsole.showConnectDialog(null, | ||
| 834 | null, | ||
| 835 | 0, | ||
| 836 | null, | ||
| 837 | null, | ||
| 838 | null); | ||
| 839 | } | ||
| 840 | } | ||
| 841 | }); | ||
| 842 | } | ||
| 843 | |||
| 844 | public static void main(String[] args) { | ||
| 845 | boolean noTile = false, hotspot = false; | ||
| 846 | int argIndex = 0; | ||
| 847 | ProxyClient proxyClient = null; | ||
| 848 | |||
| 849 | if (System.getProperty("jconsole.showOutputViewer") != null) { | ||
| 850 | OutputViewer.init(); | ||
| 851 | } | ||
| 852 | |||
| 853 | while (args.length - argIndex > 0 && args[argIndex].startsWith("-")) { | ||
| 854 | String arg = args[argIndex++]; | ||
| 855 | if (arg.equals("-h") || | ||
| 856 | arg.equals("-help") || | ||
| 857 | arg.equals("-?")) { | ||
| 858 | |||
| 859 | usage(); | ||
| 860 | return; | ||
| 861 | } else if (arg.startsWith("-interval=")) { | ||
| 862 | try { | ||
| 863 | updateInterval = Integer.parseInt(arg.substring(10)) * | ||
| 864 | 1000; | ||
| 865 | } catch (NumberFormatException ex) { | ||
| 866 | usage(); | ||
| 867 | return; | ||
| 868 | } | ||
| 869 | } else if (arg.equals("-pluginpath")) { | ||
| 870 | if (argIndex < args.length && !args[argIndex].startsWith("-")) { | ||
| 871 | pluginPath = args[argIndex++]; | ||
| 872 | } else { | ||
| 873 | // Invalid argument | ||
| 874 | usage(); | ||
| 875 | return; | ||
| 876 | } | ||
| 877 | } else if (arg.equals("-notile")) { | ||
| 878 | noTile = true; | ||
| 879 | } else if (arg.equals("-version")) { | ||
| 880 | Version.print(System.err); | ||
| 881 | return; | ||
| 882 | } else if (arg.equals("-debug")) { | ||
| 883 | debug = true; | ||
| 884 | } else if (arg.equals("-fullversion")) { | ||
| 885 | Version.printFullVersion(System.err); | ||
| 886 | return; | ||
| 887 | } else { | ||
| 888 | // Unknown switch | ||
| 889 | usage(); | ||
| 890 | return; | ||
| 891 | } | ||
| 892 | } | ||
| 893 | |||
| 894 | if (System.getProperty("jconsole.showUnsupported") != null) { | ||
| 895 | hotspot = true; | ||
| 896 | } | ||
| 897 | |||
| 898 | List<String> urls = new ArrayList<String>(); | ||
| 899 | List<String> hostNames = new ArrayList<String>(); | ||
| 900 | List<Integer> ports = new ArrayList<Integer>(); | ||
| 901 | List<LocalVirtualMachine> vms = new ArrayList<LocalVirtualMachine>(); | ||
| 902 | |||
| 903 | for (int i = argIndex; i < args.length; i++) { | ||
| 904 | String arg = args[i]; | ||
| 905 | if (isValidRemoteString(arg)) { | ||
| 906 | if (arg.startsWith(ROOT_URL)) { | ||
| 907 | urls.add(arg); | ||
| 908 | } else if (arg.matches(".*:[0-9]*")) { | ||
| 909 | int p = arg.lastIndexOf(':'); | ||
| 910 | hostNames.add(arg.substring(0, p)); | ||
| 911 | try { | ||
| 912 | ports.add(Integer.parseInt(arg.substring(p+1))); | ||
| 913 | } catch (NumberFormatException ex) { | ||
| 914 | usage(); | ||
| 915 | return; | ||
| 916 | } | ||
| 917 | } | ||
| 918 | } else { | ||
| 919 | if (!isLocalAttachAvailable()) { | ||
| 920 | System.err.println("Local process monitoring is not supported"); | ||
| 921 | return; | ||
| 922 | } | ||
| 923 | try { | ||
| 924 | int vmid = Integer.parseInt(arg); | ||
| 925 | LocalVirtualMachine lvm = | ||
| 926 | LocalVirtualMachine.getLocalVirtualMachine(vmid); | ||
| 927 | if (lvm == null) { | ||
| 928 | System.err.println("Invalid process id:" + vmid); | ||
| 929 | return; | ||
| 930 | } | ||
| 931 | vms.add(lvm); | ||
| 932 | } catch (NumberFormatException ex) { | ||
| 933 | usage(); | ||
| 934 | return; | ||
| 935 | } | ||
| 936 | } | ||
| 937 | } | ||
| 938 | |||
| 939 | mainInit(urls, hostNames, ports, vms, proxyClient, noTile, hotspot); | ||
| 940 | } | ||
| 941 | |||
| 942 | public static boolean isDebug() { | ||
| 943 | return debug; | ||
| 944 | } | ||
| 945 | |||
| 946 | private static void dbgStackTrace(Exception ex) { | ||
| 947 | if (debug) { | ||
| 948 | ex.printStackTrace(); | ||
| 949 | } | ||
| 950 | } | ||
| 951 | |||
| 952 | private static final boolean localAttachmentSupported; | ||
| 953 | static { | ||
| 954 | boolean supported; | ||
| 955 | try { | ||
| 956 | Class.forName("com.sun.tools.attach.VirtualMachine"); | ||
| 957 | Class.forName("sun.management.ConnectorAddressLink"); | ||
| 958 | supported = true; | ||
| 959 | } catch (NoClassDefFoundError x) { | ||
| 960 | supported = false; | ||
| 961 | } catch (ClassNotFoundException x) { | ||
| 962 | supported = false; | ||
| 963 | } | ||
| 964 | localAttachmentSupported = supported; | ||
| 965 | } | ||
| 966 | |||
| 967 | public static boolean isLocalAttachAvailable() { | ||
| 968 | return localAttachmentSupported; | ||
| 969 | } | ||
| 970 | |||
| 971 | |||
| 972 | private static ServiceLoader<JConsolePlugin> pluginService = null; | ||
| 973 | |||
| 974 | // Return a list of newly instantiated JConsolePlugin objects | ||
| 975 | static synchronized List<JConsolePlugin> getPlugins() { | ||
| 976 | if (pluginService == null) { | ||
| 977 | // First time loading and initializing the plugins | ||
| 978 | initPluginService(pluginPath); | ||
| 979 | } else { | ||
| 980 | // reload the plugin so that new instances will be created | ||
| 981 | pluginService.reload(); | ||
| 982 | } | ||
| 983 | |||
| 984 | List<JConsolePlugin> plugins = new ArrayList<JConsolePlugin>(); | ||
| 985 | for (JConsolePlugin p : pluginService) { | ||
| 986 | plugins.add(p); | ||
| 987 | } | ||
| 988 | return plugins; | ||
| 989 | } | ||
| 990 | |||
| 991 | private static void initPluginService(String pluginPath) { | ||
| 992 | if (pluginPath.length() > 0) { | ||
| 993 | try { | ||
| 994 | ClassLoader pluginCL = new URLClassLoader(pathToURLs(pluginPath)); | ||
| 995 | ServiceLoader<JConsolePlugin> plugins = | ||
| 996 | ServiceLoader.load(JConsolePlugin.class, pluginCL); | ||
| 997 | // validate all plugins | ||
| 998 | for (JConsolePlugin p : plugins) { | ||
| 999 | if (isDebug()) { | ||
| 1000 | System.out.println("Plugin " + p.getClass() + " loaded."); | ||
| 1001 | } | ||
| 1002 | } | ||
| 1003 | pluginService = plugins; | ||
| 1004 | } catch (ServiceConfigurationError e) { | ||
| 1005 | // Error occurs during initialization of plugin | ||
| 1006 | System.out.println(Resources.getText("Fail to load plugin", | ||
| 1007 | e.getMessage())); | ||
| 1008 | } catch (MalformedURLException e) { | ||
| 1009 | if (JConsole.isDebug()) { | ||
| 1010 | e.printStackTrace(); | ||
| 1011 | } | ||
| 1012 | System.out.println(Resources.getText("Invalid plugin path", | ||
| 1013 | e.getMessage())); | ||
| 1014 | } | ||
| 1015 | } | ||
| 1016 | |||
| 1017 | if (pluginService == null) { | ||
| 1018 | initEmptyPlugin(); | ||
| 1019 | } | ||
| 1020 | } | ||
| 1021 | |||
| 1022 | private static void initEmptyPlugin() { | ||
| 1023 | ClassLoader pluginCL = new URLClassLoader(new URL[0]); | ||
| 1024 | pluginService = ServiceLoader.load(JConsolePlugin.class, pluginCL); | ||
| 1025 | } | ||
| 1026 | |||
| 1027 | /** | ||
| 1028 | * Utility method for converting a search path string to an array | ||
| 1029 | * of directory and JAR file URLs. | ||
| 1030 | * | ||
| 1031 | * @param path the search path string | ||
| 1032 | * @return the resulting array of directory and JAR file URLs | ||
| 1033 | */ | ||
| 1034 | private static URL[] pathToURLs(String path) throws MalformedURLException { | ||
| 1035 | String[] names = path.split(File.pathSeparator); | ||
| 1036 | URL[] urls = new URL[names.length]; | ||
| 1037 | int count = 0; | ||
| 1038 | for (String f : names) { | ||
| 1039 | URL url = fileToURL(new File(f)); | ||
| 1040 | urls[count++] = url; | ||
| 1041 | } | ||
| 1042 | return urls; | ||
| 1043 | } | ||
| 1044 | |||
| 1045 | /** | ||
| 1046 | * Returns the directory or JAR file URL corresponding to the specified | ||
| 1047 | * local file name. | ||
| 1048 | * | ||
| 1049 | * @param file the File object | ||
| 1050 | * @return the resulting directory or JAR file URL, or null if unknown | ||
| 1051 | */ | ||
| 1052 | private static URL fileToURL(File file) throws MalformedURLException { | ||
| 1053 | String name; | ||
| 1054 | try { | ||
| 1055 | name = file.getCanonicalPath(); | ||
| 1056 | } catch (IOException e) { | ||
| 1057 | name = file.getAbsolutePath(); | ||
| 1058 | } | ||
| 1059 | name = name.replace(File.separatorChar, '/'); | ||
| 1060 | if (!name.startsWith("/")) { | ||
| 1061 | name = "/" + name; | ||
| 1062 | } | ||
| 1063 | // If the file does not exist, then assume that it's a directory | ||
| 1064 | if (!file.isFile()) { | ||
| 1065 | name = name + "/"; | ||
| 1066 | } | ||
| 1067 | return new URL("file", "", name); | ||
| 1068 | } | ||
| 1069 | |||
| 1070 | |||
| 1071 | private static class FixedJRootPane extends JRootPane { | ||
| 1072 | public void updateUI() { | ||
| 1073 | updateLafValues(); | ||
| 1074 | super.updateUI(); | ||
| 1075 | } | ||
| 1076 | |||
| 1077 | /** | ||
| 1078 | * The revalidate method seems to be the only one that gets | ||
| 1079 | * called whenever there is a change of L&F or change of theme | ||
| 1080 | * in Windows L&F and GTK L&F. | ||
| 1081 | */ | ||
| 1082 | @Override | ||
| 1083 | public void revalidate() { | ||
| 1084 | // Workaround for Swing bug where the titledborder in both | ||
| 1085 | // GTK and Windows L&F's use calculated colors instead of | ||
| 1086 | // the highlight/shadow colors from the theme. | ||
| 1087 | // | ||
| 1088 | // Putting null removes any previous override and causes a | ||
| 1089 | // fallback to the current L&F's value. | ||
| 1090 | UIManager.put("TitledBorder.border", null); | ||
| 1091 | Border border = UIManager.getBorder("TitledBorder.border"); | ||
| 1092 | if (border instanceof BorderUIResource.EtchedBorderUIResource) { | ||
| 1093 | Color highlight = UIManager.getColor("ToolBar.highlight"); | ||
| 1094 | Color shadow = UIManager.getColor("ToolBar.shadow"); | ||
| 1095 | border = new BorderUIResource.EtchedBorderUIResource(highlight, | ||
| 1096 | shadow); | ||
| 1097 | UIManager.put("TitledBorder.border", border); | ||
| 1098 | } | ||
| 1099 | |||
| 1100 | if (IS_GTK) { | ||
| 1101 | // Workaround for Swing bug where the titledborder in | ||
| 1102 | // GTK L&F use hardcoded color and font for the title | ||
| 1103 | // instead of getting them from the theme. | ||
| 1104 | UIManager.put("TitledBorder.titleColor", | ||
| 1105 | UIManager.getColor("Label.foreground")); | ||
| 1106 | UIManager.put("TitledBorder.font", | ||
| 1107 | UIManager.getFont("Label.font")); | ||
| 1108 | } | ||
| 1109 | super.revalidate(); | ||
| 1110 | } | ||
| 1111 | } | ||
| 1112 | } | ||