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-2010 Sun Microsystems, Inc. 015 * Portions Copyright 2013-2015 ForgeRock AS. 016 */ 017package org.opends.quicksetup.installer.ui; 018 019import static org.forgerock.util.Utils.*; 020import static org.opends.messages.QuickSetupMessages.*; 021 022import java.awt.Component; 023import java.awt.GridBagConstraints; 024import java.awt.GridBagLayout; 025import java.awt.Insets; 026import java.util.Comparator; 027import java.util.HashMap; 028import java.util.HashSet; 029import java.util.LinkedHashSet; 030import java.util.Map; 031import java.util.Map.Entry; 032import java.util.Set; 033import java.util.TreeSet; 034 035import javax.swing.Box; 036import javax.swing.JCheckBox; 037import javax.swing.JComboBox; 038import javax.swing.JEditorPane; 039import javax.swing.JLabel; 040import javax.swing.JPanel; 041import javax.swing.JScrollPane; 042import javax.swing.JSeparator; 043import javax.swing.SwingConstants; 044 045import org.forgerock.i18n.LocalizableMessage; 046import org.opends.admin.ads.ADSContext; 047import org.opends.admin.ads.ReplicaDescriptor; 048import org.opends.admin.ads.SuffixDescriptor; 049import org.opends.quicksetup.Constants; 050import org.opends.quicksetup.UserData; 051import org.opends.quicksetup.installer.AuthenticationData; 052import org.opends.quicksetup.installer.SuffixesToReplicateOptions; 053import org.opends.quicksetup.ui.FieldName; 054import org.opends.quicksetup.ui.GuiApplication; 055import org.opends.quicksetup.ui.QuickSetupStepPanel; 056import org.opends.quicksetup.ui.UIFactory; 057import org.opends.quicksetup.ui.UIFactory.IconType; 058import org.opends.quicksetup.util.Utils; 059import org.opends.server.config.ConfigConstants; 060import org.opends.server.tools.BackendTypeHelper; 061import org.opends.server.tools.BackendTypeHelper.BackendTypeUIAdapter; 062 063/** 064 * This class is used to provide a data model for the list of suffixes that we 065 * have to replicate on the new server. 066 */ 067public class SuffixesToReplicatePanel extends QuickSetupStepPanel implements Comparator<SuffixDescriptor> 068{ 069 private static final long serialVersionUID = -8051367953737385327L; 070 071 private static final Insets SUFFIXES_TO_REPLICATE_INSETS = new Insets(4, 4, 4, 4); 072 073 private final Set<SuffixDescriptor> orderedSuffixes = new TreeSet<>(this); 074 private final Map<String, JCheckBox> hmCheckBoxes = new HashMap<>(); 075 private final Map<String, JComboBox<BackendTypeUIAdapter>> backendTypeComboBoxes = new HashMap<>(); 076 /** 077 * The display of the server the user provided in the replication options 078 * panel. 079 */ 080 private String serverToConnectDisplay; 081 082 private JLabel noSuffixLabel; 083 private Component labelGlue; 084 private JPanel checkBoxPanel; 085 private JScrollPane scroll; 086 087 /** 088 * Constructor of the panel. 089 * 090 * @param application 091 * Application represented by this panel and used to initialize the 092 * fields of the panel. 093 */ 094 public SuffixesToReplicatePanel(GuiApplication application) 095 { 096 super(application); 097 createComponents(); 098 } 099 100 @Override 101 public Object getFieldValue(FieldName fieldName) 102 { 103 if (fieldName == FieldName.SUFFIXES_TO_REPLICATE_OPTIONS) 104 { 105 return SuffixesToReplicateOptions.Type.REPLICATE_WITH_EXISTING_SUFFIXES; 106 } 107 else if (fieldName == FieldName.SUFFIXES_TO_REPLICATE) 108 { 109 return getSelectedSuffixes(); 110 } 111 else if (fieldName == FieldName.SUFFIXES_TO_REPLICATE_BACKEND_TYPE) 112 { 113 return getSelectedSuffixBackendTypes(); 114 } 115 116 return null; 117 } 118 119 private Set<SuffixDescriptor> getSelectedSuffixes() 120 { 121 Set<SuffixDescriptor> suffixes = new HashSet<>(); 122 for (SuffixDescriptor suffix : orderedSuffixes) 123 { 124 if (hmCheckBoxes.get(suffix.getId()).isSelected()) 125 { 126 suffixes.add(suffix); 127 } 128 } 129 return suffixes; 130 } 131 132 private Map<String, BackendTypeUIAdapter> getSelectedSuffixBackendTypes() 133 { 134 final Map<String, BackendTypeUIAdapter> backendTypes = new HashMap<>(); 135 for (SuffixDescriptor suffix : getSelectedSuffixes()) 136 { 137 final String backendName = suffix.getReplicas().iterator().next().getBackendName(); 138 backendTypes.put(backendName, (BackendTypeUIAdapter) backendTypeComboBoxes.get(backendName).getSelectedItem()); 139 } 140 return backendTypes; 141 } 142 143 @Override 144 public int compare(SuffixDescriptor desc1, SuffixDescriptor desc2) 145 { 146 int result = compareSuffixDN(desc1, desc2); 147 if (result == 0) 148 { 149 result = compareSuffixStrings(desc1, desc2); 150 } 151 return result; 152 } 153 154 @Override 155 protected Component createInputPanel() 156 { 157 JPanel panel = new JPanel(new GridBagLayout()); 158 panel.setOpaque(false); 159 160 GridBagConstraints gbc = new GridBagConstraints(); 161 gbc.weightx = 1.0; 162 gbc.anchor = GridBagConstraints.NORTHWEST; 163 gbc.fill = GridBagConstraints.HORIZONTAL; 164 gbc.gridwidth = GridBagConstraints.REMAINDER; 165 gbc.insets = UIFactory.getEmptyInsets(); 166 gbc.insets.top = UIFactory.TOP_INSET_SECONDARY_FIELD; 167 gbc.insets.left = UIFactory.LEFT_INSET_BACKGROUND; 168 169 // Add the checkboxes 170 checkBoxPanel = new JPanel(new GridBagLayout()); 171 checkBoxPanel.setOpaque(false); 172 gbc.insets.top = 0; 173 gbc.anchor = GridBagConstraints.NORTH; 174 gbc.weighty = 1.0; 175 gbc.fill = GridBagConstraints.BOTH; 176 scroll = UIFactory.createBorderLessScrollBar(checkBoxPanel); 177 panel.add(scroll, gbc); 178 179 gbc.insets.left = UIFactory.LEFT_INSET_SUBPANEL_SUBORDINATE; 180 gbc.weighty = 0.0; 181 gbc.fill = GridBagConstraints.HORIZONTAL; 182 gbc.insets.top = UIFactory.TOP_INSET_SECONDARY_FIELD; 183 gbc.anchor = GridBagConstraints.NORTHEAST; 184 panel.add(noSuffixLabel, gbc); 185 noSuffixLabel.setVisible(false); 186 187 labelGlue = Box.createVerticalGlue(); 188 gbc.fill = GridBagConstraints.VERTICAL; 189 gbc.weighty = 1.0; 190 panel.add(labelGlue, gbc); 191 labelGlue.setVisible(false); 192 193 return panel; 194 } 195 196 @Override 197 protected boolean requiresScroll() 198 { 199 return false; 200 } 201 202 @Override 203 protected LocalizableMessage getInstructions() 204 { 205 return INFO_SUFFIXES_TO_REPLICATE_PANEL_INSTRUCTIONS.get(); 206 } 207 208 @Override 209 protected LocalizableMessage getTitle() 210 { 211 return INFO_SUFFIXES_TO_REPLICATE_PANEL_TITLE.get(); 212 } 213 214 @Override 215 public void beginDisplay(UserData data) 216 { 217 Set<SuffixDescriptor> array = orderSuffixes(data.getSuffixesToReplicateOptions().getAvailableSuffixes()); 218 AuthenticationData authData = data.getReplicationOptions().getAuthenticationData(); 219 String newServerDisplay; 220 newServerDisplay = authData != null ? authData.getHostName() + ":" + authData.getPort() : ""; 221 222 if (!array.equals(orderedSuffixes) || !newServerDisplay.equals(serverToConnectDisplay)) 223 { 224 serverToConnectDisplay = newServerDisplay; 225 Map<String, Boolean> hmOldValues = new HashMap<>(); 226 for (String id : hmCheckBoxes.keySet()) 227 { 228 hmOldValues.put(id, hmCheckBoxes.get(id).isSelected()); 229 } 230 orderedSuffixes.clear(); 231 for (SuffixDescriptor suffix : array) 232 { 233 if (!Utils.areDnsEqual(suffix.getDN(), ADSContext.getAdministrationSuffixDN()) 234 && !Utils.areDnsEqual(suffix.getDN(), Constants.SCHEMA_DN) 235 && !Utils.areDnsEqual(suffix.getDN(), Constants.REPLICATION_CHANGES_DN)) 236 { 237 orderedSuffixes.add(suffix); 238 } 239 } 240 hmCheckBoxes.clear(); 241 for (SuffixDescriptor suffix : orderedSuffixes) 242 { 243 JCheckBox cb = UIFactory.makeJCheckBox(LocalizableMessage.raw(suffix.getDN()), 244 INFO_SUFFIXES_TO_REPLICATE_DN_TOOLTIP.get(), UIFactory.TextStyle.SECONDARY_FIELD_VALID); 245 cb.setOpaque(false); 246 Boolean v = hmOldValues.get(suffix.getId()); 247 if (v != null) 248 { 249 cb.setSelected(v); 250 } 251 hmCheckBoxes.put(suffix.getId(), cb); 252 } 253 populateCheckBoxPanel(); 254 } 255 256 boolean display = !orderedSuffixes.isEmpty(); 257 noSuffixLabel.setVisible(!display); 258 labelGlue.setVisible(!display); 259 scroll.setVisible(display); 260 } 261 262 /** Creates the components of this panel. */ 263 private void createComponents() 264 { 265 noSuffixLabel = UIFactory.makeJLabel( 266 UIFactory.IconType.NO_ICON, INFO_SUFFIX_LIST_EMPTY.get(), UIFactory.TextStyle.SECONDARY_FIELD_VALID); 267 } 268 269 private void populateCheckBoxPanel() 270 { 271 checkBoxPanel.removeAll(); 272 final GridBagConstraints gbc = new GridBagConstraints(); 273 gbc.fill = GridBagConstraints.BOTH; 274 gbc.insets = SUFFIXES_TO_REPLICATE_INSETS; 275 gbc.gridy = 0; 276 277 final Map<String, Set<SuffixDescriptor>> backendToSuffixes = getSuffixesForBackends(); 278 for (Map.Entry<String, Set<SuffixDescriptor>> backendData : backendToSuffixes.entrySet()) 279 { 280 gbc.anchor = GridBagConstraints.LINE_START; 281 gbc.gridwidth = 1; 282 gbc.gridheight = 1; 283 for (SuffixDescriptor suffix : backendData.getValue()) 284 { 285 gbc.gridx = 0; 286 final JCheckBox cb = hmCheckBoxes.get(suffix.getId()); 287 checkBoxPanel.add(cb, gbc); 288 printReplicaTooltipButton(suffix, gbc); 289 gbc.gridy++; 290 } 291 printBackendInformations(backendData, gbc); 292 printSeparatorLine(gbc); 293 } 294 gbc.weighty = 1.0; 295 gbc.insets = UIFactory.getEmptyInsets(); 296 gbc.fill = GridBagConstraints.VERTICAL; 297 checkBoxPanel.add(Box.createVerticalGlue(), gbc); 298 } 299 300 private Map<String, Set<SuffixDescriptor>> getSuffixesForBackends() 301 { 302 final Map<String, Set<SuffixDescriptor>> backendToSuffixes = new HashMap<>(); 303 for (SuffixDescriptor suffix : orderedSuffixes) 304 { 305 final String backendName = suffix.getReplicas().iterator().next().getBackendName(); 306 if (!backendToSuffixes.containsKey(backendName)) 307 { 308 backendToSuffixes.put(backendName, new LinkedHashSet<SuffixDescriptor>()); 309 } 310 backendToSuffixes.get(backendName).add(suffix); 311 } 312 313 return backendToSuffixes; 314 } 315 316 private void printReplicaTooltipButton(SuffixDescriptor suffix, GridBagConstraints gbc) 317 { 318 gbc.gridx++; 319 String imageDesc = "<html>"; 320 for (ReplicaDescriptor replica : suffix.getReplicas()) 321 { 322 imageDesc += getServerDisplay(replica) + "<br>"; 323 } 324 final int entriesNb = suffix.getReplicas().iterator().next().getEntries(); 325 final LocalizableMessage entriesNbToPrint = getNumberOfEntriesMsg(entriesNb); 326 imageDesc += entriesNbToPrint + "</html>"; 327 328 final JLabel helpReplicasTooltip = new JLabel(); 329 helpReplicasTooltip.setIcon(UIFactory.getImageIcon(IconType.HELP_MEDIUM)); 330 helpReplicasTooltip.setToolTipText(imageDesc); 331 UIFactory.setTextStyle(helpReplicasTooltip, UIFactory.TextStyle.SECONDARY_FIELD_VALID); 332 checkBoxPanel.add(helpReplicasTooltip, gbc); 333 } 334 335 private LocalizableMessage getNumberOfEntriesMsg(int nEntries) 336 { 337 if (nEntries > 0) 338 { 339 return INFO_SUFFIX_LIST_REPLICA_DISPLAY_ENTRIES.get(nEntries); 340 } 341 else if (nEntries == 0) 342 { 343 return INFO_SUFFIX_LIST_REPLICA_DISPLAY_NO_ENTRIES.get(); 344 } 345 else 346 { 347 return INFO_SUFFIX_LIST_REPLICA_DISPLAY_ENTRIES_NOT_AVAILABLE.get(); 348 } 349 } 350 351 private void printBackendInformations(Map.Entry<String, Set<SuffixDescriptor>> backendData, GridBagConstraints gbc) 352 { 353 final int nbSuffixForBackend = backendData.getValue().size(); 354 gbc.gridy -= nbSuffixForBackend; 355 printBackendNameText(backendData, gbc); 356 printComboBoxForSuffix(backendData.getValue().iterator().next(), gbc); 357 gbc.gridy += nbSuffixForBackend; 358 } 359 360 private void printSeparatorLine(GridBagConstraints gbc) 361 { 362 gbc.gridwidth = gbc.gridx; 363 gbc.gridx = 0; 364 checkBoxPanel.add(new JSeparator(SwingConstants.HORIZONTAL), gbc); 365 gbc.gridy++; 366 } 367 368 private void printBackendNameText(Entry<String, Set<SuffixDescriptor>> backendData, GridBagConstraints gbc) 369 { 370 gbc.gridx++; 371 final JEditorPane backendNameText = UIFactory.makeTextPane( 372 LocalizableMessage.raw(backendData.getKey()), UIFactory.TextStyle.SECONDARY_FIELD_VALID); 373 backendNameText.setToolTipText(INFO_REPLICATED_SUFFIXES_BACKEND_NAME_TOOLTIP.get().toString()); 374 gbc.anchor = GridBagConstraints.CENTER; 375 checkBoxPanel.add(backendNameText, gbc); 376 } 377 378 private void printComboBoxForSuffix(SuffixDescriptor suffix, GridBagConstraints gbc) 379 { 380 gbc.gridx++; 381 gbc.anchor = GridBagConstraints.LINE_END; 382 gbc.insets = UIFactory.getEmptyInsets(); 383 final ReplicaDescriptor backendData = suffix.getReplicas().iterator().next(); 384 final JComboBox<BackendTypeUIAdapter> backendTypeComboBox = 385 new JComboBox<>(new BackendTypeHelper().getBackendTypeUIAdaptors()); 386 backendTypeComboBox.setToolTipText(INFO_REPLICATED_SUFFIXES_BACKEND_TYPE_TOOLTIP.get().toString()); 387 final Set<String> objectClasses = backendData.getObjectClasses(); 388 backendTypeComboBox.setSelectedItem(getBackendTypeFromObjectClasses(objectClasses)); 389 backendTypeComboBoxes.put(backendData.getBackendName(), backendTypeComboBox); 390 checkBoxPanel.add(backendTypeComboBox, gbc); 391 gbc.insets = SUFFIXES_TO_REPLICATE_INSETS; 392 } 393 394 /** 395 * Returns the concrete backend type corresponding to the provided object 396 * classes. If the backend is not found, returns the default backend of this 397 * server configuration. 398 * 399 * @param objectClasses 400 * The set of object class with one should be a concrete backend 401 * type. 402 * @return The concrete backend type corresponding to object classes or this 403 * server default one. 404 */ 405 private BackendTypeUIAdapter getBackendTypeFromObjectClasses(Set<String> objectClasses) 406 { 407 for (String objectClass : objectClasses) 408 { 409 BackendTypeUIAdapter adapter = 410 BackendTypeHelper.getBackendTypeAdapter(objectClass.replace(ConfigConstants.NAME_PREFIX_CFG, "")); 411 if (adapter != null) 412 { 413 return adapter; 414 } 415 } 416 417 return new BackendTypeHelper().getBackendTypeUIAdaptors()[0]; 418 } 419 420 private String getSuffixString(SuffixDescriptor desc) 421 { 422 Set<String> replicaDisplays = new TreeSet<>(); 423 for (ReplicaDescriptor rep : desc.getReplicas()) 424 { 425 replicaDisplays.add(getServerDisplay(rep)); 426 } 427 return joinAsString("\n", replicaDisplays); 428 } 429 430 private String getServerDisplay(ReplicaDescriptor replica) 431 { 432 final boolean isServerToConnect = replica.getServer().getHostPort(false).equalsIgnoreCase(serverToConnectDisplay); 433 return isServerToConnect ? serverToConnectDisplay : replica.getServer().getHostPort(true); 434 } 435 436 private Set<SuffixDescriptor> orderSuffixes(Set<SuffixDescriptor> suffixes) 437 { 438 Set<SuffixDescriptor> ordered = new TreeSet<>(this); 439 ordered.addAll(suffixes); 440 441 return ordered; 442 } 443 444 private int compareSuffixDN(SuffixDescriptor desc1, SuffixDescriptor desc2) 445 { 446 return desc1.getDN().compareTo(desc2.getDN()); 447 } 448 449 private int compareSuffixStrings(SuffixDescriptor desc1, SuffixDescriptor desc2) 450 { 451 return getSuffixString(desc1).compareTo(getSuffixString(desc2)); 452 } 453 454}