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