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-2015 ForgeRock AS. 016 */ 017 018package org.opends.guitools.controlpanel.ui; 019 020import static org.opends.messages.AdminToolMessages.*; 021 022import java.awt.Component; 023import java.awt.GridBagConstraints; 024import java.awt.event.ItemEvent; 025import java.awt.event.ItemListener; 026import java.util.ArrayList; 027import java.util.Collection; 028import java.util.HashMap; 029import java.util.LinkedHashSet; 030import java.util.List; 031import java.util.Map; 032import java.util.Set; 033import java.util.SortedSet; 034import java.util.TreeSet; 035 036import javax.swing.ButtonGroup; 037import javax.swing.DefaultComboBoxModel; 038import javax.swing.JComboBox; 039import javax.swing.JLabel; 040import javax.swing.JRadioButton; 041import javax.swing.JScrollPane; 042import javax.swing.ListCellRenderer; 043import javax.swing.SwingUtilities; 044 045import org.forgerock.i18n.LocalizableMessage; 046import org.opends.guitools.controlpanel.datamodel.AbstractIndexDescriptor; 047import org.opends.guitools.controlpanel.datamodel.BackendDescriptor; 048import org.opends.guitools.controlpanel.datamodel.CategorizedComboBoxElement; 049import org.opends.guitools.controlpanel.datamodel.ControlPanelInfo; 050import org.opends.guitools.controlpanel.datamodel.IndexDescriptor; 051import org.opends.guitools.controlpanel.datamodel.ServerDescriptor; 052import org.opends.guitools.controlpanel.datamodel.SortableListModel; 053import org.opends.guitools.controlpanel.datamodel.VLVIndexDescriptor; 054import org.opends.guitools.controlpanel.event.ConfigurationChangeEvent; 055import org.opends.guitools.controlpanel.event.IndexModifiedEvent; 056import org.opends.guitools.controlpanel.event.IndexModifiedListener; 057import org.opends.guitools.controlpanel.task.IndexTask; 058import org.opends.guitools.controlpanel.task.Task; 059import org.opends.guitools.controlpanel.ui.components.AddRemovePanel; 060import org.opends.guitools.controlpanel.ui.renderer.CustomListCellRenderer; 061import org.opends.guitools.controlpanel.ui.renderer.IndexCellRenderer; 062import org.opends.guitools.controlpanel.ui.renderer.IndexComboBoxCellRenderer; 063import org.opends.guitools.controlpanel.util.Utilities; 064import org.opends.guitools.controlpanel.util.ViewPositions; 065 066/** 067 * The panel that appears when the user wants to verify an index. 068 */ 069public class VerifyIndexPanel extends StatusGenericPanel implements IndexModifiedListener 070{ 071 private static final long serialVersionUID = 5252070109221657041L; 072 private JComboBox<?> baseDNs; 073 private JRadioButton verifyIndexContents; 074 private JRadioButton verifyKeyEntryIDs; 075 private AddRemovePanel<AbstractIndexDescriptor> addRemove; 076 private JComboBox<?> keyEntryIDs; 077 private Map<String, SortedSet<AbstractIndexDescriptor>> hmIndexes = new HashMap<>(); 078 079 private JLabel lBaseDN; 080 private JLabel lAction; 081 private JLabel lIndex; 082 private JLabel lNoBaseDNsFound; 083 084 /** Constructor of the panel. */ 085 public VerifyIndexPanel() 086 { 087 super(); 088 createLayout(); 089 } 090 091 @Override 092 public void setInfo(ControlPanelInfo info) 093 { 094 super.setInfo(info); 095 ListCellRenderer indexCellRenderer = new IndexCellRenderer(addRemove.getAvailableList(), info); 096 addRemove.getAvailableList().setCellRenderer(indexCellRenderer); 097 addRemove.getSelectedList().setCellRenderer(indexCellRenderer); 098 info.addIndexModifiedListener(this); 099 } 100 101 @Override 102 public void indexModified(IndexModifiedEvent ev) 103 { 104 refreshContents(getInfo().getServerDescriptor()); 105 } 106 107 @Override 108 public void backendIndexesModified(IndexModifiedEvent ev) 109 { 110 refreshContents(getInfo().getServerDescriptor()); 111 } 112 113 /** Creates the layout of the panel (but the contents are not populated here). */ 114 private void createLayout() 115 { 116 GridBagConstraints gbc = new GridBagConstraints(); 117 gbc.anchor = GridBagConstraints.WEST; 118 gbc.weightx = 0.0; 119 gbc.gridx = 0; 120 gbc.gridy = 0; 121 gbc.gridwidth = 1; 122 gbc.fill = GridBagConstraints.NONE; 123 lBaseDN = Utilities.createPrimaryLabel(INFO_CTRL_PANEL_BASE_DN_LABEL.get()); 124 add(lBaseDN, gbc); 125 gbc.insets.left = 10; 126 gbc.gridx = 1; 127 gbc.gridy = 0; 128 baseDNs = Utilities.createComboBox(); 129 DefaultComboBoxModel model = new DefaultComboBoxModel(); 130 baseDNs.setModel(model); 131 baseDNs.setRenderer(new CustomListCellRenderer(baseDNs)); 132 ItemListener listener = new IgnoreItemListener(baseDNs); 133 baseDNs.addItemListener(listener); 134 baseDNs.addItemListener(new ItemListener() 135 { 136 @Override 137 public void itemStateChanged(ItemEvent ev) 138 { 139 comboBoxSelected(hmIndexes, (CategorizedComboBoxElement) baseDNs.getSelectedItem(), addRemove); 140 updateVerifyKeyEntriesComboBox(); 141 } 142 }); 143 listener.itemStateChanged(null); 144 gbc.gridwidth = 2; 145 add(baseDNs, gbc); 146 lNoBaseDNsFound = Utilities.createDefaultLabel(INFO_CTRL_PANEL_NO_BASE_DNS_FOUND_LABEL.get()); 147 add(lNoBaseDNsFound, gbc); 148 lNoBaseDNsFound.setVisible(false); 149 150 lAction = Utilities.createPrimaryLabel(INFO_CTRL_PANEL_ACTION_LABEL.get()); 151 gbc.insets.top = 10; 152 gbc.gridy++; 153 gbc.gridx = 0; 154 gbc.gridwidth = 1; 155 add(lAction, gbc); 156 157 verifyIndexContents = Utilities.createRadioButton(INFO_CTRL_PANEL_VERIFY_ENTRY_CONTEXT_ARE_INDEXES.get()); 158 verifyIndexContents.setSelected(true); 159 gbc.insets.left = 10; 160 gbc.gridx = 1; 161 gbc.gridwidth = 2; 162 add(verifyIndexContents, gbc); 163 164 addRemove = new AddRemovePanel<>(AbstractIndexDescriptor.class); 165 addRemove.getAvailableLabel().setText(INFO_CTRL_PANEL_AVAILABLE_INDEXES_LABEL.get().toString()); 166 addRemove.getSelectedLabel().setText(INFO_CTRL_PANEL_SELECTED_INDEXES_LABEL.get().toString()); 167 168 gbc.gridy++; 169 gbc.weightx = 1.0; 170 gbc.weighty = 0.0; 171 gbc.gridwidth = 2; 172 gbc.insets.top = 5; 173 gbc.insets.left = 30; 174 gbc.fill = GridBagConstraints.BOTH; 175 add(addRemove, gbc); 176 177 gbc.gridy++; 178 JLabel explanation = Utilities.createInlineHelpLabel(INFO_CTRL_PANEL_REQUIRES_REBUILD_LEGEND.get()); 179 gbc.insets.top = 3; 180 add(explanation, gbc); 181 182 verifyKeyEntryIDs = Utilities.createRadioButton(INFO_CTRL_PANEL_VERIFY_ALL_KEYS.get()); 183 verifyKeyEntryIDs.setSelected(true); 184 gbc.insets.left = 10; 185 gbc.insets.top = 10; 186 gbc.gridx = 1; 187 gbc.gridwidth = 2; 188 gbc.gridy++; 189 gbc.weighty = 0.0; 190 gbc.fill = GridBagConstraints.NONE; 191 add(verifyKeyEntryIDs, gbc); 192 193 gbc.gridy++; 194 gbc.insets.left = 30; 195 gbc.insets.top = 5; 196 gbc.gridwidth = 1; 197 gbc.weightx = 0.0; 198 lIndex = Utilities.createDefaultLabel(INFO_CTRL_PANEL_INDEX_LABEL.get()); 199 add(lIndex, gbc); 200 201 keyEntryIDs = Utilities.createComboBox(); 202 model = new DefaultComboBoxModel(); 203 keyEntryIDs.setModel(model); 204 keyEntryIDs.setRenderer(new IndexComboBoxCellRenderer(keyEntryIDs)); 205 listener = new IgnoreItemListener(keyEntryIDs); 206 keyEntryIDs.addItemListener(listener); 207 listener.itemStateChanged(null); 208 gbc.gridx = 2; 209 gbc.insets.left = 5; 210 add(keyEntryIDs, gbc); 211 212 addBottomGlue(gbc); 213 214 ButtonGroup group = new ButtonGroup(); 215 group.add(verifyIndexContents); 216 group.add(verifyKeyEntryIDs); 217 verifyIndexContents.setSelected(true); 218 listener = new ItemListener() 219 { 220 @Override 221 public void itemStateChanged(ItemEvent ev) 222 { 223 addRemove.setEnabled(verifyIndexContents.isSelected()); 224 keyEntryIDs.setEnabled(!verifyIndexContents.isSelected()); 225 lIndex.setEnabled(!verifyIndexContents.isSelected()); 226 } 227 }; 228 verifyIndexContents.addItemListener(listener); 229 listener.itemStateChanged(null); 230 } 231 232 @Override 233 public LocalizableMessage getTitle() 234 { 235 return INFO_CTRL_PANEL_VERIFY_INDEXES_PANEL_TITLE.get(); 236 } 237 238 @Override 239 public Component getPreferredFocusComponent() 240 { 241 return baseDNs; 242 } 243 244 @Override 245 public void configurationChanged(ConfigurationChangeEvent ev) 246 { 247 refreshContents(ev.getNewDescriptor()); 248 } 249 250 private void refreshContents(final ServerDescriptor desc) 251 { 252 updateIndexMap(desc, hmIndexes); 253 updateBaseDNComboBoxModel((DefaultComboBoxModel) baseDNs.getModel(), desc); 254 SwingUtilities.invokeLater(new Runnable() 255 { 256 @Override 257 public void run() 258 { 259 ViewPositions pos; 260 JScrollPane scroll = Utilities.getContainingScroll(VerifyIndexPanel.this); 261 if (scroll != null) 262 { 263 pos = Utilities.getViewPositions(scroll); 264 } 265 else 266 { 267 pos = Utilities.getViewPositions(VerifyIndexPanel.this); 268 } 269 comboBoxSelected(hmIndexes, (CategorizedComboBoxElement) baseDNs.getSelectedItem(), addRemove); 270 updateVerifyKeyEntriesComboBox(); 271 addRemove.getAvailableList().repaint(); 272 addRemove.getSelectedList().repaint(); 273 boolean comboVisible = baseDNs.getModel().getSize() > 0; 274 baseDNs.setVisible(comboVisible); 275 lNoBaseDNsFound.setVisible(!comboVisible); 276 Utilities.updateViewPositions(pos); 277 278 if (!desc.isLocal()) 279 { 280 displayErrorMessage(INFO_CTRL_PANEL_SERVER_REMOTE_SUMMARY.get(), 281 INFO_CTRL_PANEL_SERVER_MUST_BE_LOCAL_VERIFY_INDEX_SUMMARY.get()); 282 } 283 else 284 { 285 displayMainPanel(); 286 } 287 setEnabledOK(desc.isLocal()); 288 } 289 }); 290 } 291 292 @Override 293 public void cancelClicked() 294 { 295 setPrimaryValid(lBaseDN); 296 setSecondaryValid(addRemove.getSelectedLabel()); 297 setSecondaryValid(lIndex); 298 super.cancelClicked(); 299 } 300 301 @Override 302 public void okClicked() 303 { 304 setPrimaryValid(lBaseDN); 305 setSecondaryValid(addRemove.getSelectedLabel()); 306 setSecondaryValid(lIndex); 307 308 final Set<LocalizableMessage> errors = new LinkedHashSet<>(); 309 String baseDN = getSelectedBaseDN(); 310 311 if (baseDN == null) 312 { 313 setPrimaryInvalid(lBaseDN); 314 if (baseDNs.getItemCount() == 0) 315 { 316 errors.add(ERR_CTRL_PANEL_NO_BASE_DNS_DEFINED_LABEL.get()); 317 } 318 else 319 { 320 errors.add(ERR_CTRL_PANEL_MUST_SELECT_BASE_DN.get()); 321 } 322 } 323 324 if (verifyIndexContents.isSelected()) 325 { 326 SortableListModel<AbstractIndexDescriptor> model = addRemove.getSelectedListModel(); 327 if (model.getSize() == 0) 328 { 329 setSecondaryInvalid(addRemove.getSelectedLabel()); 330 errors.add(ERR_CTRL_PANEL_INDEX_TO_BE_VERIFIED_REQUIRED.get()); 331 } 332 } 333 else 334 { 335 AbstractIndexDescriptor index = getSelectedIndex(); 336 337 if (index == null) 338 { 339 setPrimaryInvalid(lIndex); 340 final boolean indexSelected = keyEntryIDs.getItemCount() == 0 && baseDN != null; 341 errors.add(indexSelected ? ERR_CTRL_PANEL_NO_INDEXES_FOR_BASEDN.get(baseDN) 342 : ERR_CTRL_PANEL_INDEX_MUST_BE_SELECTED.get()); 343 } 344 } 345 346 if (errors.isEmpty()) 347 { 348 ProgressDialog progressDialog = 349 new ProgressDialog(Utilities.createFrame(), Utilities.getParentDialog(this), getTitle(), getInfo()); 350 VerifyIndexTask newTask = new VerifyIndexTask(getInfo(), progressDialog); 351 for (Task task : getInfo().getTasks()) 352 { 353 task.canLaunch(newTask, errors); 354 } 355 if (errors.isEmpty()) 356 { 357 launchOperation(newTask, 358 INFO_CTRL_PANEL_VERIFYING_INDEXES_SUMMARY.get(baseDN), 359 INFO_CTRL_PANEL_VERIFYING_INDEXES_SUCCESSFUL_SUMMARY.get(), 360 INFO_CTRL_PANEL_VERIFYING_INDEXES_SUCCESSFUL_DETAILS.get(), 361 ERR_CTRL_PANEL_VERIFYING_INDEXES_ERROR_SUMMARY.get(), null, 362 ERR_CTRL_PANEL_VERIFYING_INDEXES_ERROR_DETAILS, progressDialog); 363 progressDialog.setVisible(true); 364 Utilities.getParentDialog(this).setVisible(false); 365 } 366 } 367 if (!errors.isEmpty()) 368 { 369 displayErrorDialog(errors); 370 } 371 } 372 373 @Override 374 protected boolean displayBackend(BackendDescriptor backend) 375 { 376 return !backend.isConfigBackend() && backend.getType() == BackendDescriptor.Type.PLUGGABLE; 377 } 378 379 private String getSelectedBaseDN() 380 { 381 CategorizedComboBoxElement o = (CategorizedComboBoxElement) baseDNs.getSelectedItem(); 382 return o != null ? (String) o.getValue() : null; 383 } 384 385 private AbstractIndexDescriptor getSelectedIndex() 386 { 387 CategorizedComboBoxElement o = (CategorizedComboBoxElement) keyEntryIDs.getSelectedItem(); 388 return o != null ? (AbstractIndexDescriptor) o.getValue() : null; 389 } 390 391 private void updateVerifyKeyEntriesComboBox() 392 { 393 String dn = getSelectedBaseDN(); 394 if (dn != null) 395 { 396 SortedSet<AbstractIndexDescriptor> indexes = hmIndexes.get(dn); 397 if (indexes != null) 398 { 399 List<CategorizedComboBoxElement> newElements = new ArrayList<>(); 400 List<AbstractIndexDescriptor> databaseIndexes = new ArrayList<>(); 401 List<AbstractIndexDescriptor> attributeIndexes = new ArrayList<>(); 402 List<AbstractIndexDescriptor> vlvIndexes = new ArrayList<>(); 403 for (AbstractIndexDescriptor index : indexes) 404 { 405 if (index instanceof IndexDescriptor) 406 { 407 IndexDescriptor standardIndex = (IndexDescriptor) index; 408 if (standardIndex.isDatabaseIndex()) 409 { 410 databaseIndexes.add(standardIndex); 411 } 412 else 413 { 414 attributeIndexes.add(standardIndex); 415 } 416 } 417 else 418 { 419 vlvIndexes.add(index); 420 } 421 } 422 addNewElements(databaseIndexes, INFO_CTRL_PANEL_DATABASE_INDEXES.get().toString(), newElements); 423 addNewElements(attributeIndexes, INFO_CTRL_PANEL_ATTRIBUTE_INDEXES.get().toString(), newElements); 424 addNewElements(vlvIndexes, INFO_CTRL_PANEL_VLV_INDEXES.get().toString(), newElements); 425 updateComboBoxModel(newElements, (DefaultComboBoxModel) keyEntryIDs.getModel()); 426 } 427 } 428 } 429 430 private void addNewElements(final List<AbstractIndexDescriptor> indexes, final String label, 431 final List<CategorizedComboBoxElement> elements) 432 { 433 if (!indexes.isEmpty()) 434 { 435 elements.add(new CategorizedComboBoxElement(label, CategorizedComboBoxElement.Type.CATEGORY)); 436 for (AbstractIndexDescriptor index : indexes) 437 { 438 elements.add(new CategorizedComboBoxElement(index, CategorizedComboBoxElement.Type.REGULAR)); 439 } 440 } 441 } 442 443 /** The task in charge of verifying the index. */ 444 protected class VerifyIndexTask extends IndexTask 445 { 446 private String baseDN; 447 448 /** 449 * The constructor of the task. 450 * 451 * @param info 452 * the control panel info. 453 * @param dlg 454 * the progress dialog that shows the progress of the task. 455 */ 456 public VerifyIndexTask(ControlPanelInfo info, ProgressDialog dlg) 457 { 458 super(info, dlg, getSelectedBaseDN()); 459 this.baseDN = getSelectedBaseDN(); 460 } 461 462 @Override 463 public Type getType() 464 { 465 return Type.VERIFY_INDEXES; 466 } 467 468 @Override 469 public LocalizableMessage getTaskDescription() 470 { 471 return INFO_CTRL_PANEL_VERIFY_INDEX_TASK_DESCRIPTION.get(baseDN); 472 } 473 474 @Override 475 public boolean canLaunch(Task taskToBeLaunched, Collection<LocalizableMessage> incompatibilityReasons) 476 { 477 boolean canLaunch = true; 478 if (state == State.RUNNING && runningOnSameServer(taskToBeLaunched)) 479 { 480 // All the operations are incompatible if they apply to this backend. 481 Set<String> backends = new TreeSet<>(taskToBeLaunched.getBackends()); 482 backends.retainAll(getBackends()); 483 Task.Type type = taskToBeLaunched.getType(); 484 if (type != Task.Type.BACKUP 485 && type != Task.Type.EXPORT_LDIF 486 && type != Task.Type.ENABLE_WINDOWS_SERVICE 487 && type != Task.Type.DISABLE_WINDOWS_SERVICE 488 && !backends.isEmpty()) 489 { 490 incompatibilityReasons.add(getIncompatibilityMessage(this, taskToBeLaunched)); 491 canLaunch = false; 492 } 493 } 494 return canLaunch; 495 } 496 497 @Override 498 public void runTask() 499 { 500 state = State.RUNNING; 501 lastException = null; 502 try 503 { 504 List<String> arguments = getCommandLineArguments(); 505 String[] args = arguments.toArray(new String[arguments.size()]); 506 507 returnCode = executeCommandLine(getCommandLinePath(), args); 508 state = returnCode == 0 ? State.FINISHED_SUCCESSFULLY : State.FINISHED_WITH_ERROR; 509 } 510 catch (Throwable t) 511 { 512 lastException = t; 513 state = State.FINISHED_WITH_ERROR; 514 } 515 } 516 517 @Override 518 protected List<String> getCommandLineArguments() 519 { 520 List<String> args = new ArrayList<>(); 521 522 args.add("--baseDN"); 523 args.add(getSelectedBaseDN()); 524 525 if (verifyIndexContents.isSelected()) 526 { 527 SortableListModel<AbstractIndexDescriptor> model = addRemove.getSelectedListModel(); 528 for (AbstractIndexDescriptor index : model.getData()) 529 { 530 args.add("--index"); 531 args.add(getName(index)); 532 } 533 } 534 else 535 { 536 args.add("--index"); 537 getName(getSelectedIndex()); 538 args.add("--clean"); 539 } 540 541 args.add("--countErrors"); 542 543 return args; 544 } 545 546 private String getName(AbstractIndexDescriptor index) 547 { 548 if (index instanceof VLVIndexDescriptor) 549 { 550 return Utilities.getVLVNameInCommandLine((VLVIndexDescriptor) index); 551 } 552 return index.getName(); 553 } 554 555 @Override 556 protected String getCommandLinePath() 557 { 558 return getCommandLinePath("verify-index"); 559 } 560 } 561}