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-2016 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  @Override
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  @Override
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  @Override
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  @Override
253  protected LocalizableMessage getInstructions()
254  {
255    return INFO_DATA_REPLICATION_OPTIONS_PANEL_INSTRUCTIONS.get();
256  }
257
258  @Override
259  protected LocalizableMessage getTitle()
260  {
261    return INFO_DATA_REPLICATION_OPTIONS_PANEL_TITLE.get();
262  }
263
264  @Override
265  public void endDisplay()
266  {
267    if (lastFocusComponent != null)
268    {
269      lastFocusComponent.requestFocusInWindow();
270    }
271  }
272
273  @Override
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.getHostPort().getHost();
307    case REMOTE_SERVER_PORT:
308      return auth.getHostPort().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  /** Creates the components and populates the Maps with them. */
333  private void populateComponentMaps()
334  {
335    HashMap<FieldName, LabelFieldDescriptor> hm = new HashMap<>();
336
337    hm.put(FieldName.REPLICATION_PORT, new LabelFieldDescriptor(
338        INFO_REPLICATION_PORT_LABEL.get(),
339        INFO_REPLICATION_PORT_TOOLTIP.get(),
340        LabelFieldDescriptor.FieldType.TEXTFIELD,
341        LabelFieldDescriptor.LabelType.SECONDARY,
342        UIFactory.PORT_FIELD_SIZE));
343
344    hm.put(FieldName.REMOTE_SERVER_DN, new LabelFieldDescriptor(
345        INFO_REMOTE_SERVER_DN_LABEL.get(),
346        INFO_REMOTE_SERVER_DN_TOOLTIP.get(),
347        LabelFieldDescriptor.FieldType.TEXTFIELD,
348        LabelFieldDescriptor.LabelType.SECONDARY, UIFactory.DN_FIELD_SIZE));
349
350    hm.put(FieldName.REMOTE_SERVER_PWD, new LabelFieldDescriptor(
351        INFO_REMOTE_SERVER_PWD_LABEL.get(),
352        INFO_REMOTE_SERVER_PWD_TOOLTIP.get(),
353        LabelFieldDescriptor.FieldType.PASSWORD,
354        LabelFieldDescriptor.LabelType.SECONDARY,
355        UIFactory.PASSWORD_FIELD_SIZE));
356
357    hm.put(FieldName.REMOTE_SERVER_HOST, new LabelFieldDescriptor(
358        INFO_REMOTE_SERVER_HOST_LABEL.get(),
359        INFO_REMOTE_SERVER_HOST_TOOLTIP.get(),
360        LabelFieldDescriptor.FieldType.TEXTFIELD,
361        LabelFieldDescriptor.LabelType.SECONDARY,
362        UIFactory.HOST_FIELD_SIZE));
363
364    hm.put(FieldName.REMOTE_SERVER_PORT, new LabelFieldDescriptor(
365        INFO_REMOTE_SERVER_PORT_LABEL.get(),
366        INFO_REMOTE_SERVER_PORT_TOOLTIP.get(),
367        LabelFieldDescriptor.FieldType.TEXTFIELD,
368        LabelFieldDescriptor.LabelType.SECONDARY,
369        UIFactory.PORT_FIELD_SIZE));
370
371    for (FieldName fieldName : hm.keySet())
372    {
373      LabelFieldDescriptor desc = hm.get(fieldName);
374
375      String defaultValue = getDefaultStringValue(fieldName);
376      JTextComponent field = UIFactory.makeJTextComponent(desc, defaultValue);
377
378      hmFields.put(fieldName, field);
379
380      JLabel l = UIFactory.makeJLabel(desc);
381      l.setLabelFor(field);
382
383      hmLabels.put(fieldName, l);
384    }
385
386    ButtonGroup buttonGroup = new ButtonGroup();
387    rbStandalone =
388      UIFactory.makeJRadioButton(INFO_STANDALONE_SERVER_LABEL.get(),
389          INFO_STANDALONE_SERVER_TOOLTIP.get(),
390          UIFactory.TextStyle.SECONDARY_FIELD_VALID);
391    rbStandalone.setOpaque(false);
392    rbReplicated =
393      UIFactory.makeJRadioButton(INFO_REPLICATED_SERVER_LABEL.get(),
394          INFO_REPLICATED_SERVER_TOOLTIP.get(),
395          UIFactory.TextStyle.SECONDARY_FIELD_VALID);
396    rbReplicated.setOpaque(false);
397    buttonGroup.add(rbStandalone);
398    buttonGroup.add(rbReplicated);
399
400    DataReplicationOptions.Type type =
401      defaultUserData.getReplicationOptions().getType();
402    cbTopologyExists = UIFactory.makeJCheckBox(INFO_TOPOLOGY_EXISTS_LABEL.get(),
403        INFO_TOPOLOGY_EXISTS_TOOLTIP.get(),
404        UIFactory.TextStyle.SECONDARY_FIELD_VALID);
405    cbTopologyExists.setOpaque(false);
406    rbStandalone.setSelected(type ==
407      DataReplicationOptions.Type.STANDALONE);
408    rbReplicated.setSelected(type !=
409      DataReplicationOptions.Type.STANDALONE);
410    cbSecureReplication = UIFactory.makeJCheckBox(
411        INFO_SECURE_REPLICATION_LABEL.get(),
412        INFO_SECURE_REPLICATION_TOOLTIP.get(),
413        UIFactory.TextStyle.SECONDARY_FIELD_VALID);
414    cbSecureReplication.setSelected(
415        defaultUserData.getReplicationOptions().useSecureReplication());
416    cbTopologyExists.setSelected(type ==
417      DataReplicationOptions.Type.IN_EXISTING_TOPOLOGY);
418    checkEnablingState();
419  }
420
421  /** Adds all the required document listeners to the fields. */
422  private void addDocumentListeners()
423  {
424    FieldName[] fields = {
425        FieldName.REMOTE_SERVER_DN,
426        FieldName.REMOTE_SERVER_PWD,
427        FieldName.REMOTE_SERVER_HOST,
428        FieldName.REMOTE_SERVER_PORT
429    };
430    for (FieldName field : fields) {
431      JTextComponent tf = getField(field);
432      tf.getDocument().addDocumentListener(new DocumentListener() {
433        @Override
434        public void changedUpdate(DocumentEvent ev) {
435          if (!rbReplicated.isSelected()) {
436            rbReplicated.setSelected(true);
437          }
438          if (!cbTopologyExists.isSelected()) {
439            cbTopologyExists.setSelected(true);
440          }
441        }
442
443        @Override
444        public void insertUpdate(DocumentEvent ev) {
445          changedUpdate(ev);
446        }
447
448        @Override
449        public void removeUpdate(DocumentEvent ev) {
450          changedUpdate(ev);
451        }
452      });
453    }
454  }
455
456  /** Adds the required focus listeners to the fields. */
457  private void addFocusListeners()
458  {
459    final FocusListener l = new FocusListener()
460    {
461      @Override
462      public void focusGained(FocusEvent e)
463      {
464        lastFocusComponent = e.getComponent();
465        if (lastFocusComponent instanceof JTextComponent)
466        {
467          rbReplicated.setSelected(true);
468          if (lastFocusComponent != getField(FieldName.REPLICATION_PORT))
469          {
470            cbTopologyExists.setSelected(true);
471          }
472        }
473      }
474
475      @Override
476      public void focusLost(FocusEvent e)
477      {
478      }
479    };
480
481    for (JTextComponent tf : hmFields.values())
482    {
483      tf.addFocusListener(l);
484    }
485    rbReplicated.addFocusListener(l);
486    rbStandalone.addFocusListener(l);
487    cbTopologyExists.addFocusListener(l);
488    cbSecureReplication.addFocusListener(l);
489
490    lastFocusComponent = rbStandalone;
491  }
492
493  /** Adds the required focus listeners to the fields. */
494  private void addActionListeners()
495  {
496    final ActionListener l = new ActionListener()
497    {
498      @Override
499      public void actionPerformed(ActionEvent ev)
500      {
501        checkEnablingState();
502        ButtonEvent be = new ButtonEvent(ev.getSource(),
503            ButtonName.INPUT_PANEL_BUTTON);
504        notifyButtonListeners(be);
505      }
506    };
507    rbReplicated.addActionListener(l);
508    rbStandalone.addActionListener(l);
509    cbTopologyExists.addActionListener(l);
510    cbTopologyExists.addActionListener(new ActionListener()
511    {
512      @Override
513      public void actionPerformed(ActionEvent ev)
514      {
515        if (cbTopologyExists.isSelected())
516        {
517          rbReplicated.setSelected(true);
518        }
519      }
520    });
521  }
522
523  /** Enables/disables the fields. */
524  private void checkEnablingState()
525  {
526    boolean enableFields = rbReplicated.isSelected() &&
527    cbTopologyExists.isSelected();
528
529    for (JTextComponent tf : hmFields.values())
530    {
531      tf.setEnabled(enableFields);
532    }
533
534    for (JLabel l : hmLabels.values())
535    {
536      l.setEnabled(enableFields);
537    }
538
539    cbTopologyExists.setEnabled(rbReplicated.isSelected());
540    getLabel(FieldName.REPLICATION_PORT).setEnabled(rbReplicated.isSelected());
541    getField(FieldName.REPLICATION_PORT).setEnabled(rbReplicated.isSelected());
542    cbSecureReplication.setEnabled(rbReplicated.isSelected());
543  }
544
545  /**
546   * Returns the label associated with the given field name.
547   * @param fieldName the field name for which we want to retrieve the JLabel.
548   * @return the label associated with the given field name.
549   */
550  private JLabel getLabel(FieldName fieldName)
551  {
552    return hmLabels.get(fieldName);
553  }
554
555  /**
556   * Returns the JTextComponent associated with the given field name.
557   * @param fieldName the field name for which we want to retrieve the
558   * JTextComponent.
559   * @return the JTextComponent associated with the given field name.
560   */
561  private JTextComponent getField(FieldName fieldName)
562  {
563    return hmFields.get(fieldName);
564  }
565}