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