1 4 package com.tc.admin; 5 6 import org.apache.commons.httpclient.HttpClient; 7 import org.apache.commons.httpclient.HttpStatus; 8 import org.apache.commons.httpclient.methods.GetMethod; 9 import org.apache.commons.io.IOUtils; 10 import org.apache.log4j.Level; 11 import org.apache.log4j.Logger; 12 import org.dijon.Button; 13 import org.dijon.CheckBox; 14 import org.dijon.Dialog; 15 import org.dijon.DialogResource; 16 import org.dijon.FrameResource; 17 import org.dijon.Label; 18 import org.dijon.ScrollPane; 19 import org.dijon.Separator; 20 import org.dijon.TextArea; 21 import org.dijon.TextPane; 22 import org.dijon.UndoMonger; 23 24 import com.tc.admin.common.BrowserLauncher; 25 import com.tc.admin.common.ComponentNode; 26 import com.tc.admin.common.ContactTerracottaAction; 27 import com.tc.admin.common.PrefsHelper; 28 import com.tc.admin.common.XAbstractAction; 29 import com.tc.admin.common.XContainer; 30 import com.tc.admin.common.XMenu; 31 import com.tc.admin.common.XMenuBar; 32 import com.tc.admin.common.XMenuItem; 33 import com.tc.admin.common.XRootNode; 34 import com.tc.admin.common.XTabbedPane; 35 import com.tc.admin.common.XTextArea; 36 import com.tc.admin.common.XTextField; 37 import com.tc.admin.common.XTreeModel; 38 import com.tc.admin.common.XTreeNode; 39 40 import java.awt.BorderLayout ; 41 import java.awt.event.ActionEvent ; 42 import java.awt.event.ActionListener ; 43 import java.awt.event.HierarchyEvent ; 44 import java.awt.event.HierarchyListener ; 45 import java.awt.event.KeyAdapter ; 46 import java.awt.event.KeyEvent ; 47 import java.awt.event.MouseAdapter ; 48 import java.awt.event.MouseEvent ; 49 import java.beans.PropertyChangeEvent ; 50 import java.beans.PropertyChangeListener ; 51 import java.io.IOException ; 52 import java.io.InputStream ; 53 import java.io.PrintWriter ; 54 import java.io.StringWriter ; 55 import java.net.ConnectException ; 56 import java.net.MalformedURLException ; 57 import java.net.URL ; 58 import java.net.URLEncoder ; 59 import java.util.ArrayList ; 60 import java.util.Date ; 61 import java.util.Properties ; 62 import java.util.StringTokenizer ; 63 import java.util.prefs.Preferences ; 64 65 import javax.swing.Icon ; 66 import javax.swing.JOptionPane ; 67 import javax.swing.JPopupMenu ; 68 import javax.swing.JScrollPane ; 69 import javax.swing.JSeparator ; 70 import javax.swing.JSplitPane ; 71 import javax.swing.KeyStroke ; 72 import javax.swing.SwingUtilities ; 73 import javax.swing.Timer ; 74 import javax.swing.event.ChangeEvent ; 75 import javax.swing.event.ChangeListener ; 76 import javax.swing.event.DocumentEvent ; 77 import javax.swing.event.DocumentListener ; 78 import javax.swing.event.HyperlinkEvent ; 79 import javax.swing.event.HyperlinkListener ; 80 import javax.swing.event.TreeSelectionEvent ; 81 import javax.swing.event.TreeSelectionListener ; 82 import javax.swing.text.AttributeSet ; 83 import javax.swing.text.Element ; 84 import javax.swing.text.JTextComponent ; 85 import javax.swing.text.html.HTML ; 86 import javax.swing.tree.TreeModel ; 87 import javax.swing.tree.TreePath ; 88 import javax.swing.undo.UndoManager ; 89 import javax.swing.undo.UndoableEdit ; 90 91 public class AdminClientPanel extends XContainer 92 implements AdminClientController, 93 UndoMonger 94 { 95 private NavTree m_tree; 96 private XContainer m_nodeView; 97 private JSplitPane m_mainSplitter; 98 private Integer m_mainDivLoc; 99 private JSplitPane m_leftSplitter; 100 private Integer m_leftDivLoc; 101 private DividerListener m_dividerListener; 102 private XTabbedPane m_bottomPane; 103 private XTextArea m_logArea; 104 private ArrayList m_logListeners; 105 private Icon m_infoIcon; 106 private XTextField m_statusLine; 107 protected UndoAction m_undoCmd; 108 protected RedoAction m_redoCmd; 109 protected UndoManager m_undoManager; 110 protected NewServerAction m_newServerAction; 111 protected HelpAction m_helpAction; 112 protected AboutAction m_aboutAction; 113 114 public static final String UNDO = "Undo"; 115 public static final String REDO = "Redo"; 116 117 protected MouseAdapter 118 m_statusCleaner = new MouseAdapter () { 119 public void mouseClicked(MouseEvent e) { 120 setStatus(null); 121 } 122 }; 123 124 public AdminClientPanel() { 125 super(); 126 127 AdminClientContext acc = AdminClient.getContext(); 128 129 acc.controller = this; 130 131 FrameResource frameRes = acc.topRes.getFrame("MyFrame"); 132 load(frameRes.getContentPane()); 133 134 m_tree = (NavTree)findComponent("Tree"); 135 m_nodeView = (XContainer)findComponent("NodeView"); 136 m_bottomPane = (XTabbedPane)findComponent("BottomPane"); 137 m_logArea = (XTextArea)m_bottomPane.findComponent("LogArea"); 138 m_statusLine = (XTextField)findComponent("StatusLine"); 139 140 m_nodeView.setLayout(new BorderLayout ()); 141 142 m_tree.addMouseListener(new MouseAdapter () { 143 public void mousePressed(MouseEvent me) { 144 TreePath path = m_tree.getPathForLocation(me.getX(), me.getY()); 145 146 if(path != null) { 147 m_tree.requestFocus(); 148 149 XTreeNode node = (XTreeNode)path.getLastPathComponent(); 150 if(node != null) { 151 select(node); 152 } 153 } 154 } 155 156 public void mouseClicked(MouseEvent me) { 157 TreePath path = m_tree.getPathForLocation(me.getX(), me.getY()); 158 159 if(path != null) { 160 m_tree.requestFocus(); 161 162 XTreeNode node = (XTreeNode)path.getLastPathComponent(); 163 if(node != null) { 164 node.nodeClicked(me); 165 } 166 } 167 } 168 }); 169 170 m_tree.addTreeSelectionListener(new TreeSelectionListener () { 171 public void valueChanged(TreeSelectionEvent tse) { 172 TreePath path = tse.getNewLeadSelectionPath(); 173 174 m_nodeView.removeAll(); 175 176 if(path != null) { 177 m_tree.requestFocus(); 178 179 XTreeNode node = (XTreeNode)path.getLastPathComponent(); 180 if(node != null) { 181 node.nodeSelected(tse); 182 183 if(node instanceof ComponentNode) { 184 ComponentNode cnode = (ComponentNode)node; 185 java.awt.Component comp = (java.awt.Component )cnode.getComponent(); 186 187 if(comp != null) { 188 m_nodeView.add(comp); 189 } 190 } 191 } 192 } 193 194 m_nodeView.revalidate(); 195 m_nodeView.repaint(); 196 } 197 }); 198 199 m_infoIcon = LogHelper.getHelper().getInfoIcon(); 200 201 m_logListeners = new ArrayList (); 202 LogDocumentListener ldl = new LogDocumentListener(m_logArea); 203 m_logListeners.add(ldl); 204 m_logArea.getDocument().addDocumentListener(ldl); 205 206 m_bottomPane.addChangeListener(new ChangeListener () { 207 public void stateChanged(ChangeEvent e) { 208 int index = m_bottomPane.getSelectedIndex(); 209 m_bottomPane.setIconAt(index, null); 210 } 211 }); 212 213 m_tree.setModel(new NavTreeModel()); 214 215 setHelpPath("/com/tc/admin/AdminClient.html"); 216 217 addMouseListener(m_statusCleaner); 218 219 addKeyListener(new KeyAdapter () { 220 public void keyPressed(KeyEvent e) { 221 setStatus(null); 222 } 223 }); 224 225 getActionMap().put(UNDO, m_undoCmd = new UndoAction()); 226 getActionMap().put(REDO, m_redoCmd = new RedoAction()); 227 228 initNavTreeMenu(); 229 } 230 231 protected NewServerAction getNewServerAction() { 232 if(m_newServerAction == null) { 233 m_newServerAction = new NewServerAction(); 234 } 235 return m_newServerAction; 236 } 237 238 protected HelpAction getHelpAction() { 239 if(m_helpAction == null) { 240 m_helpAction = new HelpAction(); 241 } 242 return m_helpAction; 243 } 244 245 protected AboutAction getAboutAction() { 246 if(m_aboutAction == null) { 247 m_aboutAction = new AboutAction(); 248 } 249 return m_aboutAction; 250 } 251 252 protected void initNavTreeMenu() { 253 JPopupMenu popup = new JPopupMenu ("ProjectTree Actions"); 254 255 popup.add(getNewServerAction()); 256 popup.add(new Separator()); 257 popup.add(getHelpAction()); 258 if(shouldAddAboutItem()) { 259 popup.add(getAboutAction()); 260 } 261 262 m_tree.setPopupMenu(popup); 263 } 264 265 private String getBundleString(String key) { 266 return AdminClient.getContext().getMessage(key); 267 } 268 269 private String formatBundleString(String key, Object [] args) { 270 return AdminClient.getContext().format(key, args); 271 } 272 273 private String formatBundleString(String key, Object arg) { 274 return formatBundleString(key, new Object []{arg}); 275 } 276 277 public void initMenubar(XMenuBar menuBar) { 278 XMenu menu = new XMenu(getBundleString("file.menu.label")); 279 280 menu.add(m_newServerAction = new NewServerAction()); 281 menu.add(new JSeparator ()); 282 menu.add(new QuitAction()); 283 284 menuBar.add(menu); 285 286 menu = new XMenu(getBundleString("help.menu.label")); 287 XMenuItem mitem = new XMenuItem("AdminConsole Help", 288 HelpHelper.getHelper().getHelpIcon()); 289 mitem.setAction(m_helpAction = new HelpAction()); 290 menu.add(mitem); 291 menu.addSeparator(); 292 menu.add(new ContactTerracottaAction("Visit Terracotta Forums", 293 "http://www.terracottatech.com/forums/")); 294 menu.add(new ContactTerracottaAction("Contact Terracotta Technical Support", 295 "http://www.terracottatech.com/support_services.shtml")); 296 menu.addSeparator(); 297 menu.add(new UpdateCheckerAction()); 298 menu.add(m_aboutAction = new AboutAction()); 299 300 menuBar.add(menu); 301 } 302 303 class HelpAction extends XAbstractAction { 304 HelpAction() { 305 super("AdminConsole Help"); 306 } 307 308 public void actionPerformed(ActionEvent ae) { 309 block(); 310 BrowserLauncher.openURL("http://www.terracotta.org/kit/reflector?kitID=2.3&pageID=ConsoleGuide"); 311 unblock(); 312 } 313 } 314 315 public boolean isExpanded(XTreeNode node) { 316 return node != null && 317 m_tree.isExpanded(new TreePath (node.getPath())); 318 } 319 320 public void expand(XTreeNode node) { 321 if(node != null) { 322 m_tree.expandPath(new TreePath (node.getPath())); 323 } 324 } 325 326 public boolean isSelected(XTreeNode node) { 327 return node != null && 328 m_tree.isPathSelected(new TreePath (node.getPath())); 329 } 330 331 public void select(XTreeNode node) { 332 if(node != null) { 333 m_tree.requestFocus(); 334 m_tree.setSelectionPath(new TreePath (node.getPath())); 335 } 336 } 337 338 public void remove(XTreeNode node) { 339 XTreeModel model = (XTreeModel)m_tree.getModel(); 340 XTreeNode parent = (XTreeNode)node.getParent(); 341 int index = parent.getIndex(node); 342 TreePath nodePath = new TreePath (node.getPath()); 343 TreePath selPath = m_tree.getSelectionPath(); 344 345 node.tearDown(); 346 model.removeNodeFromParent(node); 347 348 if(nodePath.isDescendant(selPath)) { 349 int count = parent.getChildCount(); 350 351 if(count > 0) { 352 node = (XTreeNode)parent.getChildAt(index < count ? index : count-1); 353 } 354 else { 355 node = parent; 356 } 357 358 m_tree.setSelectionPath(new TreePath (node.getPath())); 359 } 360 } 361 362 public void nodeStructureChanged(XTreeNode node) { 363 TreeModel treeModel = m_tree.getModel(); 364 365 if(treeModel instanceof XTreeModel) { 366 ((XTreeModel)treeModel).nodeStructureChanged(node); 367 } 368 } 369 370 public void nodeChanged(XTreeNode node) { 371 TreeModel treeModel = m_tree.getModel(); 372 373 if(treeModel instanceof XTreeModel) { 374 ((XTreeModel)treeModel).nodeChanged(node); 375 } 376 } 377 378 protected Preferences getPreferences() { 379 AdminClientContext acc = AdminClient.getContext(); 380 return acc.prefs.node("AdminClientFrame"); 381 } 382 383 protected void storePreferences() { 384 AdminClientContext acc = AdminClient.getContext(); 385 acc.client.storePrefs(); 386 } 387 388 private int getSplitPref(JSplitPane splitter) { 389 Preferences prefs = getPreferences(); 390 Preferences splitPrefs = prefs.node(splitter.getName()); 391 392 return splitPrefs.getInt("Split", -1); 393 } 394 395 private JSplitPane getMainSplitter() { 396 if(m_mainSplitter == null) { 397 m_mainSplitter = (JSplitPane )findComponent("MainSplitter"); 398 m_mainDivLoc = new Integer (getSplitPref(m_mainSplitter)); 399 400 if(m_dividerListener == null) { 401 m_dividerListener = new DividerListener(); 402 } 403 } 404 405 return m_mainSplitter; 406 } 407 408 private JSplitPane getLeftSplitter() { 409 if(m_leftSplitter == null) { 410 m_leftSplitter = (JSplitPane )findComponent("LeftSplitter"); 411 m_leftDivLoc = new Integer (getSplitPref(m_leftSplitter)); 412 413 if(m_dividerListener == null) { 414 m_dividerListener = new DividerListener(); 415 } 416 } 417 418 return m_leftSplitter; 419 } 420 421 public void updateServerPrefs() { 422 XRootNode root = m_tree.getRootNode(); 423 int count = root.getChildCount(); 424 AdminClientContext acc = AdminClient.getContext(); 425 PrefsHelper helper = PrefsHelper.getHelper(); 426 Preferences prefs = acc.prefs.node("AdminClient"); 427 Preferences serverPrefs = prefs.node(ServersHelper.SERVERS); 428 Preferences serverPref; 429 ServerNode serverNode; 430 431 helper.clearChildren(serverPrefs); 432 433 for(int i = 0; i < count; i++) { 434 serverNode = (ServerNode)root.getChildAt(i); 435 serverPref = serverPrefs.node("server-"+i); 436 serverNode.setPreferences(serverPref); 437 } 438 439 storePreferences(); 440 } 441 442 public void disconnectAll() { 443 XRootNode root = m_tree.getRootNode(); 444 int count = root.getChildCount(); 445 ServerNode serverNode; 446 447 for(int i = 0; i < count; i++) { 448 serverNode = (ServerNode)root.getChildAt(i); 449 450 if(serverNode.isConnected()) { 451 serverNode.disconnectOnExit(); 452 } 453 } 454 455 root.tearDown(); 456 storePreferences(); 457 } 458 459 class DividerListener implements PropertyChangeListener { 460 public void propertyChange(PropertyChangeEvent pce) { 461 JSplitPane splitter = (JSplitPane )pce.getSource(); 462 String propName = pce.getPropertyName(); 463 464 if(splitter.isShowing() == false || 465 JSplitPane.DIVIDER_LOCATION_PROPERTY.equals(propName) == false) 466 { 467 return; 468 } 469 470 int divLoc = splitter.getDividerLocation(); 471 Integer divLocObj = new Integer (divLoc); 472 Preferences prefs = getPreferences(); 473 String name = splitter.getName(); 474 Preferences node = prefs.node(name); 475 476 node.putInt("Split", divLoc); 477 storePreferences(); 478 479 if(m_mainSplitter.getName().equals(name)) { 480 m_mainDivLoc = divLocObj; 481 } 482 else { 483 m_leftDivLoc = divLocObj; 484 } 485 } 486 } 487 488 public void doLayout() { 489 super.doLayout(); 490 491 JSplitPane splitter = getMainSplitter(); 492 if(m_mainDivLoc != null) { 493 splitter.setDividerLocation(m_mainDivLoc.intValue()); 494 } 495 else { 496 splitter.setDividerLocation(0.7); 497 } 498 499 splitter = getLeftSplitter(); 500 if(m_leftDivLoc != null) { 501 splitter.setDividerLocation(m_leftDivLoc.intValue()); 502 } 503 else { 504 splitter.setDividerLocation(0.25); 505 } 506 } 507 508 public void log(String s) { 509 m_logArea.append(s+System.getProperty("line.separator")); 510 m_logArea.setCaretPosition(m_logArea.getDocument().getLength()-1); 511 } 512 513 public void log(Exception e) { 514 StringWriter sw = new StringWriter (); 515 PrintWriter pw = new PrintWriter (sw); 516 517 e.printStackTrace(pw); 518 pw.close(); 519 520 log(sw.toString()); 521 } 522 523 public void setStatus(String msg) { 524 m_statusLine.setText(msg); 525 } 526 527 public void clearStatus() { 528 setStatus(""); 529 } 530 531 public void addNotify() { 532 super.addNotify(); 533 534 getMainSplitter().addPropertyChangeListener(m_dividerListener); 535 getLeftSplitter().addPropertyChangeListener(m_dividerListener); 536 537 } 540 541 public void removeNotify() { 542 getMainSplitter().removePropertyChangeListener(m_dividerListener); 543 getLeftSplitter().removePropertyChangeListener(m_dividerListener); 544 545 super.removeNotify(); 546 } 547 548 class NewServerAction extends XAbstractAction { 549 NewServerAction() { 550 super(getBundleString("new.server.action.label")); 551 } 552 553 public void actionPerformed(ActionEvent ae) { 554 XTreeModel model = (XTreeModel)m_tree.getModel(); 555 XTreeNode root = (XTreeNode)model.getRoot(); 556 int index = root.getChildCount(); 557 ServerNode serverNode = new ServerNode(); 558 559 model.insertNodeInto(serverNode, root, index); 560 TreePath path = new TreePath (serverNode.getPath()); 561 m_tree.makeVisible(path); 562 m_tree.setSelectionPath(path); 563 564 AdminClientContext acc = AdminClient.getContext(); 565 PrefsHelper helper = PrefsHelper.getHelper(); 566 Preferences prefs = acc.prefs.node("AdminClient"); 567 Preferences servers = prefs.node(ServersHelper.SERVERS); 568 int count = helper.childrenNames(servers).length; 569 570 serverNode.setPreferences(servers.node("server-"+count)); 571 storePreferences(); 572 } 573 } 574 575 class QuitAction extends XAbstractAction { 576 QuitAction() { 577 super(getBundleString("quit.action.label")); 578 579 setAccelerator( 580 KeyStroke.getKeyStroke(KeyEvent.VK_Q, 581 MENU_SHORTCUT_KEY_MASK, 582 true)); 583 } 584 585 public void actionPerformed(ActionEvent ae) { 586 System.exit(0); 587 } 588 } 589 590 private java.awt.Frame getFrame() { 591 return (java.awt.Frame ) 592 SwingUtilities.getAncestorOfClass(java.awt.Frame .class, this); 593 } 594 595 protected boolean shouldAddAboutItem() { 596 return true; 597 } 598 599 class UpdateCheckerAction extends XAbstractAction { 600 Dialog m_updateCheckerDialog; 601 ProductInfo m_productInfo; 602 603 UpdateCheckerAction() { 604 super(getBundleString("update-checker.action.label")); 605 Preferences updateCheckerPrefs = getUpdateCheckerPrefs(); 606 boolean shouldCheck = updateCheckerPrefs.getBoolean("checking-enabled", true); 607 608 Logger.getLogger("org.apache.commons.httpclient.HttpClient").setLevel(Level.OFF); 609 Logger.getLogger("org.apache.commons.httpclient.params.DefaultHttpParams").setLevel(Level.OFF); 610 Logger.getLogger("org.apache.commons.httpclient.methods.GetMethod").setLevel(Level.OFF); 611 Logger.getLogger("org.apache.commons.httpclient.HttpMethodDirector").setLevel(Level.OFF); 612 Logger.getLogger("org.apache.commons.httpclient.HttpConnection").setLevel(Level.OFF); 613 Logger.getLogger("org.apache.commons.httpclient.HttpMethodBase").setLevel(Level.OFF); 614 Logger.getLogger("org.apache.commons.httpclient.HttpState").setLevel(Level.OFF); 615 Logger.getLogger("org.apache.commons.httpclient.HttpParser").setLevel(Level.OFF); 616 Logger.getLogger("org.apache.commons.httpclient.cookie.CookieSpec").setLevel(Level.OFF); 617 Logger.getLogger("httpclient.wire.header").setLevel(Level.OFF); 618 Logger.getLogger("httpclient.wire.content").setLevel(Level.OFF); 619 620 if(shouldCheck) { 621 long nextCheckTime = updateCheckerPrefs.getLong("next-check-time", 0L); 622 623 if(nextCheckTime == 0L) { 624 updateCheckerPrefs.putLong("next-check-time", nextCheckTime()); 625 storePreferences(); 626 } else if(nextCheckTime < System.currentTimeMillis()) { 627 AdminClientPanel.this.addHierarchyListener(new HierarchyListener () { 628 public void hierarchyChanged(HierarchyEvent e) { 629 if((e.getChangeFlags() & HierarchyEvent.DISPLAYABILITY_CHANGED) != 0 && 630 AdminClientPanel.this.isDisplayable()) 631 { 632 AdminClientPanel.this.removeHierarchyListener(this); 633 SwingUtilities.invokeLater(new Runnable () { 634 public void run() { 635 Timer t = new Timer (100, UpdateCheckerAction.this); 636 t.setRepeats(false); 637 t.start(); 638 } 639 }); 640 } 641 } 642 }); 643 } 644 } 645 } 646 647 Preferences getUpdateCheckerPrefs() { 648 return getPreferences().node("update-checker"); 649 } 650 651 public void actionPerformed(ActionEvent e) { 652 final Preferences updateCheckerPrefs = getUpdateCheckerPrefs(); 653 final boolean promptForCheck = updateCheckerPrefs.getBoolean("prompt-for-check-enabled", true); 654 final Object src = e.getSource(); 655 656 if(promptForCheck || !(src instanceof Timer )) { 657 if(m_updateCheckerDialog == null) { 658 AdminClientContext acc = AdminClient.getContext(); 659 java.awt.Frame frame = getFrame(); 660 661 m_updateCheckerDialog = frame != null ? new Dialog(frame) : new Dialog(); 662 m_updateCheckerDialog.load((DialogResource)acc.topRes.child("UpdateCheckerDialog")); 663 664 Button button = (Button)m_updateCheckerDialog.findComponent("EnableCheckingButton"); 665 button.addActionListener(new ActionListener () { 666 public void actionPerformed(ActionEvent ae) { 667 updateCheckerPrefs.putBoolean("checking-enabled", true); 668 storePreferences(); 669 UpdateCheckerAction.this.startUpdateCheck(true); 670 m_updateCheckerDialog.setVisible(false); 671 } 672 }); 673 m_updateCheckerDialog.getRootPane().setDefaultButton(button); 674 675 CheckBox promptForCheckToggle = (CheckBox)m_updateCheckerDialog.findComponent("PromptForCheckToggle"); 676 promptForCheckToggle.addActionListener(new ActionListener () { 677 public void actionPerformed(ActionEvent ae) { 678 CheckBox cb = (CheckBox)ae.getSource(); 679 updateCheckerPrefs.putBoolean("prompt-for-check-enabled", cb.isSelected()); 680 storePreferences(); 681 } 682 }); 683 promptForCheckToggle.setSelected(updateCheckerPrefs.getBoolean("prompt-for-check-enabled", true)); 684 685 button = (Button)m_updateCheckerDialog.findComponent("DisableCheckingButton"); 686 button.addActionListener(new ActionListener () { 687 public void actionPerformed(ActionEvent ae) { 688 updateCheckerPrefs.putBoolean("checking-enabled", false); 689 storePreferences(); 690 m_updateCheckerDialog.setVisible(false); 691 } 692 }); 693 694 button = (Button)m_updateCheckerDialog.findComponent("CloseButton"); 695 button.addActionListener(new ActionListener () { 696 public void actionPerformed(ActionEvent ae) { 697 m_updateCheckerDialog.setVisible(false); 698 } 699 }); 700 Label lastCheckLabel = (Label)m_updateCheckerDialog.findComponent("LastCheckTimeLabel"); 701 long lastCheckTime = updateCheckerPrefs.getLong("last-check-time", 0L); 702 if(lastCheckTime != 0L) { 703 lastCheckLabel.setText(formatBundleString("update-checker.last.checked.msg", 704 new Date (lastCheckTime))); 705 } 706 } 707 708 m_updateCheckerDialog.pack(); 709 m_updateCheckerDialog.center(AdminClientPanel.this); 710 m_updateCheckerDialog.setVisible(true); 711 } else { 712 UpdateCheckerAction.this.startUpdateCheck(false); 713 } 714 } 715 716 ProductInfo getProductInfo() { 717 if(m_productInfo == null) { 718 m_productInfo = new ProductInfo(); 719 } 720 return m_productInfo; 721 } 722 723 URL constructCheckURL() throws MalformedURLException { 724 String defaultPropsUrl = "http://www.terracotta.org/kit/reflector?kitID=default&pageID=update.properties"; 725 String propsUrl = System.getProperty("terracotta.update-checker.url", defaultPropsUrl); 726 StringBuffer sb = new StringBuffer (propsUrl); 727 ProductInfo productInfo = getProductInfo(); 728 729 sb.append(defaultPropsUrl.equals(propsUrl) ? '&' : '?'); 730 731 sb.append("os-name="); 732 sb.append(URLEncoder.encode(System.getProperty("os.name"))); 733 sb.append("&jvm-name="); 734 sb.append(URLEncoder.encode(System.getProperty("java.vm.name"))); 735 sb.append("&jvm-version="); 736 sb.append(URLEncoder.encode(System.getProperty("java.vm.version"))); 737 sb.append("&platform="); 738 sb.append(URLEncoder.encode(System.getProperty("os.arch"))); 739 sb.append("&tc-version="); 740 sb.append(URLEncoder.encode(productInfo.getVersion())); 741 sb.append("&tc-product="); 742 sb.append(productInfo.getLicense().equals(ProductInfo.DEFAULT_LICENSE) ? "oss" : "ee"); 743 744 return new URL (sb.toString()); 745 } 746 747 void showMessage(String msg) { 748 TextArea textArea = new TextArea(); 749 textArea.setText(msg); 750 textArea.setRows(8); 751 textArea.setColumns(80); 752 textArea.setEditable(false); 753 ScrollPane scrollPane = new ScrollPane(textArea); 754 JOptionPane.showMessageDialog(AdminClientPanel.this, scrollPane, 755 getBundleString("update-checker.action.title"), 756 JOptionPane.INFORMATION_MESSAGE); 757 } 758 759 public Properties getResponseBody(URL url, HttpClient client) throws ConnectException , IOException { 760 GetMethod get = new GetMethod(url.toString()); 761 762 get.setFollowRedirects(true); 763 try { 764 int status = client.executeMethod(get); 765 if (status != HttpStatus.SC_OK) { 766 throw new ConnectException ("The http client has encountered a status code other than ok for the url: " + url 767 + " status: " + HttpStatus.getStatusText(status)); 768 } 769 Properties props = new Properties (); 770 props.load(get.getResponseBodyAsStream()); 771 return props; 772 } finally { 773 get.releaseConnection(); 774 } 775 } 776 777 void startUpdateCheck(final boolean wasPrompted) { 778 Thread t = new Thread () { 779 public void run() { 780 InputStream is = null; 781 Object result = null; 782 String versionNotice = null; 783 784 try { 785 StringBuffer sb = new StringBuffer (); 786 String version = getProductInfo().getVersion(); 787 if(version.indexOf('.') != -1) { 788 URL url = constructCheckURL(); 789 HttpClient httpClient = new HttpClient(); 790 Properties props = getResponseBody(url, httpClient); 791 792 String propVal = props.getProperty("general.notice"); 793 if(propVal != null && (propVal = propVal.trim()) != null && propVal.length() > 0) { 794 showMessage(propVal); 795 } 796 797 propVal = props.getProperty(version+".notice"); 798 if(propVal != null && (propVal = propVal.trim()) != null && propVal.length() > 0) { 799 showMessage(propVal); 800 } 801 versionNotice = propVal; 802 803 propVal = props.getProperty(version+".updates"); 804 if(propVal != null && (propVal = propVal.trim()) != null && propVal.length() > 0) { 805 sb.append("<ul>"); 806 StringTokenizer st = new StringTokenizer (propVal, ","); 807 while(st.hasMoreElements()) { 808 sb.append("<li>"); 809 String newVersion = st.nextToken(); 810 sb.append(newVersion); 811 812 propVal = props.getProperty(newVersion+".release-notes"); 813 if(propVal != null && (propVal = propVal.trim()) != null && propVal.length() > 0) { 814 sb.append(" -- <a HREF=\""); 815 sb.append(propVal); 816 sb.append("\">"); 817 sb.append(getBundleString("update-checker.release-notes.label")); 818 sb.append("</a>"); 819 } 820 sb.append("</li>\n"); 821 } 822 sb.append("</ol>"); 823 } 824 } 825 if(sb.length() > 0) { 826 sb.insert(0, "<html><body><p>"+getBundleString("update-checker.updates.available.msg")+"</p>"); 827 sb.append("</body></html>"); 828 TextPane textPane = new TextPane(); 829 textPane.setEditable(false); 830 textPane.setContentType("text/html"); 831 textPane.setBackground(null); 832 textPane.setText(sb.toString()); 833 textPane.addHyperlinkListener(new HyperlinkListener () { 834 public void hyperlinkUpdate(HyperlinkEvent e) { 835 if(e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) { 836 Element elem = e.getSourceElement(); 837 AttributeSet a = elem.getAttributes(); 838 AttributeSet anchor = (AttributeSet ) a.getAttribute(HTML.Tag.A); 839 String action = (String ) anchor.getAttribute(HTML.Attribute.HREF); 840 BrowserLauncher.openURL(action); 841 } 842 } 843 }); 844 result = textPane; 845 } else if(wasPrompted && versionNotice == null) { 846 result = getBundleString("update-checker.current.msg"); 847 } 848 } catch(Exception e) { 849 if(wasPrompted) { 850 result = getBundleString("update-checker.connect.failed.msg"); 851 } 852 } finally { 853 IOUtils.closeQuietly(is); 854 } 855 UpdateCheckerAction.this.finishUpdateCheck(wasPrompted, result); 856 } 857 }; 858 t.start(); 859 } 860 861 void finishUpdateCheck(final boolean wasPrompted, final Object msg) { 862 if(msg != null) { 863 SwingUtilities.invokeLater(new Runnable () { 864 public void run() { 865 JOptionPane.showMessageDialog(AdminClientPanel.this, msg, 866 getBundleString("update-checker.action.title"), 867 JOptionPane.INFORMATION_MESSAGE); 868 } 869 }); 870 } 871 872 final Preferences updateCheckerPrefs = getUpdateCheckerPrefs(); 873 updateCheckerPrefs.putLong("next-check-time", nextCheckTime()); 874 updateCheckerPrefs.putLong("last-check-time", System.currentTimeMillis()); 875 storePreferences(); 876 } 877 878 long nextCheckTime() { 879 long currentTime = System.currentTimeMillis(); 880 Long minutes = Long.getLong("terracotta.update-checker.next-check-minutes"); 881 long nextCheckTime; 882 883 if(minutes != null) { 884 nextCheckTime = currentTime+(minutes.longValue()*60*1000); 885 } else { 886 nextCheckTime = currentTime+(14*24*60*60*1000); 887 } 888 889 return nextCheckTime; 890 } 891 } 892 893 class AboutAction extends XAbstractAction { 894 Dialog m_aboutDialog; 895 896 AboutAction() { 897 super(getBundleString("about.action.label")); 898 } 899 900 public void actionPerformed(ActionEvent ae) { 901 if(m_aboutDialog == null) { 902 AdminClientContext acc = AdminClient.getContext(); 903 java.awt.Frame frame = getFrame(); 904 905 m_aboutDialog = frame != null ? new Dialog(frame) : new Dialog(); 906 m_aboutDialog.load((DialogResource)acc.topRes.child("AboutDialog")); 907 908 AdminClientInfoPanel info; 909 String title = getBundleString("title"); 910 info = (AdminClientInfoPanel)m_aboutDialog.findComponent("AdminClientInfoPanel"); 911 info.init(title, new ProductInfo()); 912 Label monikerLabel = (Label)m_aboutDialog.findComponent("MonikerLabel"); 913 monikerLabel.setText(title); 914 Button okButton = (Button)m_aboutDialog.findComponent("OKButton"); 915 m_aboutDialog.getRootPane().setDefaultButton(okButton); 916 okButton.addActionListener(new ActionListener () { 917 public void actionPerformed(ActionEvent ae2) { 918 m_aboutDialog.setVisible(false); 919 } 920 }); 921 } 922 923 m_aboutDialog.pack(); 924 m_aboutDialog.center(AdminClientPanel.this); 925 m_aboutDialog.setVisible(true); 926 } 927 } 928 929 public void addServerLog(ConnectionContext cc) { 930 ServerLog log = new ServerLog(cc); 931 JScrollPane scroller = new JScrollPane (log); 932 int index = m_bottomPane.getTabCount(); 933 934 m_bottomPane.addTab(cc.toString(), (Icon )null, scroller, null); 935 m_bottomPane.setSelectedIndex(index); 936 937 LogDocumentListener ldl = new LogDocumentListener(log); 938 log.getDocument().addDocumentListener(ldl); 939 m_logListeners.add(ldl); 940 } 941 942 public void removeServerLog(ConnectionContext cc) { 943 JScrollPane scroller; 944 ServerLog log; 945 LogDocumentListener ldl; 946 947 for(int i = 1; i < m_bottomPane.getTabCount(); i++) { 948 scroller = (JScrollPane )m_bottomPane.getComponentAt(i); 949 log = (ServerLog)scroller.getViewport().getView(); 950 951 if(cc.equals(log.getConnectionContext())) { 952 ldl = (LogDocumentListener)m_logListeners.remove(i); 953 log.getDocument().removeDocumentListener(ldl); 954 m_bottomPane.removeTabAt(i); 955 956 int index = m_bottomPane.getSelectedIndex(); 957 m_bottomPane.setIconAt(index, null); 958 959 return; 960 } 961 } 962 } 963 964 class LogDocumentListener implements DocumentListener { 965 JTextComponent textComponent; 966 967 LogDocumentListener(JTextComponent textComponent) { 968 this.textComponent = textComponent; 969 } 970 971 public void insertUpdate(DocumentEvent e) { 972 int index = m_logListeners.indexOf(this); 973 974 if(!textComponent.isShowing() && 975 m_bottomPane.getIconAt(index) == null) 976 { 977 m_bottomPane.setIconAt(index, m_infoIcon); 978 } 979 } 980 981 public void removeUpdate(DocumentEvent e) {} 982 public void changedUpdate(DocumentEvent e) {} 983 } 984 985 public void block() { 986 987 } 988 989 public void unblock() { 990 991 } 992 993 public UndoManager getUndoManager() { 994 if(m_undoManager == null) { 995 m_undoManager = new MyUndoManager(); 996 } 997 998 return m_undoManager; 999 } 1000 1001 class UndoAction extends XAbstractAction { 1002 public void actionPerformed(ActionEvent ae) { 1003 UndoManager undoMan = getUndoManager(); 1004 UndoableEdit next = ((MyUndoManager)undoMan).nextUndoable(); 1005 1006 if(next != null) { 1007 undoMan.undo(); 1008 setStatus("Undid '"+next.getPresentationName()+"'"); 1009 } 1010 } 1011 1012 public boolean isEnabled() { 1013 return getUndoManager().canUndo(); 1014 } 1015 } 1016 1017 class RedoAction extends XAbstractAction { 1018 public void actionPerformed(ActionEvent ae) { 1019 UndoManager undoMan = getUndoManager(); 1020 UndoableEdit next = ((MyUndoManager)undoMan).nextRedoable(); 1021 1022 if(next != null) { 1023 undoMan.redo(); 1024 setStatus("Redid '"+next.getPresentationName()+"'"); 1025 } 1026 } 1027 1028 public boolean isEnabled() { 1029 return getUndoManager().canRedo(); 1030 } 1031 } 1032 1033 class MyUndoManager extends UndoManager { 1034 public UndoableEdit nextUndoable() { 1035 return editToBeUndone(); 1036 } 1037 1038 public UndoableEdit nextRedoable() { 1039 return editToBeRedone(); 1040 } 1041 } 1042 1043 public String toString() { 1044 return getName(); 1045 } 1046 1047 protected void addEdit(UndoableEdit edit) { 1048 getUndoManager().addEdit(edit); 1049 } 1050} 1051 | Popular Tags |