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