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 2014-2015 ForgeRock AS 026 */ 027package org.opends.guitools.controlpanel.ui; 028 029import static org.opends.messages.AdminToolMessages.*; 030 031import java.awt.Component; 032import java.awt.GridBagConstraints; 033import java.awt.GridBagLayout; 034import java.awt.event.ActionEvent; 035import java.awt.event.ActionListener; 036import java.util.ArrayList; 037import java.util.Collection; 038import java.util.Collections; 039import java.util.HashMap; 040import java.util.HashSet; 041import java.util.LinkedHashSet; 042import java.util.Map; 043import java.util.Set; 044import java.util.SortedSet; 045import java.util.TreeSet; 046 047import javax.swing.Box; 048import javax.swing.DefaultListModel; 049import javax.swing.JButton; 050import javax.swing.JLabel; 051import javax.swing.JList; 052import javax.swing.JPanel; 053import javax.swing.SwingUtilities; 054import javax.swing.event.ListSelectionEvent; 055import javax.swing.event.ListSelectionListener; 056 057import org.forgerock.i18n.LocalizableMessage; 058import org.forgerock.i18n.LocalizableMessageBuilder; 059import org.opends.guitools.controlpanel.datamodel.BackendDescriptor; 060import org.opends.guitools.controlpanel.datamodel.BaseDNDescriptor; 061import org.opends.guitools.controlpanel.datamodel.ServerDescriptor; 062import org.opends.guitools.controlpanel.event.ConfigurationChangeEvent; 063import org.opends.guitools.controlpanel.task.DeleteBaseDNAndBackendTask; 064import org.opends.guitools.controlpanel.task.Task; 065import org.opends.guitools.controlpanel.ui.renderer.CustomListCellRenderer; 066import org.opends.guitools.controlpanel.util.Utilities; 067import org.opends.server.types.DN; 068 069/** 070 * The panel displayed when the user clicks on 'Delete Base DN...' in the 071 * browse entries dialog. 072 */ 073public class DeleteBaseDNPanel extends StatusGenericPanel 074{ 075 private static final long serialVersionUID = 2182662824496761087L; 076 077 /** The list containing the base DNs. */ 078 protected JList list; 079 /** Label indicating that no element was found. */ 080 protected JLabel lNoElementsFound; 081 /** The main panel. */ 082 protected JPanel mainPanel; 083 084 /** Default constructor. */ 085 public DeleteBaseDNPanel() 086 { 087 super(); 088 createLayout(); 089 } 090 091 /** {@inheritDoc} */ 092 public LocalizableMessage getTitle() 093 { 094 return INFO_CTRL_PANEL_DELETE_BASE_DN_TITLE.get(); 095 } 096 097 /** {@inheritDoc} */ 098 public Component getPreferredFocusComponent() 099 { 100 return list; 101 } 102 103 /** {@inheritDoc} */ 104 public boolean requiresScroll() 105 { 106 return false; 107 } 108 109 /** 110 * Returns the no backend found label. 111 * @return the no backend found label. 112 */ 113 protected LocalizableMessage getNoElementsFoundLabel() 114 { 115 return INFO_CTRL_PANEL_NO_BASE_DNS_FOUND_LABEL.get(); 116 } 117 118 /** 119 * Returns the list label. 120 * @return the list label. 121 */ 122 protected LocalizableMessage getListLabel() 123 { 124 return INFO_CTRL_PANEL_SELECT_BASE_DNS_TO_DELETE.get(); 125 } 126 127 /** 128 * Updates the list of base DNs. 129 * @param newElements the base DNs to be used to update the list. 130 */ 131 protected void updateList(final Collection<?> newElements) 132 { 133 final DefaultListModel model = (DefaultListModel)list.getModel(); 134 boolean changed = newElements.size() != model.getSize(); 135 if (!changed) 136 { 137 int i = 0; 138 for (Object newElement : newElements) 139 { 140 changed = !newElement.equals(model.getElementAt(i)); 141 if (changed) 142 { 143 break; 144 } 145 i++; 146 } 147 } 148 if (changed) 149 { 150 SwingUtilities.invokeLater(new Runnable() 151 { 152 /** {@inheritDoc} */ 153 public void run() 154 { 155 @SuppressWarnings("deprecation") 156 Object[] s = list.getSelectedValues(); 157 Set<Object> selected = new HashSet<>(); 158 if (s != null) 159 { 160 Collections.addAll(selected, s); 161 } 162 final DefaultListModel model = (DefaultListModel)list.getModel(); 163 model.clear(); 164 SortedSet<Integer> indices = new TreeSet<>(); 165 int i = 0; 166 for (Object newElement : newElements) 167 { 168 model.addElement(newElement); 169 if (selected.contains(newElement)) 170 { 171 indices.add(i); 172 } 173 i ++; 174 } 175 if (!selected.isEmpty()) 176 { 177 list.setSelectedIndices(toIntArray(indices)); 178 } 179 checkVisibility(); 180 } 181 182 private int[] toIntArray(Set<Integer> indices) 183 { 184 int[] result = new int[indices.size()]; 185 int i = 0; 186 for (Integer index : indices) 187 { 188 result[i] = index; 189 i++; 190 } 191 return result; 192 } 193 }); 194 } 195 } 196 197 private void checkVisibility() 198 { 199 mainPanel.setVisible(list.getModel().getSize() > 0); 200 lNoElementsFound.setVisible(list.getModel().getSize() == 0); 201 } 202 203 /** Creates the layout of the panel (but the contents are not populated here). */ 204 private void createLayout() 205 { 206 GridBagConstraints gbc = new GridBagConstraints(); 207 208 gbc.gridx = 0; 209 gbc.gridy = 0; 210 gbc.gridwidth = 1; 211 addErrorPane(gbc); 212 213 mainPanel = new JPanel(new GridBagLayout()); 214 mainPanel.setOpaque(false); 215 gbc.gridy ++; 216 gbc.weightx = 1.0; 217 gbc.weighty = 1.0; 218 gbc.fill = GridBagConstraints.BOTH; 219 add(mainPanel, gbc); 220 221 gbc.anchor = GridBagConstraints.CENTER; 222 gbc.fill = GridBagConstraints.NONE; 223 lNoElementsFound = Utilities.createPrimaryLabel(getNoElementsFoundLabel()); 224 add(lNoElementsFound, gbc); 225 lNoElementsFound.setVisible(false); 226 227 gbc.gridy = 0; 228 gbc.anchor = GridBagConstraints.WEST; 229 gbc.weightx = 0.0; 230 gbc.gridwidth = 2; 231 gbc.weightx = 0.0; 232 gbc.weighty = 0.0; 233 gbc.fill = GridBagConstraints.NONE; 234 JLabel lBaseDNs = 235 Utilities.createPrimaryLabel(getListLabel()); 236 mainPanel.add(lBaseDNs, gbc); 237 gbc.insets.top = 5; 238 list = new JList(new DefaultListModel()); 239 list.setCellRenderer(new CustomListCellRenderer(list)); 240 list.setVisibleRowCount(15); 241 gbc.gridy ++; 242 gbc.gridheight = 3; 243 gbc.gridwidth = 1; 244 gbc.weightx = 1.0; 245 gbc.weighty = 1.0; 246 gbc.fill = GridBagConstraints.BOTH; 247 mainPanel.add(Utilities.createScrollPane(list), gbc); 248 249 JButton selectAllButton = Utilities.createButton( 250 INFO_CTRL_PANEL_SELECT_ALL_BUTTON.get()); 251 selectAllButton.addActionListener(new ActionListener() 252 { 253 /** {@inheritDoc} */ 254 public void actionPerformed(ActionEvent ev) 255 { 256 int[] indices = new int[list.getModel().getSize()]; 257 for (int i=0 ; i<indices.length; i++) 258 { 259 indices[i] = i; 260 } 261 list.setSelectedIndices(indices); 262 } 263 }); 264 gbc.gridx ++; 265 gbc.gridheight = 1; 266 gbc.fill = GridBagConstraints.HORIZONTAL; 267 gbc.insets.left = 5; 268 gbc.weightx = 0.0; 269 gbc.weighty = 0.0; 270 mainPanel.add(selectAllButton, gbc); 271 272 gbc.gridy ++; 273 JButton unselectAllButton = Utilities.createButton( 274 INFO_CTRL_PANEL_CLEAR_SELECTION_BUTTON.get()); 275 unselectAllButton.addActionListener(new ActionListener() 276 { 277 /** {@inheritDoc} */ 278 public void actionPerformed(ActionEvent ev) 279 { 280 list.clearSelection(); 281 } 282 }); 283 mainPanel.add(unselectAllButton, gbc); 284 285 list.addListSelectionListener(new ListSelectionListener() 286 { 287 /** {@inheritDoc} */ 288 public void valueChanged(ListSelectionEvent ev) 289 { 290 checkOKButtonEnable(); 291 } 292 }); 293 294 gbc.gridy ++; 295 gbc.fill = GridBagConstraints.VERTICAL; 296 gbc.insets.top = 0; 297 gbc.weighty = 1.0; 298 mainPanel.add(Box.createVerticalGlue(), gbc); 299 } 300 301 /** {@inheritDoc} */ 302 public void toBeDisplayed(boolean visible) 303 { 304 if (visible) 305 { 306 list.clearSelection(); 307 checkVisibility(); 308 } 309 } 310 311 /** {@inheritDoc} */ 312 protected void checkOKButtonEnable() 313 { 314 setEnabledOK(!list.isSelectionEmpty() && mainPanel.isVisible()); 315 } 316 317 /** {@inheritDoc} */ 318 public void configurationChanged(ConfigurationChangeEvent ev) 319 { 320 ServerDescriptor desc = ev.getNewDescriptor(); 321 final SortedSet<DN> newElements = new TreeSet<>(); 322 for (BackendDescriptor backend : desc.getBackends()) 323 { 324 if (!backend.isConfigBackend()) 325 { 326 for (BaseDNDescriptor baseDN : backend.getBaseDns()) 327 { 328 newElements.add(baseDN.getDn()); 329 } 330 } 331 } 332 updateList(newElements); 333 updateErrorPaneAndOKButtonIfAuthRequired(desc, 334 isLocal() ? 335 INFO_CTRL_PANEL_AUTHENTICATION_REQUIRED_FOR_BASE_DN_DELETE.get() : 336 INFO_CTRL_PANEL_CANNOT_CONNECT_TO_REMOTE_DETAILS.get(desc.getHostname())); 337 } 338 339 /** {@inheritDoc} */ 340 public void okClicked() 341 { 342 final LinkedHashSet<LocalizableMessage> errors = new LinkedHashSet<>(); 343 ProgressDialog progressDialog = new ProgressDialog( 344 Utilities.createFrame(), 345 Utilities.getParentDialog(this), getTitle(), getInfo()); 346 @SuppressWarnings("deprecation") 347 Object[] dns = list.getSelectedValues(); 348 ArrayList<BaseDNDescriptor> baseDNsToDelete = new ArrayList<>(); 349 for (Object o : dns) 350 { 351 DN dn = (DN)o; 352 BaseDNDescriptor baseDN = findBaseDN(dn); 353 if (baseDN != null) 354 { 355 baseDNsToDelete.add(baseDN); 356 } 357 } 358 DeleteBaseDNAndBackendTask newTask = new DeleteBaseDNAndBackendTask( 359 getInfo(), progressDialog, new HashSet<BackendDescriptor>(), 360 baseDNsToDelete); 361 for (Task task : getInfo().getTasks()) 362 { 363 task.canLaunch(newTask, errors); 364 } 365 if (errors.isEmpty()) 366 { 367 LocalizableMessage confirmationMessage = getConfirmationMessage(baseDNsToDelete); 368 if (displayConfirmationDialog( 369 INFO_CTRL_PANEL_CONFIRMATION_REQUIRED_SUMMARY.get(), 370 confirmationMessage)) 371 { 372 launchOperation(newTask, 373 INFO_CTRL_PANEL_DELETING_BASE_DNS_SUMMARY.get(), 374 INFO_CTRL_PANEL_DELETING_BASE_DNS_COMPLETE.get(), 375 INFO_CTRL_PANEL_DELETING_BASE_DNS_SUCCESSFUL.get(), 376 ERR_CTRL_PANEL_DELETING_BASE_DNS_ERROR_SUMMARY.get(), 377 ERR_CTRL_PANEL_DELETING_BASE_DNS_ERROR_DETAILS.get(), 378 null, 379 progressDialog); 380 progressDialog.setVisible(true); 381 Utilities.getParentDialog(this).setVisible(false); 382 } 383 } 384 if (!errors.isEmpty()) 385 { 386 displayErrorDialog(errors); 387 } 388 } 389 390 private BaseDNDescriptor findBaseDN(DN dn) 391 { 392 for (BackendDescriptor backend : getInfo().getServerDescriptor().getBackends()) 393 { 394 for (BaseDNDescriptor baseDN : backend.getBaseDns()) 395 { 396 if (baseDN.getDn().equals(dn)) 397 { 398 return baseDN; 399 } 400 } 401 } 402 return null; 403 } 404 405 private LocalizableMessage getConfirmationMessage( 406 Collection<BaseDNDescriptor> baseDNsToDelete) 407 { 408 LocalizableMessageBuilder mb = new LocalizableMessageBuilder(); 409 Map<String, Set<BaseDNDescriptor>> hmBackends = new HashMap<>(); 410 for (BaseDNDescriptor baseDN : baseDNsToDelete) 411 { 412 String backendID = baseDN.getBackend().getBackendID(); 413 Set<BaseDNDescriptor> set = hmBackends.get(backendID); 414 if (set == null) 415 { 416 set = new HashSet<>(); 417 hmBackends.put(backendID, set); 418 } 419 set.add(baseDN); 420 } 421 ArrayList<String> indirectBackendsToDelete = new ArrayList<>(); 422 for (Set<BaseDNDescriptor> set : hmBackends.values()) 423 { 424 BackendDescriptor backend = set.iterator().next().getBackend(); 425 if (set.size() == backend.getBaseDns().size()) 426 { 427 // All of the suffixes must be deleted. 428 indirectBackendsToDelete.add(backend.getBackendID()); 429 } 430 } 431 mb.append(INFO_CTRL_PANEL_CONFIRMATION_DELETE_BASE_DNS_DETAILS.get()); 432 for (BaseDNDescriptor baseDN : baseDNsToDelete) 433 { 434 mb.append("<br> - ").append(baseDN.getDn()); 435 } 436 if (!indirectBackendsToDelete.isEmpty()) 437 { 438 mb.append("<br><br>"); 439 mb.append( 440 INFO_CTRL_PANEL_CONFIRMATION_DELETE_BASE_DNS_INDIRECT_DETAILS.get()); 441 for (String backendID : indirectBackendsToDelete) 442 { 443 mb.append("<br> - ").append(backendID); 444 } 445 } 446 mb.append("<br><br>"); 447 mb.append(INFO_CTRL_PANEL_DO_YOU_WANT_TO_CONTINUE.get()); 448 return mb.toMessage(); 449 } 450}