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 2008-2009 Sun Microsystems, Inc.
025 *      Portions Copyright 2013-2015 ForgeRock AS.
026 */
027package org.opends.quicksetup.installer.ui;
028
029import org.forgerock.i18n.LocalizableMessage;
030import static org.opends.messages.QuickSetupMessages.*;
031
032import java.awt.Component;
033import java.awt.GridBagConstraints;
034import java.awt.GridBagLayout;
035import java.awt.event.ActionEvent;
036import java.awt.event.ActionListener;
037import java.awt.event.FocusEvent;
038import java.awt.event.FocusListener;
039import java.util.HashMap;
040
041import javax.swing.Box;
042import javax.swing.ButtonGroup;
043import javax.swing.JCheckBox;
044import javax.swing.JLabel;
045import javax.swing.JPanel;
046import javax.swing.JRadioButton;
047import javax.swing.event.DocumentEvent;
048import javax.swing.event.DocumentListener;
049import javax.swing.text.JTextComponent;
050
051import org.opends.quicksetup.ButtonName;
052import org.opends.quicksetup.UserData;
053import org.opends.quicksetup.event.ButtonEvent;
054import org.opends.quicksetup.installer.AuthenticationData;
055import org.opends.quicksetup.installer.DataReplicationOptions;
056import org.opends.quicksetup.ui.FieldName;
057import org.opends.quicksetup.ui.GuiApplication;
058import org.opends.quicksetup.ui.LabelFieldDescriptor;
059import org.opends.quicksetup.ui.QuickSetupStepPanel;
060import org.opends.quicksetup.ui.UIFactory;
061
062/**
063 * This class is used to display the replication options for the server
064 * that is being installed.
065 */
066public class DataReplicationPanel extends QuickSetupStepPanel
067{
068  private static final long serialVersionUID = -1721551487477733587L;
069  private Component lastFocusComponent;
070  private UserData defaultUserData;
071
072  private JRadioButton rbStandalone;
073  private JRadioButton rbReplicated;
074  private JCheckBox cbSecureReplication;
075  private JCheckBox cbTopologyExists;
076  private HashMap<FieldName, JLabel> hmLabels = new HashMap<>();
077  private HashMap<FieldName, JTextComponent> hmFields = new HashMap<>();
078
079  /**
080   * Constructor of the panel.
081   * @param application Application represented by this panel and used to
082   * initialize the fields of the panel.
083   */
084  public DataReplicationPanel(GuiApplication application)
085  {
086    super(application);
087    this.defaultUserData = application.getUserData();
088    populateComponentMaps();
089    addDocumentListeners();
090    addFocusListeners();
091    addActionListeners();
092  }
093
094  /** {@inheritDoc} */
095  public Object getFieldValue(FieldName fieldName)
096  {
097    Object value = null;
098
099    if (fieldName == FieldName.REPLICATION_OPTIONS)
100    {
101      if (rbStandalone.isSelected())
102      {
103        value = DataReplicationOptions.Type.STANDALONE;
104      }
105      else if (cbTopologyExists.isSelected())
106      {
107        value =
108          DataReplicationOptions.Type.IN_EXISTING_TOPOLOGY;
109      }
110      else
111      {
112        value = DataReplicationOptions.Type.FIRST_IN_TOPOLOGY;
113      }
114    }
115    else if (fieldName == FieldName.REPLICATION_SECURE)
116    {
117      value = Boolean.valueOf(cbSecureReplication.isSelected());
118    }
119    else
120    {
121      JTextComponent field = getField(fieldName);
122      if (field != null)
123      {
124        value = field.getText();
125      }
126    }
127
128    return value;
129  }
130
131  /** {@inheritDoc} */
132  public void displayFieldInvalid(FieldName fieldName, boolean invalid)
133  {
134    JLabel label = getLabel(fieldName);
135    if (label != null)
136    {
137      UIFactory.TextStyle style;
138
139      if (invalid)
140      {
141        style = UIFactory.TextStyle.SECONDARY_FIELD_INVALID;
142      } else
143      {
144        style = UIFactory.TextStyle.SECONDARY_FIELD_VALID;
145      }
146
147      UIFactory.setTextStyle(label, style);
148    }
149  }
150
151  /** {@inheritDoc} */
152  protected Component createInputPanel()
153  {
154    JPanel panel = new JPanel(new GridBagLayout());
155    panel.setOpaque(false);
156
157    GridBagConstraints gbc = new GridBagConstraints();
158    gbc.weightx = 1.0;
159    gbc.fill = GridBagConstraints.HORIZONTAL;
160    gbc.gridwidth = GridBagConstraints.REMAINDER;
161    gbc.insets = UIFactory.getEmptyInsets();
162    panel.add(rbStandalone, gbc);
163
164    gbc.insets.top = UIFactory.TOP_INSET_RADIOBUTTON;
165    panel.add(rbReplicated, gbc);
166
167    gbc.insets.top = UIFactory.TOP_INSET_SECONDARY_FIELD;
168    gbc.insets.left = UIFactory.LEFT_INSET_RADIO_SUBORDINATE;
169    JPanel auxPanel = new JPanel(new GridBagLayout());
170    auxPanel.setOpaque(false);
171    panel.add(auxPanel, gbc);
172    panel.add(cbTopologyExists, gbc);
173    gbc.insets = UIFactory.getEmptyInsets();
174    gbc.gridwidth = 4;
175    gbc.weightx = 0.0;
176    gbc.insets.left = 0;
177    gbc.anchor = GridBagConstraints.WEST;
178    auxPanel.add(getLabel(FieldName.REPLICATION_PORT), gbc);
179
180    gbc.gridwidth--;
181    gbc.insets.left = UIFactory.LEFT_INSET_SECONDARY_FIELD;
182    gbc.fill = GridBagConstraints.HORIZONTAL;
183    gbc.weightx = 0.0;
184    auxPanel.add(getField(FieldName.REPLICATION_PORT), gbc);
185
186    gbc.gridwidth = GridBagConstraints.RELATIVE;
187    gbc.fill = GridBagConstraints.HORIZONTAL;
188    gbc.weightx = 0.0;
189    auxPanel.add(cbSecureReplication, gbc);
190
191    gbc.gridwidth = GridBagConstraints.REMAINDER;
192    gbc.insets.left = 0;
193    gbc.weightx = 1.0;
194    gbc.fill = GridBagConstraints.HORIZONTAL;
195    auxPanel.add(Box.createHorizontalGlue(), gbc);
196
197    auxPanel = new JPanel(new GridBagLayout());
198    auxPanel.setOpaque(false);
199    gbc.insets.left = 2 * UIFactory.LEFT_INSET_RADIO_SUBORDINATE;
200    panel.add(auxPanel, gbc);
201
202    // Add the server location widgets
203    FieldName[] fields =
204    {
205      FieldName.REMOTE_SERVER_HOST,
206      FieldName.REMOTE_SERVER_PORT,
207      FieldName.REMOTE_SERVER_DN,
208      FieldName.REMOTE_SERVER_PWD
209    };
210
211    gbc.insets = UIFactory.getEmptyInsets();
212    for (int i=0; i<fields.length; i++)
213    {
214      if (i != 0)
215      {
216        gbc.insets.top = UIFactory.TOP_INSET_SECONDARY_FIELD;
217      }
218      else
219      {
220        gbc.insets.top = 0;
221      }
222      gbc.gridwidth = GridBagConstraints.RELATIVE;
223      gbc.weightx = 0.0;
224      gbc.insets.left = 0;
225      gbc.anchor = GridBagConstraints.WEST;
226      auxPanel.add(getLabel(fields[i]), gbc);
227
228      JPanel aux2Panel = new JPanel(new GridBagLayout());
229      aux2Panel.setOpaque(false);
230
231      if (fields[i] == FieldName.REMOTE_SERVER_PORT)
232      {
233        gbc.gridwidth = 3;
234      }
235      else
236      {
237        gbc.gridwidth = GridBagConstraints.RELATIVE;
238      }
239      gbc.insets.left = UIFactory.LEFT_INSET_SECONDARY_FIELD;
240      gbc.fill = GridBagConstraints.HORIZONTAL;
241      gbc.weightx = 0.0;
242      aux2Panel.add(getField(fields[i]), gbc);
243
244      gbc.gridwidth = GridBagConstraints.REMAINDER;
245      gbc.insets.left = 0;
246      gbc.weightx = 1.0;
247      gbc.fill = GridBagConstraints.HORIZONTAL;
248      aux2Panel.add(Box.createHorizontalGlue(), gbc);
249
250      gbc.weightx = 1.0;
251      gbc.fill = GridBagConstraints.HORIZONTAL;
252      gbc.insets = UIFactory.getEmptyInsets();
253      gbc.gridwidth = GridBagConstraints.REMAINDER;
254      auxPanel.add(aux2Panel, gbc);
255    }
256
257    addVerticalGlue(panel);
258
259    return panel;
260  }
261
262  /** {@inheritDoc} */
263  protected LocalizableMessage getInstructions()
264  {
265    return INFO_DATA_REPLICATION_OPTIONS_PANEL_INSTRUCTIONS.get();
266  }
267
268  /** {@inheritDoc} */
269  protected LocalizableMessage getTitle()
270  {
271    return INFO_DATA_REPLICATION_OPTIONS_PANEL_TITLE.get();
272  }
273
274  /** {@inheritDoc} */
275  public void endDisplay()
276  {
277    if (lastFocusComponent != null)
278    {
279      lastFocusComponent.requestFocusInWindow();
280    }
281  }
282
283  /** {@inheritDoc} */
284  protected LocalizableMessage getTextForIcon(UIFactory.IconType iconType)
285  {
286    if (iconType == UIFactory.IconType.WAIT &&
287        rbReplicated.isSelected() && cbTopologyExists.isSelected())
288    {
289      return INFO_CONTACTING_SERVER_LABEL.get();
290    }
291    else
292    {
293      return super.getTextForIcon(iconType);
294    }
295  }
296
297  /**
298   * Returns the default value for the provided field Name.
299   * @param fieldName the field name for which we want to get the default
300   * value.
301   * @return the default value for the provided field Name.
302   */
303  private Object getDefaultValue(FieldName fieldName)
304  {
305    AuthenticationData auth =
306      defaultUserData.getReplicationOptions().getAuthenticationData();
307    switch (fieldName)
308    {
309    case REPLICATION_PORT:
310      return defaultUserData.getReplicationOptions().getReplicationPort();
311    case REMOTE_SERVER_DN:
312      return auth.getDn();
313    case REMOTE_SERVER_PWD:
314      return auth.getPwd();
315    case REMOTE_SERVER_HOST:
316      return auth.getHostName();
317    case REMOTE_SERVER_PORT:
318      return auth.getPort();
319    case REPLICATION_OPTIONS:
320      return defaultUserData.getReplicationOptions().getType();
321    default:
322      throw new IllegalArgumentException("Unknown field name: " + fieldName);
323    }
324  }
325
326  /**
327   * Returns the default string value for the provided field Name.
328   * @param fieldName the field name for which we want to get the default
329   * string value.
330   * @return the default value for the provided field Name.
331   */
332  private String getDefaultStringValue(FieldName fieldName)
333  {
334    Object v = getDefaultValue(fieldName);
335    if (v != null)
336    {
337      return String.valueOf(v);
338    }
339    return null;
340  }
341
342  /**
343   * Creates the components and populates the Maps with them.
344   */
345  private void populateComponentMaps()
346  {
347    HashMap<FieldName, LabelFieldDescriptor> hm = new HashMap<>();
348
349    hm.put(FieldName.REPLICATION_PORT, new LabelFieldDescriptor(
350        INFO_REPLICATION_PORT_LABEL.get(),
351        INFO_REPLICATION_PORT_TOOLTIP.get(),
352        LabelFieldDescriptor.FieldType.TEXTFIELD,
353        LabelFieldDescriptor.LabelType.SECONDARY,
354        UIFactory.PORT_FIELD_SIZE));
355
356    hm.put(FieldName.REMOTE_SERVER_DN, new LabelFieldDescriptor(
357        INFO_REMOTE_SERVER_DN_LABEL.get(),
358        INFO_REMOTE_SERVER_DN_TOOLTIP.get(),
359        LabelFieldDescriptor.FieldType.TEXTFIELD,
360        LabelFieldDescriptor.LabelType.SECONDARY, UIFactory.DN_FIELD_SIZE));
361
362    hm.put(FieldName.REMOTE_SERVER_PWD, new LabelFieldDescriptor(
363        INFO_REMOTE_SERVER_PWD_LABEL.get(),
364        INFO_REMOTE_SERVER_PWD_TOOLTIP.get(),
365        LabelFieldDescriptor.FieldType.PASSWORD,
366        LabelFieldDescriptor.LabelType.SECONDARY,
367        UIFactory.PASSWORD_FIELD_SIZE));
368
369    hm.put(FieldName.REMOTE_SERVER_HOST, new LabelFieldDescriptor(
370        INFO_REMOTE_SERVER_HOST_LABEL.get(),
371        INFO_REMOTE_SERVER_HOST_TOOLTIP.get(),
372        LabelFieldDescriptor.FieldType.TEXTFIELD,
373        LabelFieldDescriptor.LabelType.SECONDARY,
374        UIFactory.HOST_FIELD_SIZE));
375
376    hm.put(FieldName.REMOTE_SERVER_PORT, new LabelFieldDescriptor(
377        INFO_REMOTE_SERVER_PORT_LABEL.get(),
378        INFO_REMOTE_SERVER_PORT_TOOLTIP.get(),
379        LabelFieldDescriptor.FieldType.TEXTFIELD,
380        LabelFieldDescriptor.LabelType.SECONDARY,
381        UIFactory.PORT_FIELD_SIZE));
382
383    for (FieldName fieldName : hm.keySet())
384    {
385      LabelFieldDescriptor desc = hm.get(fieldName);
386
387      String defaultValue = getDefaultStringValue(fieldName);
388      JTextComponent field = UIFactory.makeJTextComponent(desc, defaultValue);
389
390      hmFields.put(fieldName, field);
391
392      JLabel l = UIFactory.makeJLabel(desc);
393      l.setLabelFor(field);
394
395      hmLabels.put(fieldName, l);
396    }
397
398    ButtonGroup buttonGroup = new ButtonGroup();
399    rbStandalone =
400      UIFactory.makeJRadioButton(INFO_STANDALONE_SERVER_LABEL.get(),
401          INFO_STANDALONE_SERVER_TOOLTIP.get(),
402          UIFactory.TextStyle.SECONDARY_FIELD_VALID);
403    rbStandalone.setOpaque(false);
404    rbReplicated =
405      UIFactory.makeJRadioButton(INFO_REPLICATED_SERVER_LABEL.get(),
406          INFO_REPLICATED_SERVER_TOOLTIP.get(),
407          UIFactory.TextStyle.SECONDARY_FIELD_VALID);
408    rbReplicated.setOpaque(false);
409    buttonGroup.add(rbStandalone);
410    buttonGroup.add(rbReplicated);
411
412    DataReplicationOptions.Type type =
413      defaultUserData.getReplicationOptions().getType();
414    cbTopologyExists = UIFactory.makeJCheckBox(INFO_TOPOLOGY_EXISTS_LABEL.get(),
415        INFO_TOPOLOGY_EXISTS_TOOLTIP.get(),
416        UIFactory.TextStyle.SECONDARY_FIELD_VALID);
417    cbTopologyExists.setOpaque(false);
418    rbStandalone.setSelected(type ==
419      DataReplicationOptions.Type.STANDALONE);
420    rbReplicated.setSelected(type !=
421      DataReplicationOptions.Type.STANDALONE);
422    cbSecureReplication = UIFactory.makeJCheckBox(
423        INFO_SECURE_REPLICATION_LABEL.get(),
424        INFO_SECURE_REPLICATION_TOOLTIP.get(),
425        UIFactory.TextStyle.SECONDARY_FIELD_VALID);
426    cbSecureReplication.setSelected(
427        defaultUserData.getReplicationOptions().useSecureReplication());
428    cbTopologyExists.setSelected(type ==
429      DataReplicationOptions.Type.IN_EXISTING_TOPOLOGY);
430    checkEnablingState();
431  }
432
433  /**
434   * Adds all the required document listeners to the fields.
435   */
436  private void addDocumentListeners()
437  {
438    FieldName[] fields = {
439        FieldName.REMOTE_SERVER_DN,
440        FieldName.REMOTE_SERVER_PWD,
441        FieldName.REMOTE_SERVER_HOST,
442        FieldName.REMOTE_SERVER_PORT
443    };
444    for (FieldName field : fields) {
445      JTextComponent tf = getField(field);
446      tf.getDocument().addDocumentListener(new DocumentListener() {
447        public void changedUpdate(DocumentEvent ev) {
448          if (!rbReplicated.isSelected()) {
449            rbReplicated.setSelected(true);
450          }
451          if (!cbTopologyExists.isSelected()) {
452            cbTopologyExists.setSelected(true);
453          }
454        }
455
456        public void insertUpdate(DocumentEvent ev) {
457          changedUpdate(ev);
458        }
459
460        public void removeUpdate(DocumentEvent ev) {
461          changedUpdate(ev);
462        }
463      });
464    }
465  }
466
467  /**
468   * Adds the required focus listeners to the fields.
469   */
470  private void addFocusListeners()
471  {
472    final FocusListener l = new FocusListener()
473    {
474      public void focusGained(FocusEvent e)
475      {
476        lastFocusComponent = e.getComponent();
477        if (lastFocusComponent instanceof JTextComponent)
478        {
479          rbReplicated.setSelected(true);
480          if (lastFocusComponent != getField(FieldName.REPLICATION_PORT))
481          {
482            cbTopologyExists.setSelected(true);
483          }
484        }
485      }
486
487      public void focusLost(FocusEvent e)
488      {
489      }
490    };
491
492    for (JTextComponent tf : hmFields.values())
493    {
494      tf.addFocusListener(l);
495    }
496    rbReplicated.addFocusListener(l);
497    rbStandalone.addFocusListener(l);
498    cbTopologyExists.addFocusListener(l);
499    cbSecureReplication.addFocusListener(l);
500
501    lastFocusComponent = rbStandalone;
502  }
503
504  /**
505   * Adds the required focus listeners to the fields.
506   */
507  private void addActionListeners()
508  {
509    final ActionListener l = new ActionListener()
510    {
511      public void actionPerformed(ActionEvent ev)
512      {
513        checkEnablingState();
514        ButtonEvent be = new ButtonEvent(ev.getSource(),
515            ButtonName.INPUT_PANEL_BUTTON);
516        notifyButtonListeners(be);
517      }
518    };
519    rbReplicated.addActionListener(l);
520    rbStandalone.addActionListener(l);
521    cbTopologyExists.addActionListener(l);
522    cbTopologyExists.addActionListener(new ActionListener()
523    {
524      public void actionPerformed(ActionEvent ev)
525      {
526        if (cbTopologyExists.isSelected())
527        {
528          rbReplicated.setSelected(true);
529        }
530      }
531    });
532  }
533
534  /**
535   * Enables/disables the fields.
536   */
537  private void checkEnablingState()
538  {
539    boolean enableFields = rbReplicated.isSelected() &&
540    cbTopologyExists.isSelected();
541
542    for (JTextComponent tf : hmFields.values())
543    {
544      tf.setEnabled(enableFields);
545    }
546
547    for (JLabel l : hmLabels.values())
548    {
549      l.setEnabled(enableFields);
550    }
551
552    cbTopologyExists.setEnabled(rbReplicated.isSelected());
553    getLabel(FieldName.REPLICATION_PORT).setEnabled(rbReplicated.isSelected());
554    getField(FieldName.REPLICATION_PORT).setEnabled(rbReplicated.isSelected());
555    cbSecureReplication.setEnabled(rbReplicated.isSelected());
556  }
557
558  /**
559   * Returns the label associated with the given field name.
560   * @param fieldName the field name for which we want to retrieve the JLabel.
561   * @return the label associated with the given field name.
562   */
563  private JLabel getLabel(FieldName fieldName)
564  {
565    return hmLabels.get(fieldName);
566  }
567
568  /**
569   * Returns the JTextComponent associated with the given field name.
570   * @param fieldName the field name for which we want to retrieve the
571   * JTextComponent.
572   * @return the JTextComponent associated with the given field name.
573   */
574  private JTextComponent getField(FieldName fieldName)
575  {
576    return hmFields.get(fieldName);
577  }
578}