001/*
002 * The contents of this file are subject to the terms of the Common Development and
003 * Distribution License (the License). You may not use this file except in compliance with the
004 * License.
005 *
006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
007 * specific language governing permission and limitations under the License.
008 *
009 * When distributing Covered Software, include this CDDL Header Notice in each file and include
010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
011 * Header, with the fields enclosed by brackets [] replaced by your own identifying
012 * information: "Portions Copyright [year] [name of copyright owner]".
013 *
014 * Copyright 2009 Sun Microsystems, Inc.
015 * Portions Copyright 2014-2015 ForgeRock AS.
016 */
017package org.opends.guitools.controlpanel.ui;
018
019import static org.opends.messages.AdminToolMessages.*;
020import static org.opends.server.util.StaticUtils.isOEMVersion;
021
022import java.awt.Component;
023import java.awt.Dimension;
024import java.awt.GridBagConstraints;
025import java.awt.GridBagLayout;
026import java.awt.Insets;
027import java.awt.Window;
028import java.util.HashMap;
029
030import javax.swing.ImageIcon;
031import javax.swing.JPanel;
032import javax.swing.JScrollPane;
033import javax.swing.JSplitPane;
034import javax.swing.JTree;
035import javax.swing.SwingUtilities;
036import javax.swing.border.EmptyBorder;
037import javax.swing.event.TreeSelectionEvent;
038import javax.swing.event.TreeSelectionListener;
039import javax.swing.tree.DefaultMutableTreeNode;
040import javax.swing.tree.DefaultTreeModel;
041import javax.swing.tree.TreePath;
042
043import org.opends.guitools.controlpanel.browser.IconPool;
044import org.opends.guitools.controlpanel.datamodel.ControlPanelInfo;
045import org.opends.guitools.controlpanel.datamodel.CustomSearchResult;
046import org.opends.guitools.controlpanel.datamodel.ServerDescriptor;
047import org.opends.guitools.controlpanel.event.ConfigurationChangeEvent;
048import org.opends.guitools.controlpanel.ui.components.TreePanel;
049import org.opends.guitools.controlpanel.ui.nodes.GeneralMonitoringTreeNode;
050import org.opends.guitools.controlpanel.ui.renderer.TreeCellRenderer;
051import org.opends.guitools.controlpanel.util.Utilities;
052import org.opends.guitools.controlpanel.util.ViewPositions;
053import org.forgerock.i18n.LocalizableMessage;
054import org.forgerock.i18n.LocalizableMessageBuilder;
055
056/**
057 * The pane that is displayed when the user clicks on 'General Monitoring'.
058 *
059 */
060public class BrowseGeneralMonitoringPanel extends StatusGenericPanel
061{
062  private static final long serialVersionUID = 6462914563746678830L;
063
064  /**
065   * The panel containing the tree.
066   */
067  private TreePanel treePane;
068
069  private JScrollPane treeScroll;
070
071  private ServerDescriptor lastServer;
072
073  private String lastServerName;
074
075  private boolean ignoreSelectionEvents;
076
077  private LocalizableMessage NO_ELEMENT_SELECTED =
078    INFO_CTRL_PANEL_GENERAL_MONITORING_NO_ITEM_SELECTED.get();
079  private LocalizableMessage MULTIPLE_ITEMS_SELECTED =
080    INFO_CTRL_PANEL_MULTIPLE_ITEMS_SELECTED_LABEL.get();
081
082  /**
083   * The enumeration used to define the different static nodes of the tree.
084   *
085   */
086  protected enum NodeType
087  {
088    /** Root node. */
089    ROOT,
090    /** System information node. */
091    SYSTEM_INFORMATION,
092    /** Java information node. */
093    JAVA_INFORMATION,
094    /** Work queue node. */
095    WORK_QUEUE,
096    /** Entry caches node. */
097    ENTRY_CACHES,
098    /** JE Databases information node. */
099    JE_DATABASES_INFORMATION,
100    /** PDB databases information node. */
101    PDB_DATABASES_INFORMATION
102  }
103
104  /**
105   * The panel displaying the informations about the selected node.
106   */
107  protected GeneralMonitoringRightPanel entryPane;
108
109  /**
110   * Default constructor.
111   *
112   */
113  public BrowseGeneralMonitoringPanel()
114  {
115    super();
116    createLayout();
117  }
118
119  /** {@inheritDoc} */
120  @Override
121  public boolean requiresBorder()
122  {
123    return false;
124  }
125
126  /** {@inheritDoc} */
127  @Override
128  public boolean requiresScroll()
129  {
130    return false;
131  }
132
133  /** {@inheritDoc} */
134  @Override
135  public boolean callConfigurationChangedInBackground()
136  {
137    return true;
138  }
139
140  /** {@inheritDoc} */
141  @Override
142  public void toBeDisplayed(boolean visible)
143  {
144    Window w = Utilities.getParentDialog(this);
145    if (w instanceof GenericDialog)
146    {
147      ((GenericDialog)w).getRootPane().setDefaultButton(null);
148    }
149    else if (w instanceof GenericFrame)
150    {
151      ((GenericFrame)w).getRootPane().setDefaultButton(null);
152    }
153  }
154
155  /**
156   * Creates the layout of the panel (but the contents are not populated here).
157   */
158  private void createLayout()
159  {
160    setBackground(ColorAndFontConstants.greyBackground);
161    GridBagConstraints gbc = new GridBagConstraints();
162    gbc.anchor = GridBagConstraints.WEST;
163    gbc.gridx = 0;
164    gbc.gridy = 0;
165    gbc.gridwidth = 1;
166    gbc.weightx = 1.0;
167    gbc.fill = GridBagConstraints.BOTH;
168    addErrorPane(gbc);
169
170    gbc.insets = new Insets(10, 0, 0, 0);
171    gbc.gridx = 0;
172    gbc.gridy ++;
173    gbc.weightx = 1.0;
174    gbc.weighty = 1.0;
175    gbc.fill = GridBagConstraints.BOTH;
176    gbc.gridwidth = 7;
177    add(createSplitPane(), gbc);
178  }
179
180  /** {@inheritDoc} */
181  @Override
182  public LocalizableMessage getTitle()
183  {
184    return INFO_CTRL_PANEL_GENERAL_MONITORING_TITLE.get();
185  }
186
187  /** {@inheritDoc} */
188  @Override
189  public Component getPreferredFocusComponent()
190  {
191    return treePane;
192  }
193
194  /** {@inheritDoc} */
195  @Override
196  public void okClicked()
197  {
198    // No ok button
199  }
200
201  /** {@inheritDoc} */
202  @Override
203  public GenericDialog.ButtonType getButtonType()
204  {
205    return GenericDialog.ButtonType.CLOSE;
206  }
207
208  /**
209   * Creates the browser right panel.
210   * @return the created browser right panel.
211   */
212  private GeneralMonitoringRightPanel createBrowserRightPanel()
213  {
214    return new GeneralMonitoringRightPanel();
215  }
216
217  private Component createSplitPane()
218  {
219    treePane = new TreePanel();
220
221    entryPane = createBrowserRightPanel();
222
223    JPanel p = new JPanel(new GridBagLayout());
224    p.setBackground(ColorAndFontConstants.background);
225    GridBagConstraints gbc = new GridBagConstraints();
226    gbc.gridx = 0;
227    gbc.gridy = 0;
228    gbc.gridwidth = 1;
229    gbc.anchor = GridBagConstraints.NORTHWEST;
230    gbc.fill = GridBagConstraints.BOTH;
231    gbc.weightx = 1.0;
232    gbc.weighty = 1.0;
233    Utilities.setBorder(treePane, new EmptyBorder(10, 0, 10, 0));
234    p.add(treePane, gbc);
235    treeScroll = Utilities.createScrollPane(p);
236
237    treePane.getTree().addTreeSelectionListener(new TreeSelectionListener()
238    {
239      /** {@inheritDoc} */
240      public void valueChanged(TreeSelectionEvent ev)
241      {
242        if (!ignoreSelectionEvents)
243        {
244          ignoreSelectionEvents = true;
245          updateEntryPane();
246          ignoreSelectionEvents = false;
247        }
248      }
249    });
250    JTree tree = treePane.getTree();
251    repopulateTree(tree, true);
252    tree.setRootVisible(true);
253    tree.setVisibleRowCount(20);
254    tree.expandPath(new TreePath(getRoot(tree)));
255    tree.setCellRenderer(new GeneralMonitoringTreeCellRenderer());
256    treeScroll.setPreferredSize(
257        new Dimension(treeScroll.getPreferredSize().width + 30,
258            3 * treeScroll.getPreferredSize().height));
259    entryPane.displayMessage(NO_ELEMENT_SELECTED);
260    entryPane.setBorder(getRightPanelBorder());
261    entryPane.setPreferredSize(
262        new Dimension(treeScroll.getPreferredSize().width * 2,
263            treeScroll.getPreferredSize().height));
264    JSplitPane pane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
265    pane.setOpaque(true); //content panes must be opaque
266    pane.setLeftComponent(treeScroll);
267    pane.setRightComponent(entryPane);
268    pane.setResizeWeight(0.0);
269    pane.setDividerLocation(treeScroll.getPreferredSize().width);
270    return pane;
271  }
272
273  /** {@inheritDoc} */
274  @Override
275  public void setInfo(ControlPanelInfo info)
276  {
277    super.setInfo(info);
278    treePane.setInfo(info);
279    entryPane.setInfo(info);
280  }
281
282  /** {@inheritDoc} */
283  public void configurationChanged(ConfigurationChangeEvent ev)
284  {
285    ServerDescriptor server = ev.getNewDescriptor();
286    if (serverChanged(server))
287    {
288      final boolean firstTimeCalled = lastServer == null;
289      lastServer = server;
290
291      SwingUtilities.invokeLater(new Runnable()
292      {
293        public void run()
294        {
295          String serverName = getServerName(lastServer);
296          // Repopulate the tree to display a root node with server information
297          if (!serverName.equals(lastServerName))
298          {
299            repopulateTree(treePane.getTree(), false);
300            lastServerName = serverName;
301          }
302          if (firstTimeCalled)
303          {
304            // Select the root
305            treePane.getTree().setSelectionInterval(0, 0);
306          }
307          else
308          {
309            // Reselect
310            updateEntryPane();
311          }
312        }
313      });
314    }
315    else
316    {
317      lastServer = server;
318    }
319
320    boolean displayErrorPane = false;
321    LocalizableMessage errorTitle = LocalizableMessage.EMPTY;
322    LocalizableMessage errorDetails = LocalizableMessage.EMPTY;
323    ServerDescriptor.ServerStatus status = server.getStatus();
324    if (status == ServerDescriptor.ServerStatus.STARTED)
325    {
326      if (!server.isAuthenticated())
327      {
328        LocalizableMessageBuilder mb = new LocalizableMessageBuilder();
329        mb.append(
330   INFO_CTRL_PANEL_AUTH_REQUIRED_TO_BROWSE_MONITORING_SUMMARY.
331   get());
332        mb.append("<br><br>").append(getAuthenticateHTML());
333        errorDetails = mb.toMessage();
334        errorTitle = INFO_CTRL_PANEL_AUTHENTICATION_REQUIRED_SUMMARY.get();
335
336        displayErrorPane = true;
337      }
338    }
339    else if (status == ServerDescriptor.ServerStatus.NOT_CONNECTED_TO_REMOTE)
340    {
341      LocalizableMessageBuilder mb = new LocalizableMessageBuilder();
342      mb.append(INFO_CTRL_PANEL_CANNOT_CONNECT_TO_REMOTE_DETAILS.get(
343          server.getHostname()));
344      mb.append("<br><br>").append(getAuthenticateHTML());
345      errorDetails = mb.toMessage();
346      errorTitle = INFO_CTRL_PANEL_CANNOT_CONNECT_TO_REMOTE_SUMMARY.get();
347      displayErrorPane = true;
348    }
349    else
350    {
351      errorTitle = INFO_CTRL_PANEL_SERVER_NOT_RUNNING_SUMMARY.get();
352      LocalizableMessageBuilder mb = new LocalizableMessageBuilder();
353      mb.append(
354          INFO_CTRL_PANEL_SERVER_MUST_RUN_TO_BROWSE_MONITORING_SUMMARY.
355          get());
356      mb.append("<br><br>");
357      mb.append(getStartServerHTML());
358      errorDetails = mb.toMessage();
359      displayErrorPane = true;
360    }
361    final boolean fDisplayErrorPane = displayErrorPane;
362    final LocalizableMessage fErrorTitle = errorTitle;
363    final LocalizableMessage fErrorDetails = errorDetails;
364    SwingUtilities.invokeLater(new Runnable()
365    {
366      /** {@inheritDoc} */
367      public void run()
368      {
369        errorPane.setVisible(fDisplayErrorPane);
370        if (fDisplayErrorPane)
371        {
372          updateErrorPane(errorPane, fErrorTitle,
373              ColorAndFontConstants.errorTitleFont, fErrorDetails,
374              ColorAndFontConstants.defaultFont);
375        }
376      }
377    });
378  }
379
380  /**
381   * Populates the tree.  Should be called only once since the tree in this
382   * panel is static.
383   * @param tree the tree to be repopulated.
384   * @param forceScroll whether the scroll must be reset or not.
385   */
386  private void repopulateTree(JTree tree, boolean forceScroll)
387  {
388    ignoreSelectionEvents = true;
389
390    ViewPositions pos = Utilities.getViewPositions(treeScroll);
391
392    ServerDescriptor server = null;
393    if (getInfo() != null)
394    {
395      server = getInfo().getServerDescriptor();
396    }
397    GeneralMonitoringTreeNode root;
398    if (server == null)
399    {
400      root =
401        new GeneralMonitoringTreeNode(
402            INFO_CTRL_PANEL_GENERAL_MONITORING_ROOT.get().toString(),
403            NodeType.ROOT,
404            true);
405    }
406    else
407    {
408      root =
409        new GeneralMonitoringTreeNode(
410            getServerName(server),
411            NodeType.ROOT,
412            true);
413    }
414
415    LocalizableMessage[] messages = getNodeMessages();
416    NodeType[] identifiers = getNodeTypes();
417    for (int i=0; i < messages.length; i++)
418    {
419      if (isVisible(identifiers[i]))
420      {
421        root.add(new GeneralMonitoringTreeNode(messages[i].toString(), identifiers[i], false));
422      }
423    }
424
425    DefaultTreeModel model = new DefaultTreeModel(root);
426    tree.setModel(model);
427
428    Utilities.updateViewPositions(pos);
429    ignoreSelectionEvents = false;
430  }
431
432  /**
433   * Updates the right entry panel.
434   *
435   */
436  private void updateEntryPane()
437  {
438    ViewPositions pos = Utilities.getViewPositions(entryPane);
439    boolean canDisplayMonitorInformation = true;
440    if (getInfo() == null)
441    {
442      return;
443    }
444    ServerDescriptor server = getInfo().getServerDescriptor();
445    ServerDescriptor.ServerStatus status = server.getStatus();
446    if (status == ServerDescriptor.ServerStatus.STARTED)
447    {
448      if (!server.isAuthenticated())
449      {
450        canDisplayMonitorInformation = false;
451        entryPane.displayMessage(
452            INFO_CTRL_PANEL_AUTHENTICATION_REQUIRED_SUMMARY.get());
453      }
454    }
455    else
456    {
457      canDisplayMonitorInformation = false;
458      entryPane.displayMessage(
459          INFO_CTRL_PANEL_SERVER_NOT_RUNNING_SUMMARY.get());
460    }
461
462    if (canDisplayMonitorInformation)
463    {
464      TreePath[] paths = treePane.getTree().getSelectionPaths();
465      TreePath path = null;
466      if (paths != null && paths.length == 1)
467      {
468        path = paths[0];
469      }
470      if (path != null)
471      {
472        GeneralMonitoringTreeNode node =
473          (GeneralMonitoringTreeNode)path.getLastPathComponent();
474        NodeType type = (NodeType)node.getIdentifier();
475        switch (type)
476        {
477        case ROOT:
478          entryPane.updateRoot();
479          break;
480        case SYSTEM_INFORMATION:
481          entryPane.updateSystemInformation();
482          break;
483        case WORK_QUEUE:
484          entryPane.updateWorkQueue();
485          break;
486        case ENTRY_CACHES:
487          entryPane.updateEntryCaches();
488          break;
489        case JE_DATABASES_INFORMATION:
490          entryPane.updateJEDatabaseInformation();
491          break;
492        case PDB_DATABASES_INFORMATION:
493          entryPane.updatePDBDatbaseInformation();
494          break;
495        case JAVA_INFORMATION:
496          entryPane.updateJavaInformation();
497          break;
498        default:
499          throw new RuntimeException("Unknown node type: "+type);
500        }
501      }
502      else
503      {
504        if (paths != null && paths.length > 1)
505        {
506          entryPane.displayMessage(MULTIPLE_ITEMS_SELECTED);
507        }
508        else
509        {
510          entryPane.displayMessage(NO_ELEMENT_SELECTED);
511        }
512      }
513    }
514    Utilities.updateViewPositions(pos);
515  }
516
517  private DefaultMutableTreeNode getRoot(JTree tree)
518  {
519    return (DefaultMutableTreeNode)tree.getModel().getRoot();
520  }
521
522  private boolean serverChanged(ServerDescriptor desc)
523  {
524    boolean changed = false;
525    if (lastServer != null)
526    {
527      // Just compare the elements interesting for this panel
528      changed =
529        !desc.getBackends().equals(lastServer.getBackends());
530      if (!changed)
531      {
532        CustomSearchResult[] monitor1 =
533        {
534            lastServer.getEntryCachesMonitor(),
535            lastServer.getJvmMemoryUsageMonitor(),
536            lastServer.getRootMonitor(),
537            lastServer.getSystemInformationMonitor(),
538            lastServer.getWorkQueueMonitor()
539        };
540        CustomSearchResult[] monitor2 =
541        {
542            desc.getEntryCachesMonitor(),
543            desc.getJvmMemoryUsageMonitor(),
544            desc.getRootMonitor(),
545            desc.getSystemInformationMonitor(),
546            desc.getWorkQueueMonitor()
547        };
548        for (int i=0; i<monitor1.length && !changed; i++)
549        {
550          if (monitor1[i] == null)
551          {
552            changed = monitor2[i] != null;
553          }
554          else
555          {
556            changed = !monitor1[i].equals(monitor2[i]);
557          }
558        }
559      }
560    }
561    else
562    {
563      changed = true;
564    }
565    return changed;
566  }
567
568  private HashMap<Object, ImageIcon> hmImages = new HashMap<>();
569  {
570    NodeType[] identifiers = {
571        NodeType.ROOT,
572        NodeType.SYSTEM_INFORMATION,
573        NodeType.JAVA_INFORMATION,
574        NodeType.WORK_QUEUE,
575        NodeType.ENTRY_CACHES,
576        NodeType.JE_DATABASES_INFORMATION,
577        NodeType.PDB_DATABASES_INFORMATION
578    };
579    LocalizableMessage[] ocPaths = {
580        INFO_CTRL_PANEL_GENERAL_MONITORING_ROOT_TREE_NODE.get(),
581        INFO_CTRL_PANEL_SYSTEM_INFORMATION_TREE_NODE.get(),
582        INFO_CTRL_PANEL_JVM_MEMORY_USAGE_TREE_NODE.get(),
583        INFO_CTRL_PANEL_WORK_QUEUE_TREE_NODE.get(),
584        INFO_CTRL_PANEL_ENTRY_CACHES_TREE_NODE.get(),
585        INFO_CTRL_PANEL_DB_ENVIRONMENT_TREE_NODE.get(),
586        INFO_CTRL_PANEL_DB_ENVIRONMENT_TREE_NODE.get()
587    };
588    for (int i=0; i<identifiers.length; i++)
589    {
590      hmImages.put(identifiers[i],
591          Utilities.createImageIcon(IconPool.IMAGE_PATH+"/"+ocPaths[i],
592              getClass().getClassLoader()));
593    }
594  }
595
596  private String getServerName(ServerDescriptor server)
597  {
598    String serverName = server.getHostname();
599    if (server.getAdminConnector() != null)
600    {
601      serverName +=":"+server.getAdminConnector().getPort();
602    }
603    return serverName;
604  }
605
606  /**
607   * Specific class used to render the nodes in the tree.  It uses specific
608   * icons for the nodes.
609   *
610   */
611  protected class GeneralMonitoringTreeCellRenderer extends TreeCellRenderer
612  {
613    private static final long serialVersionUID = -3390566664259441766L;
614
615    /** {@inheritDoc} */
616    @Override
617    public Component getTreeCellRendererComponent(JTree tree, Object value,
618        boolean isSelected, boolean isExpanded, boolean isLeaf, int row,
619        boolean hasFocus)
620    {
621      super.getTreeCellRendererComponent(tree, value, isSelected, isExpanded,
622          isLeaf, row, hasFocus);
623      setIcon(getIcon(value));
624      return this;
625    }
626
627    private ImageIcon getIcon(Object value)
628    {
629      ImageIcon icon = null;
630      if (value instanceof GeneralMonitoringTreeNode)
631      {
632        icon = hmImages.get(
633            ((GeneralMonitoringTreeNode)value).getIdentifier());
634      }
635      else
636      {
637        throw new RuntimeException("Unexpected tree node: "+value);
638      }
639      return icon;
640    }
641  }
642
643  /**
644   * Returns the labels of the nodes to be displayed.
645   * @return the labels of the nodes to be displayed.
646   */
647  protected LocalizableMessage[] getNodeMessages()
648  {
649    return new LocalizableMessage[] {
650      INFO_CTRL_PANEL_SYSTEM_INFORMATION.get(),
651      INFO_CTRL_PANEL_JAVA_INFORMATION.get(),
652      INFO_CTRL_PANEL_WORK_QUEUE.get(),
653      INFO_CTRL_PANEL_ENTRY_CACHES.get(),
654      INFO_CTRL_PANEL_JE_DB_INFO.get(),
655      INFO_CTRL_PANEL_PDB_DB_INFO.get()
656    };
657  }
658
659  /**
660   * Returns the node types to be displayed.
661   * @return the node types to be displayed.
662   */
663  protected NodeType[] getNodeTypes()
664  {
665    return new NodeType[] {
666        NodeType.SYSTEM_INFORMATION,
667        NodeType.JAVA_INFORMATION,
668        NodeType.WORK_QUEUE,
669        NodeType.ENTRY_CACHES,
670        NodeType.JE_DATABASES_INFORMATION,
671        NodeType.PDB_DATABASES_INFORMATION
672    };
673  }
674
675  private boolean isVisible(NodeType nodetype)
676  {
677    return !(isOEMVersion() && nodetype == NodeType.JE_DATABASES_INFORMATION);
678  }
679}
680