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-2010 Sun Microsystems, Inc.
025 *      Portions Copyright 2014-2015 ForgeRock AS
026 */
027package org.opends.guitools.controlpanel.ui;
028
029import static org.opends.messages.AdminToolMessages.*;
030
031import java.awt.Component;
032import java.awt.GridBagConstraints;
033import java.awt.GridBagLayout;
034import java.awt.Insets;
035import java.awt.event.ActionEvent;
036import java.awt.event.ActionListener;
037import java.awt.event.ItemEvent;
038import java.awt.event.ItemListener;
039import java.awt.event.KeyEvent;
040import java.net.InetAddress;
041import java.util.Collections;
042import java.util.Comparator;
043import java.util.HashSet;
044import java.util.LinkedHashSet;
045import java.util.Set;
046import java.util.SortedSet;
047import java.util.TreeSet;
048
049import javax.swing.BorderFactory;
050import javax.swing.Box;
051import javax.swing.DefaultComboBoxModel;
052import javax.swing.JCheckBoxMenuItem;
053import javax.swing.JComboBox;
054import javax.swing.JLabel;
055import javax.swing.JMenu;
056import javax.swing.JMenuBar;
057import javax.swing.JMenuItem;
058import javax.swing.JPanel;
059import javax.swing.JScrollPane;
060import javax.swing.JTable;
061import javax.swing.SwingUtilities;
062import javax.swing.table.DefaultTableCellRenderer;
063
064import org.opends.guitools.controlpanel.datamodel.BasicMonitoringAttributes;
065import org.opends.guitools.controlpanel.datamodel.CategorizedComboBoxElement;
066import org.opends.guitools.controlpanel.datamodel.ConnectionHandlerDescriptor;
067import org.opends.guitools.controlpanel.datamodel.
068 ConnectionHandlersMonitoringTableModel;
069import org.opends.guitools.controlpanel.datamodel.ControlPanelInfo;
070import org.opends.guitools.controlpanel.datamodel.CustomSearchResult;
071import org.opends.guitools.controlpanel.datamodel.MonitoringAttributes;
072import org.opends.guitools.controlpanel.datamodel.ServerDescriptor;
073import org.opends.guitools.controlpanel.datamodel.ConnectionHandlerDescriptor.
074 Protocol;
075import org.opends.guitools.controlpanel.datamodel.ConnectionHandlerDescriptor.
076 State;
077import org.opends.guitools.controlpanel.event.ConfigurationChangeEvent;
078import org.opends.guitools.controlpanel.ui.renderer.
079 NoLeftInsetCategoryComboBoxRenderer;
080import org.opends.guitools.controlpanel.util.Utilities;
081import org.opends.guitools.controlpanel.util.ViewPositions;
082import org.forgerock.i18n.LocalizableMessage;
083import org.forgerock.i18n.LocalizableMessageBuilder;
084
085/**
086 * Class that displays the monitoring information of connection handlers.
087 *
088 */
089public class ConnectionHandlerMonitoringPanel extends StatusGenericPanel
090{
091  private static final long serialVersionUID = -6462932160985559830L;
092
093  private MonitoringAttributesViewPanel<MonitoringAttributes>
094  operationViewPanel;
095  private GenericDialog operationViewDlg;
096
097  private JComboBox connectionHandlers;
098
099  private JTable connectionHandlersTable;
100  private JScrollPane connectionHandlersScroll;
101  private ConnectionHandlersMonitoringTableModel connectionHandlersTableModel;
102
103  private JLabel lNoConnectionHandlers = Utilities.createPrimaryLabel(
104      INFO_CTRL_PANEL_NO_CONNECTION_HANDLER_FOUND.get());
105
106  private boolean firstRealDataSet;
107
108  private JCheckBoxMenuItem showAveragesMenu;
109
110  private ConnectionHandlerMonitoringMenuBar menuBar;
111
112  private LinkedHashSet<MonitoringAttributes> chOperations = new LinkedHashSet<>();
113  {
114    chOperations.add(BasicMonitoringAttributes.ADD_REQUESTS);
115    chOperations.add(BasicMonitoringAttributes.BIND_REQUESTS);
116    chOperations.add(BasicMonitoringAttributes.DELETE_REQUESTS);
117    chOperations.add(BasicMonitoringAttributes.MOD_REQUESTS);
118    chOperations.add(BasicMonitoringAttributes.MOD_DN_REQUESTS);
119    chOperations.add(BasicMonitoringAttributes.SEARCH_REQUESTS);
120  }
121  private LinkedHashSet<MonitoringAttributes> allowedChOperations = new LinkedHashSet<>();
122  {
123    allowedChOperations.addAll(chOperations);
124    allowedChOperations.add(BasicMonitoringAttributes.ADD_RESPONSES);
125    allowedChOperations.add(BasicMonitoringAttributes.BIND_RESPONSES);
126    allowedChOperations.add(BasicMonitoringAttributes.COMPARE_RESPONSES);
127    allowedChOperations.add(BasicMonitoringAttributes.DELETE_RESPONSES);
128    allowedChOperations.add(BasicMonitoringAttributes.EXTENDED_REQUESTS);
129    allowedChOperations.add(BasicMonitoringAttributes.EXTENDED_RESPONSES);
130    allowedChOperations.add(BasicMonitoringAttributes.MOD_DN_RESPONSES);
131    allowedChOperations.add(BasicMonitoringAttributes.MOD_RESPONSES);
132    allowedChOperations.add(BasicMonitoringAttributes.SEARCH_DONE);
133    allowedChOperations.add(BasicMonitoringAttributes.UNBIND_REQUESTS);
134  }
135
136  private LocalizableMessage ALL_CONNECTION_HANDLERS =
137    INFO_CTRL_PANEL_ALL_CONNECTION_HANDLERS.get();
138
139  /**
140   * Default constructor.
141   *
142   */
143  public ConnectionHandlerMonitoringPanel()
144  {
145    super();
146    createLayout();
147  }
148
149  /**
150   * Creates the layout of the panel (but the contents are not populated here).
151   */
152  private void createLayout()
153  {
154    GridBagConstraints gbc = new GridBagConstraints();
155    gbc.gridx = 0;
156    gbc.gridy = 0;
157    gbc.fill = GridBagConstraints.BOTH;
158    gbc.gridwidth = 1;
159    gbc.weightx = 1.0;
160    gbc.anchor = GridBagConstraints.NORTHWEST;
161    addErrorPane(gbc);
162    gbc.weighty = 1.0;
163    JPanel viewOptions = new JPanel(new GridBagLayout());
164    viewOptions.setBackground(ColorAndFontConstants.greyBackground);
165    viewOptions.setBorder(BorderFactory.createMatteBorder(0, 0, 1, 0,
166        ColorAndFontConstants.defaultBorderColor));
167    gbc.gridwidth = 1;
168    JLabel l = Utilities.createPrimaryLabel(
169        INFO_CTRL_PANEL_CONNECTION_HANDLERS_LABEL.get());
170    gbc.gridy = 0;
171    gbc.gridx = 0;
172    gbc.weightx = 0.0;
173    gbc.insets = new Insets(10, 10, 10, 0);
174    viewOptions.add(l, gbc);
175    gbc.insets.left = 5;
176    gbc.insets.right = 10;
177    connectionHandlers = new JComboBox(
178        new DefaultComboBoxModel(new String[]{"fakeconnectionhandlername"}));
179    connectionHandlers.addItemListener(
180        new IgnoreItemListener(connectionHandlers));
181    connectionHandlers.addItemListener(new ItemListener()
182    {
183      public void itemStateChanged(ItemEvent ev)
184      {
185        if (ev.getStateChange() == ItemEvent.SELECTED)
186        {
187          updateConnectionHandlersPanel(
188              getInfo().getServerDescriptor(),
189              errorPane.isVisible());
190        }
191      }
192    });
193    connectionHandlers.setRenderer(
194        new NoLeftInsetCategoryComboBoxRenderer(connectionHandlers));
195    gbc.gridx ++;
196    viewOptions.add(connectionHandlers, gbc);
197    gbc.gridx ++;
198    gbc.weightx = 1.0;
199    gbc.insets.left = 0;
200    gbc.insets.right = 0;
201    gbc.fill = GridBagConstraints.HORIZONTAL;
202    viewOptions.add(Box.createHorizontalGlue(), gbc);
203
204    gbc.gridy = 1;
205    gbc.gridx = 0;
206    gbc.gridwidth = 1;
207    gbc.insets.left = 0;
208    gbc.weighty = 0.0;
209    gbc.insets = new Insets(0, 0, 0, 0);
210    add(viewOptions, gbc);
211
212    connectionHandlersTableModel = new ConnectionHandlersMonitoringTableModel();
213    // Add some fake data.
214    String[] names = {"First Connection Handler", "Second Connection Handler",
215        "Third Connection Handler", "Fourth Connection Handler",
216        "Fifth Connection Handler", "Connection Handler with a long name"};
217
218    Set<ConnectionHandlerDescriptor> fakeData = new HashSet<>();
219    connectionHandlersTableModel.setAttributes(chOperations, false);
220    try
221    {
222      Set<InetAddress> addresses = new HashSet<>();
223      addresses.add(InetAddress.getLocalHost());
224      Set<CustomSearchResult> emptySet = Collections.emptySet();
225      for (String name : names)
226      {
227        fakeData.add(new ConnectionHandlerDescriptor(
228            addresses, 1389, Protocol.LDAP, State.ENABLED, name, emptySet));
229      }
230      connectionHandlersTableModel.setData(fakeData, 0);
231    }
232    catch (Throwable t)
233    {
234      // Ignore
235    }
236    connectionHandlersTable = Utilities.createSortableTable(
237        connectionHandlersTableModel,
238        new DefaultTableCellRenderer());
239    connectionHandlersScroll = Utilities.createScrollPane(
240        connectionHandlersTable);
241    gbc.insets = new Insets(10, 10, 10, 10);
242    gbc.gridy ++;
243    gbc.weighty = 1.0;
244    gbc.fill = GridBagConstraints.BOTH;
245    gbc.weightx = 1.0;
246    gbc.fill = GridBagConstraints.BOTH;
247    add(connectionHandlersScroll, gbc);
248    gbc.fill = GridBagConstraints.VERTICAL;
249    gbc.anchor = GridBagConstraints.CENTER;
250    add(lNoConnectionHandlers, gbc);
251    updateTableSizes();
252  }
253
254  /** {@inheritDoc} */
255  @Override
256  public LocalizableMessage getTitle()
257  {
258    return INFO_CTRL_PANEL_CONNECTION_HANDLER_MONITORING_TITLE.get();
259  }
260
261  /** {@inheritDoc} */
262  @Override
263  public JMenuBar getMenuBar()
264  {
265    if (menuBar == null)
266    {
267      menuBar =
268        new ConnectionHandlerMonitoringMenuBar(getInfo());
269    }
270    return menuBar;
271  }
272
273  /** {@inheritDoc} */
274  public void configurationChanged(ConfigurationChangeEvent ev)
275  {
276    final ServerDescriptor server = ev.getNewDescriptor();
277    LinkedHashSet<Object> newElements = new LinkedHashSet<>();
278
279    newElements.add(new CategorizedComboBoxElement(ALL_CONNECTION_HANDLERS,
280        CategorizedComboBoxElement.Type.REGULAR));
281    Set<ConnectionHandlerDescriptor> chs = server.getConnectionHandlers();
282
283    SortedSet<ConnectionHandlerDescriptor> sortedChs =
284      new TreeSet<>(
285          new Comparator<ConnectionHandlerDescriptor>()
286          {
287            public int compare(ConnectionHandlerDescriptor desc1,
288                ConnectionHandlerDescriptor desc2)
289            {
290              int compare = 0;
291              if (desc1.getAddresses().equals(desc2.getAddresses()))
292              {
293                Integer port1 = Integer.valueOf(desc1.getPort());
294                Integer port2 = Integer.valueOf(desc2.getPort());
295                compare = port1.compareTo(port2);
296              }
297              else
298              {
299                compare = getConnectionHandlerLabel(desc1).compareTo(
300                    getConnectionHandlerLabel(desc2));
301              }
302              return compare;
303            }
304          });
305    for (ConnectionHandlerDescriptor ch : chs)
306    {
307      if (protocolHasMonitoring(ch))
308      {
309        sortedChs.add(ch);
310      }
311    }
312    // Add the administration connector
313    sortedChs.add(server.getAdminConnector());
314
315    newElements.add(COMBO_SEPARATOR);
316
317    for (ConnectionHandlerDescriptor ch : sortedChs)
318    {
319      String connectionHandlerLabel = getConnectionHandlerLabel(ch);
320      newElements.add(new CategorizedComboBoxElement(
321          connectionHandlerLabel, CategorizedComboBoxElement.Type.REGULAR));
322    }
323    updateComboBoxModel(newElements,
324        (DefaultComboBoxModel)connectionHandlers.getModel());
325
326    boolean displayErrorPane = false;
327    LocalizableMessage errorTitle = LocalizableMessage.EMPTY;
328    LocalizableMessage errorDetails = LocalizableMessage.EMPTY;
329    ServerDescriptor.ServerStatus status = server.getStatus();
330    if (status == ServerDescriptor.ServerStatus.STARTED)
331    {
332      if (!server.isAuthenticated())
333      {
334        LocalizableMessageBuilder mb = new LocalizableMessageBuilder();
335        mb.append(
336   INFO_CTRL_PANEL_AUTH_REQUIRED_TO_SEE_TRAFFIC_MONITORING_SUMMARY.
337   get());
338        mb.append("<br><br>").append(getAuthenticateHTML());
339        errorDetails = mb.toMessage();
340        errorTitle = INFO_CTRL_PANEL_AUTHENTICATION_REQUIRED_SUMMARY.get();
341
342        displayErrorPane = true;
343      }
344    }
345    else if (status == ServerDescriptor.ServerStatus.NOT_CONNECTED_TO_REMOTE)
346    {
347      LocalizableMessageBuilder mb = new LocalizableMessageBuilder();
348      mb.append(INFO_CTRL_PANEL_CANNOT_CONNECT_TO_REMOTE_DETAILS.get(
349      server.getHostname()));
350      mb.append("<br><br>").append(getAuthenticateHTML());
351      errorDetails = mb.toMessage();
352      errorTitle = INFO_CTRL_PANEL_CANNOT_CONNECT_TO_REMOTE_SUMMARY.get();
353      displayErrorPane = true;
354    }
355    else
356    {
357      errorTitle = INFO_CTRL_PANEL_SERVER_NOT_RUNNING_SUMMARY.get();
358      LocalizableMessageBuilder mb = new LocalizableMessageBuilder();
359      mb.append(
360          INFO_CTRL_PANEL_SERVER_MUST_RUN_TO_SEE_TRAFFIC_MONITORING_SUMMARY.
361          get());
362      mb.append("<br><br>");
363      mb.append(getStartServerHTML());
364      errorDetails = mb.toMessage();
365      displayErrorPane = true;
366    }
367    final boolean fDisplayErrorPane = displayErrorPane;
368    final LocalizableMessage fErrorTitle = errorTitle;
369    final LocalizableMessage fErrorDetails = errorDetails;
370    SwingUtilities.invokeLater(new Runnable()
371    {
372      /** {@inheritDoc} */
373      public void run()
374      {
375        ViewPositions pos = Utilities.getViewPositions(
376            ConnectionHandlerMonitoringPanel.this);
377        errorPane.setVisible(fDisplayErrorPane);
378        if (fDisplayErrorPane)
379        {
380          updateErrorPane(errorPane, fErrorTitle,
381              ColorAndFontConstants.errorTitleFont, fErrorDetails,
382              ColorAndFontConstants.defaultFont);
383        }
384        // TODO: complete update the other table
385        if (!firstRealDataSet)
386        {
387          updateTableSizes();
388          firstRealDataSet = true;
389        }
390        updateConnectionHandlersPanel(server, fDisplayErrorPane);
391        Utilities.updateViewPositions(pos);
392      }
393    });
394  }
395
396  /** {@inheritDoc} */
397  @Override
398  public Component getPreferredFocusComponent()
399  {
400    return connectionHandlers;
401  }
402
403  /** {@inheritDoc} */
404  @Override
405  public void okClicked()
406  {
407    // No ok button
408  }
409
410  /** {@inheritDoc} */
411  @Override
412  public GenericDialog.ButtonType getButtonType()
413  {
414    return GenericDialog.ButtonType.CLOSE;
415  }
416
417
418  /** {@inheritDoc} */
419  @Override
420  public boolean requiresBorder()
421  {
422    return false;
423  }
424
425  /** {@inheritDoc} */
426  @Override
427  public boolean requiresScroll()
428  {
429    return false;
430  }
431
432  private void setChOperationsToDisplay(
433      LinkedHashSet<MonitoringAttributes> operations,
434      boolean showAverages)
435  {
436    connectionHandlersTableModel.setAttributes(operations, showAverages);
437    connectionHandlersTableModel.forceDataStructureChange();
438  }
439
440  private String getConnectionHandlerLabel(ConnectionHandlerDescriptor ch)
441  {
442    StringBuilder sb = new StringBuilder();
443    if (ch.getProtocol() == Protocol.ADMINISTRATION_CONNECTOR)
444    {
445      sb.append(INFO_CTRL_PANEL_ADMINISTRATION_CONNECTOR_NAME.get(
446          ch.getPort()));
447    }
448    else
449    {
450      sb.append(ch.getPort());
451      sb.append(" - ");
452      switch (ch.getProtocol())
453      {
454      case OTHER:
455        sb.append(ch.getName());
456        break;
457      default:
458        sb.append(ch.getProtocol().getDisplayMessage());
459      break;
460      }
461    }
462    return sb.toString();
463  }
464
465  /**
466   * Displays a dialog allowing the user to select which operations to display.
467   *
468   */
469  private void operationViewClicked()
470  {
471    if (operationViewDlg == null)
472    {
473      operationViewPanel =
474        MonitoringAttributesViewPanel.createMonitoringAttributesInstance(
475            allowedChOperations);
476      operationViewDlg = new GenericDialog(Utilities.getFrame(this),
477          operationViewPanel);
478      Utilities.centerGoldenMean(operationViewDlg,
479          Utilities.getParentDialog(this));
480      operationViewDlg.setModal(true);
481    }
482    operationViewPanel.setSelectedAttributes(chOperations);
483    operationViewDlg.setVisible(true);
484    if (!operationViewPanel.isCanceled())
485    {
486      boolean showAverages = showAveragesMenu.isSelected();
487      chOperations = operationViewPanel.getAttributes();
488      setChOperationsToDisplay(chOperations, showAverages);
489      updateTableSizes();
490    }
491  }
492
493  /**
494   * Updates the contents of the tables depending on whether the averages
495   * must be displayed or not.
496   *
497   */
498  private void showAverageClicked()
499  {
500    boolean showAverages = showAveragesMenu.isSelected();
501    setChOperationsToDisplay(chOperations, showAverages);
502    updateTableSizes();
503  }
504
505  private void updateTableSizes()
506  {
507    Utilities.updateTableSizes(connectionHandlersTable, 8);
508    Utilities.updateScrollMode(connectionHandlersScroll,
509        connectionHandlersTable);
510  }
511
512  private void updateConnectionHandlersPanel(ServerDescriptor server,
513      boolean errorOccurred)
514  {
515    Set<ConnectionHandlerDescriptor> cch =
516      getFilteredConnectionHandlers(server);
517    connectionHandlersTableModel.setData(cch, server.getRunningTime());
518    connectionHandlersScroll.setVisible(!cch.isEmpty() && !errorOccurred);
519    lNoConnectionHandlers.setVisible(cch.isEmpty() && !errorOccurred);
520  }
521
522  private Set<ConnectionHandlerDescriptor> getFilteredConnectionHandlers(
523      ServerDescriptor server)
524  {
525    Set<ConnectionHandlerDescriptor> cchs = new HashSet<>();
526    if (server != null)
527    {
528      Object o = connectionHandlers.getSelectedItem();
529      if (o instanceof CategorizedComboBoxElement)
530      {
531        Object value = ((CategorizedComboBoxElement)o).getValue();
532        if (value.equals(ALL_CONNECTION_HANDLERS))
533        {
534          for (ConnectionHandlerDescriptor ch : server.getConnectionHandlers())
535          {
536            if (protocolHasMonitoring(ch))
537            {
538              cchs.add(ch);
539            }
540          }
541          cchs.add(server.getAdminConnector());
542        }
543        else
544        {
545          String name = value.toString();
546          for (ConnectionHandlerDescriptor ch : server.getConnectionHandlers())
547          {
548            if (getConnectionHandlerLabel(ch).equals(name))
549            {
550              cchs.add(ch);
551              break;
552            }
553          }
554          if (cchs.isEmpty())
555          {
556            ConnectionHandlerDescriptor adminCh =
557              server.getAdminConnector();
558            if (getConnectionHandlerLabel(adminCh).equals(name))
559            {
560              cchs.add(adminCh);
561            }
562          }
563        }
564      }
565    }
566    return cchs;
567  }
568
569  private boolean protocolHasMonitoring(ConnectionHandlerDescriptor ch)
570  {
571    return ch.getState() != State.DISABLED
572        && (ch.getProtocol() == Protocol.LDAP
573            || ch.getProtocol() == Protocol.LDAPS
574            || ch.getProtocol() == Protocol.LDAP_STARTTLS
575            || ch.getProtocol() == Protocol.OTHER);
576  }
577
578  /**
579   * The specific menu bar of this panel.
580   *
581   */
582  class ConnectionHandlerMonitoringMenuBar extends MainMenuBar
583  {
584    private static final long serialVersionUID = 505187831116443370L;
585
586    /**
587     * Constructor.
588     * @param info the control panel info.
589     */
590    public ConnectionHandlerMonitoringMenuBar(ControlPanelInfo info)
591    {
592      super(info);
593    }
594
595    /** {@inheritDoc} */
596    @Override
597    protected void addMenus()
598    {
599      add(createViewMenuBar());
600      add(createHelpMenuBar());
601    }
602
603    /**
604     * Creates the view menu bar.
605     * @return the view menu bar.
606     */
607    @Override
608    protected JMenu createViewMenuBar()
609    {
610      JMenu menu = Utilities.createMenu(
611          INFO_CTRL_PANEL_CONNECTION_HANDLER_VIEW_MENU.get(),
612          INFO_CTRL_PANEL_CONNECTION_HANDLER_VIEW_MENU_DESCRIPTION.get());
613      menu.setMnemonic(KeyEvent.VK_V);
614      final JMenuItem viewOperations = Utilities.createMenuItem(
615          INFO_CTRL_PANEL_OPERATIONS_VIEW.get());
616      menu.add(viewOperations);
617      viewOperations.addActionListener(new ActionListener()
618      {
619        public void actionPerformed(ActionEvent ev)
620        {
621          operationViewClicked();
622        }
623      });
624      showAveragesMenu = new JCheckBoxMenuItem(
625          INFO_CTRL_PANEL_SHOW_AVERAGES.get().toString());
626      showAveragesMenu.setSelected(false);
627      menu.add(showAveragesMenu);
628      showAveragesMenu.addActionListener(new ActionListener()
629      {
630        public void actionPerformed(ActionEvent ev)
631        {
632          showAverageClicked();
633        }
634      });
635      return menu;
636    }
637  }
638}
639