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