/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
* or http://forgerock.org/license/CDDLv1.0.html.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at legal-notices/CDDLv1_0.txt.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information:
* Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*
*
* Copyright 2008-2010 Sun Microsystems, Inc.
* Portions Copyright 2013-2015 ForgeRock AS.
*/
package org.opends.quicksetup.installer.ui;
import static org.forgerock.util.Utils.*;
import static org.opends.messages.QuickSetupMessages.*;
import java.awt.Component;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeSet;
import javax.swing.Box;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JEditorPane;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSeparator;
import javax.swing.SwingConstants;
import org.forgerock.i18n.LocalizableMessage;
import org.opends.admin.ads.ADSContext;
import org.opends.admin.ads.ReplicaDescriptor;
import org.opends.admin.ads.SuffixDescriptor;
import org.opends.quicksetup.Constants;
import org.opends.quicksetup.UserData;
import org.opends.quicksetup.installer.AuthenticationData;
import org.opends.quicksetup.installer.SuffixesToReplicateOptions;
import org.opends.quicksetup.ui.FieldName;
import org.opends.quicksetup.ui.GuiApplication;
import org.opends.quicksetup.ui.QuickSetupStepPanel;
import org.opends.quicksetup.ui.UIFactory;
import org.opends.quicksetup.ui.UIFactory.IconType;
import org.opends.quicksetup.util.Utils;
import org.opends.server.config.ConfigConstants;
import org.opends.server.tools.BackendTypeHelper;
import org.opends.server.tools.BackendTypeHelper.BackendTypeUIAdapter;
/**
* This class is used to provide a data model for the list of suffixes that we
* have to replicate on the new server.
*/
public class SuffixesToReplicatePanel extends QuickSetupStepPanel implements Comparator<SuffixDescriptor>
{
private static final long serialVersionUID = -8051367953737385327L;
private static final Insets SUFFIXES_TO_REPLICATE_INSETS = new Insets(4, 4, 4, 4);
private final Set<SuffixDescriptor> orderedSuffixes = new TreeSet<>(this);
private final Map<String, JCheckBox> hmCheckBoxes = new HashMap<>();
private final Map<String, JComboBox<BackendTypeUIAdapter>> backendTypeComboBoxes = new HashMap<>();
/**
* The display of the server the user provided in the replication options
* panel.
*/
private String serverToConnectDisplay;
private JLabel noSuffixLabel;
private Component labelGlue;
private JPanel checkBoxPanel;
private JScrollPane scroll;
/**
* Constructor of the panel.
*
* @param application
* Application represented by this panel and used to initialize the
* fields of the panel.
*/
public SuffixesToReplicatePanel(GuiApplication application)
{
super(application);
createComponents();
}
@Override
public Object getFieldValue(FieldName fieldName)
{
if (fieldName == FieldName.SUFFIXES_TO_REPLICATE_OPTIONS)
{
return SuffixesToReplicateOptions.Type.REPLICATE_WITH_EXISTING_SUFFIXES;
}
else if (fieldName == FieldName.SUFFIXES_TO_REPLICATE)
{
return getSelectedSuffixes();
}
else if (fieldName == FieldName.SUFFIXES_TO_REPLICATE_BACKEND_TYPE)
{
return getSelectedSuffixBackendTypes();
}
return null;
}
private Set<SuffixDescriptor> getSelectedSuffixes()
{
Set<SuffixDescriptor> suffixes = new HashSet<>();
for (SuffixDescriptor suffix : orderedSuffixes)
{
if (hmCheckBoxes.get(suffix.getId()).isSelected())
{
suffixes.add(suffix);
}
}
return suffixes;
}
private Map<String, BackendTypeUIAdapter> getSelectedSuffixBackendTypes()
{
final Map<String, BackendTypeUIAdapter> backendTypes = new HashMap<>();
for (SuffixDescriptor suffix : getSelectedSuffixes())
{
final String backendName = suffix.getReplicas().iterator().next().getBackendName();
backendTypes.put(backendName, (BackendTypeUIAdapter) backendTypeComboBoxes.get(backendName).getSelectedItem());
}
return backendTypes;
}
@Override
public int compare(SuffixDescriptor desc1, SuffixDescriptor desc2)
{
int result = compareSuffixDN(desc1, desc2);
if (result == 0)
{
result = compareSuffixStrings(desc1, desc2);
}
return result;
}
@Override
protected Component createInputPanel()
{
JPanel panel = new JPanel(new GridBagLayout());
panel.setOpaque(false);
GridBagConstraints gbc = new GridBagConstraints();
gbc.weightx = 1.0;
gbc.anchor = GridBagConstraints.NORTHWEST;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.insets = UIFactory.getEmptyInsets();
gbc.insets.top = UIFactory.TOP_INSET_SECONDARY_FIELD;
gbc.insets.left = UIFactory.LEFT_INSET_BACKGROUND;
// Add the checkboxes
checkBoxPanel = new JPanel(new GridBagLayout());
checkBoxPanel.setOpaque(false);
gbc.insets.top = 0;
gbc.anchor = GridBagConstraints.NORTH;
gbc.weighty = 1.0;
gbc.fill = GridBagConstraints.BOTH;
scroll = UIFactory.createBorderLessScrollBar(checkBoxPanel);
panel.add(scroll, gbc);
gbc.insets.left = UIFactory.LEFT_INSET_SUBPANEL_SUBORDINATE;
gbc.weighty = 0.0;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.insets.top = UIFactory.TOP_INSET_SECONDARY_FIELD;
gbc.anchor = GridBagConstraints.NORTHEAST;
panel.add(noSuffixLabel, gbc);
noSuffixLabel.setVisible(false);
labelGlue = Box.createVerticalGlue();
gbc.fill = GridBagConstraints.VERTICAL;
gbc.weighty = 1.0;
panel.add(labelGlue, gbc);
labelGlue.setVisible(false);
return panel;
}
@Override
protected boolean requiresScroll()
{
return false;
}
@Override
protected LocalizableMessage getInstructions()
{
return INFO_SUFFIXES_TO_REPLICATE_PANEL_INSTRUCTIONS.get();
}
@Override
protected LocalizableMessage getTitle()
{
return INFO_SUFFIXES_TO_REPLICATE_PANEL_TITLE.get();
}
@Override
public void beginDisplay(UserData data)
{
Set<SuffixDescriptor> array = orderSuffixes(data.getSuffixesToReplicateOptions().getAvailableSuffixes());
AuthenticationData authData = data.getReplicationOptions().getAuthenticationData();
String newServerDisplay;
newServerDisplay = authData != null ? authData.getHostName() + ":" + authData.getPort() : "";
if (!array.equals(orderedSuffixes) || !newServerDisplay.equals(serverToConnectDisplay))
{
serverToConnectDisplay = newServerDisplay;
Map<String, Boolean> hmOldValues = new HashMap<>();
for (String id : hmCheckBoxes.keySet())
{
hmOldValues.put(id, hmCheckBoxes.get(id).isSelected());
}
orderedSuffixes.clear();
for (SuffixDescriptor suffix : array)
{
if (!Utils.areDnsEqual(suffix.getDN(), ADSContext.getAdministrationSuffixDN())
&& !Utils.areDnsEqual(suffix.getDN(), Constants.SCHEMA_DN)
&& !Utils.areDnsEqual(suffix.getDN(), Constants.REPLICATION_CHANGES_DN))
{
orderedSuffixes.add(suffix);
}
}
hmCheckBoxes.clear();
for (SuffixDescriptor suffix : orderedSuffixes)
{
JCheckBox cb = UIFactory.makeJCheckBox(LocalizableMessage.raw(suffix.getDN()),
INFO_SUFFIXES_TO_REPLICATE_DN_TOOLTIP.get(), UIFactory.TextStyle.SECONDARY_FIELD_VALID);
cb.setOpaque(false);
Boolean v = hmOldValues.get(suffix.getId());
if (v != null)
{
cb.setSelected(v);
}
hmCheckBoxes.put(suffix.getId(), cb);
}
populateCheckBoxPanel();
}
boolean display = !orderedSuffixes.isEmpty();
noSuffixLabel.setVisible(!display);
labelGlue.setVisible(!display);
scroll.setVisible(display);
}
/** Creates the components of this panel. */
private void createComponents()
{
noSuffixLabel = UIFactory.makeJLabel(
UIFactory.IconType.NO_ICON, INFO_SUFFIX_LIST_EMPTY.get(), UIFactory.TextStyle.SECONDARY_FIELD_VALID);
}
private void populateCheckBoxPanel()
{
checkBoxPanel.removeAll();
final GridBagConstraints gbc = new GridBagConstraints();
gbc.fill = GridBagConstraints.BOTH;
gbc.insets = SUFFIXES_TO_REPLICATE_INSETS;
gbc.gridy = 0;
final Map<String, Set<SuffixDescriptor>> backendToSuffixes = getSuffixesForBackends();
for (Map.Entry<String, Set<SuffixDescriptor>> backendData : backendToSuffixes.entrySet())
{
gbc.anchor = GridBagConstraints.LINE_START;
gbc.gridwidth = 1;
gbc.gridheight = 1;
for (SuffixDescriptor suffix : backendData.getValue())
{
gbc.gridx = 0;
final JCheckBox cb = hmCheckBoxes.get(suffix.getId());
checkBoxPanel.add(cb, gbc);
printReplicaTooltipButton(suffix, gbc);
gbc.gridy++;
}
printBackendInformations(backendData, gbc);
printSeparatorLine(gbc);
}
gbc.weighty = 1.0;
gbc.insets = UIFactory.getEmptyInsets();
gbc.fill = GridBagConstraints.VERTICAL;
checkBoxPanel.add(Box.createVerticalGlue(), gbc);
}
private Map<String, Set<SuffixDescriptor>> getSuffixesForBackends()
{
final Map<String, Set<SuffixDescriptor>> backendToSuffixes = new HashMap<>();
for (SuffixDescriptor suffix : orderedSuffixes)
{
final String backendName = suffix.getReplicas().iterator().next().getBackendName();
if (!backendToSuffixes.containsKey(backendName))
{
backendToSuffixes.put(backendName, new LinkedHashSet<SuffixDescriptor>());
}
backendToSuffixes.get(backendName).add(suffix);
}
return backendToSuffixes;
}
private void printReplicaTooltipButton(SuffixDescriptor suffix, GridBagConstraints gbc)
{
gbc.gridx++;
String imageDesc = "<html>";
for (ReplicaDescriptor replica : suffix.getReplicas())
{
imageDesc += getServerDisplay(replica) + "<br>";
}
final int entriesNb = suffix.getReplicas().iterator().next().getEntries();
final LocalizableMessage entriesNbToPrint = getNumberOfEntriesMsg(entriesNb);
imageDesc += entriesNbToPrint + "</html>";
final JLabel helpReplicasTooltip = new JLabel();
helpReplicasTooltip.setIcon(UIFactory.getImageIcon(IconType.HELP_MEDIUM));
helpReplicasTooltip.setToolTipText(imageDesc);
UIFactory.setTextStyle(helpReplicasTooltip, UIFactory.TextStyle.SECONDARY_FIELD_VALID);
checkBoxPanel.add(helpReplicasTooltip, gbc);
}
private LocalizableMessage getNumberOfEntriesMsg(int nEntries)
{
if (nEntries > 0)
{
return INFO_SUFFIX_LIST_REPLICA_DISPLAY_ENTRIES.get(nEntries);
}
else if (nEntries == 0)
{
return INFO_SUFFIX_LIST_REPLICA_DISPLAY_NO_ENTRIES.get();
}
else
{
return INFO_SUFFIX_LIST_REPLICA_DISPLAY_ENTRIES_NOT_AVAILABLE.get();
}
}
private void printBackendInformations(Map.Entry<String, Set<SuffixDescriptor>> backendData, GridBagConstraints gbc)
{
final int nbSuffixForBackend = backendData.getValue().size();
gbc.gridy -= nbSuffixForBackend;
printBackendNameText(backendData, gbc);
printComboBoxForSuffix(backendData.getValue().iterator().next(), gbc);
gbc.gridy += nbSuffixForBackend;
}
private void printSeparatorLine(GridBagConstraints gbc)
{
gbc.gridwidth = gbc.gridx;
gbc.gridx = 0;
checkBoxPanel.add(new JSeparator(SwingConstants.HORIZONTAL), gbc);
gbc.gridy++;
}
private void printBackendNameText(Entry<String, Set<SuffixDescriptor>> backendData, GridBagConstraints gbc)
{
gbc.gridx++;
final JEditorPane backendNameText = UIFactory.makeTextPane(
LocalizableMessage.raw(backendData.getKey()), UIFactory.TextStyle.SECONDARY_FIELD_VALID);
backendNameText.setToolTipText(INFO_REPLICATED_SUFFIXES_BACKEND_NAME_TOOLTIP.get().toString());
gbc.anchor = GridBagConstraints.CENTER;
checkBoxPanel.add(backendNameText, gbc);
}
private void printComboBoxForSuffix(SuffixDescriptor suffix, GridBagConstraints gbc)
{
gbc.gridx++;
gbc.anchor = GridBagConstraints.LINE_END;
gbc.insets = UIFactory.getEmptyInsets();
final ReplicaDescriptor backendData = suffix.getReplicas().iterator().next();
final JComboBox<BackendTypeUIAdapter> backendTypeComboBox =
new JComboBox<>(new BackendTypeHelper().getBackendTypeUIAdaptors());
backendTypeComboBox.setToolTipText(INFO_REPLICATED_SUFFIXES_BACKEND_TYPE_TOOLTIP.get().toString());
final Set<String> objectClasses = backendData.getObjectClasses();
backendTypeComboBox.setSelectedItem(getBackendTypeFromObjectClasses(objectClasses));
backendTypeComboBoxes.put(backendData.getBackendName(), backendTypeComboBox);
checkBoxPanel.add(backendTypeComboBox, gbc);
gbc.insets = SUFFIXES_TO_REPLICATE_INSETS;
}
/**
* Returns the concrete backend type corresponding to the provided object
* classes. If the backend is not found, returns the default backend of this
* server configuration.
*
* @param objectClasses
* The set of object class with one should be a concrete backend
* type.
* @return The concrete backend type corresponding to object classes or this
* server default one.
*/
private BackendTypeUIAdapter getBackendTypeFromObjectClasses(Set<String> objectClasses)
{
for (String objectClass : objectClasses)
{
BackendTypeUIAdapter adapter =
BackendTypeHelper.getBackendTypeAdapter(objectClass.replace(ConfigConstants.NAME_PREFIX_CFG, ""));
if (adapter != null)
{
return adapter;
}
}
return new BackendTypeHelper().getBackendTypeUIAdaptors()[0];
}
private String getSuffixString(SuffixDescriptor desc)
{
Set<String> replicaDisplays = new TreeSet<>();
for (ReplicaDescriptor rep : desc.getReplicas())
{
replicaDisplays.add(getServerDisplay(rep));
}
return joinAsString("\n", replicaDisplays);
}
private String getServerDisplay(ReplicaDescriptor replica)
{
final boolean isServerToConnect = replica.getServer().getHostPort(false).equalsIgnoreCase(serverToConnectDisplay);
return isServerToConnect ? serverToConnectDisplay : replica.getServer().getHostPort(true);
}
private Set<SuffixDescriptor> orderSuffixes(Set<SuffixDescriptor> suffixes)
{
Set<SuffixDescriptor> ordered = new TreeSet<>(this);
ordered.addAll(suffixes);
return ordered;
}
private int compareSuffixDN(SuffixDescriptor desc1, SuffixDescriptor desc2)
{
return desc1.getDN().compareTo(desc2.getDN());
}
private int compareSuffixStrings(SuffixDescriptor desc1, SuffixDescriptor desc2)
{
return getSuffixString(desc1).compareTo(getSuffixString(desc2));
}
}