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