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.event.ItemEvent; 034import java.awt.event.ItemListener; 035import java.util.HashMap; 036import java.util.HashSet; 037import java.util.Iterator; 038import java.util.LinkedHashSet; 039import java.util.Map; 040import java.util.Set; 041import java.util.SortedSet; 042 043import javax.swing.DefaultComboBoxModel; 044import javax.swing.JComboBox; 045import javax.swing.JLabel; 046import javax.swing.JScrollPane; 047import javax.swing.ListCellRenderer; 048import javax.swing.SwingUtilities; 049 050import org.forgerock.i18n.LocalizableMessage; 051import org.opends.guitools.controlpanel.datamodel.AbstractIndexDescriptor; 052import org.opends.guitools.controlpanel.datamodel.BackendDescriptor; 053import org.opends.guitools.controlpanel.datamodel.CategorizedComboBoxElement; 054import org.opends.guitools.controlpanel.datamodel.ControlPanelInfo; 055import org.opends.guitools.controlpanel.datamodel.IndexDescriptor; 056import org.opends.guitools.controlpanel.datamodel.ServerDescriptor; 057import org.opends.guitools.controlpanel.datamodel.SortableListModel; 058import org.opends.guitools.controlpanel.event.ConfigurationChangeEvent; 059import org.opends.guitools.controlpanel.event.IndexModifiedEvent; 060import org.opends.guitools.controlpanel.event.IndexModifiedListener; 061import org.opends.guitools.controlpanel.task.RebuildIndexTask; 062import org.opends.guitools.controlpanel.task.Task; 063import org.opends.guitools.controlpanel.ui.components.AddRemovePanel; 064import org.opends.guitools.controlpanel.ui.renderer.CustomListCellRenderer; 065import org.opends.guitools.controlpanel.ui.renderer.IndexCellRenderer; 066import org.opends.guitools.controlpanel.util.Utilities; 067import org.opends.guitools.controlpanel.util.ViewPositions; 068 069/** 070 * The panel that appears when the user wants to rebuild indexes. 071 */ 072public class RebuildIndexPanel extends StatusGenericPanel implements IndexModifiedListener 073{ 074 private static final long serialVersionUID = -4805445967165643375L; 075 private JComboBox baseDNs; 076 private AddRemovePanel<AbstractIndexDescriptor> addRemove; 077 078 private JLabel lBaseDN; 079 private JLabel lIndexes; 080 private JLabel lNoBaseDNsFound; 081 082 private final Map<String, SortedSet<AbstractIndexDescriptor>> hmIndexes = new HashMap<>(); 083 084 /** Constructor of the panel. */ 085 public RebuildIndexPanel() 086 { 087 createLayout(); 088 } 089 090 @Override 091 public void indexModified(final IndexModifiedEvent ev) 092 { 093 refreshContents(getInfo().getServerDescriptor()); 094 } 095 096 @Override 097 public void backendIndexesModified(final IndexModifiedEvent ev) 098 { 099 refreshContents(getInfo().getServerDescriptor()); 100 } 101 102 /** Creates the layout of the panel (but the contents are not populated here). */ 103 private void createLayout() 104 { 105 GridBagConstraints gbc = new GridBagConstraints(); 106 gbc.anchor = GridBagConstraints.WEST; 107 gbc.weightx = 0.0; 108 gbc.gridx = 0; 109 gbc.gridy = 0; 110 gbc.gridwidth = 3; 111 addErrorPane(gbc); 112 gbc.gridwidth = 1; 113 gbc.fill = GridBagConstraints.NONE; 114 lBaseDN = Utilities.createPrimaryLabel(INFO_CTRL_PANEL_BASE_DN_LABEL.get()); 115 add(lBaseDN, gbc); 116 gbc.insets.left = 10; 117 gbc.gridx = 1; 118 gbc.gridy = 0; 119 baseDNs = Utilities.createComboBox(); 120 DefaultComboBoxModel model = new DefaultComboBoxModel(); 121 baseDNs.setModel(model); 122 baseDNs.setRenderer(new CustomListCellRenderer(baseDNs)); 123 ItemListener listener = new IgnoreItemListener(baseDNs); 124 baseDNs.addItemListener(listener); 125 baseDNs.addItemListener(new ItemListener() 126 { 127 @Override 128 public void itemStateChanged(final ItemEvent ev) 129 { 130 comboBoxSelected(hmIndexes, (CategorizedComboBoxElement) baseDNs.getSelectedItem(), addRemove); 131 } 132 }); 133 listener.itemStateChanged(null); 134 add(baseDNs, gbc); 135 lNoBaseDNsFound = Utilities.createDefaultLabel(INFO_CTRL_PANEL_NO_BASE_DNS_FOUND_LABEL.get()); 136 add(lNoBaseDNsFound, gbc); 137 lNoBaseDNsFound.setVisible(false); 138 139 lIndexes = Utilities.createPrimaryLabel(INFO_CTRL_PANEL_INDEXES_LABEL.get()); 140 gbc.insets.top = 10; 141 gbc.insets.left = 0; 142 gbc.gridy++; 143 gbc.gridx = 0; 144 gbc.gridwidth = 1; 145 gbc.anchor = GridBagConstraints.NORTHWEST; 146 add(lIndexes, gbc); 147 148 addRemove = new AddRemovePanel<>(AbstractIndexDescriptor.class); 149 addRemove.getAvailableLabel().setText(INFO_CTRL_PANEL_AVAILABLE_INDEXES_LABEL.get().toString()); 150 addRemove.getSelectedLabel().setText(INFO_CTRL_PANEL_SELECTED_INDEXES_LABEL.get().toString()); 151 152 gbc.gridx = 1; 153 gbc.weightx = 1.0; 154 gbc.weighty = 0.0; 155 gbc.gridwidth = 1; 156 gbc.insets.top = 10; 157 gbc.insets.left = 10; 158 gbc.fill = GridBagConstraints.BOTH; 159 add(addRemove, gbc); 160 161 gbc.gridy++; 162 gbc.insets.top = 3; 163 JLabel explanation = Utilities.createInlineHelpLabel(INFO_CTRL_PANEL_REQUIRES_REBUILD_LEGEND.get()); 164 add(explanation, gbc); 165 166 addBottomGlue(gbc); 167 } 168 169 @Override 170 public void setInfo(final ControlPanelInfo info) 171 { 172 super.setInfo(info); 173 ListCellRenderer indexCellRenderer = new IndexCellRenderer(addRemove.getAvailableList(), info); 174 addRemove.getAvailableList().setCellRenderer(indexCellRenderer); 175 addRemove.getSelectedList().setCellRenderer(indexCellRenderer); 176 info.addIndexModifiedListener(this); 177 } 178 179 @Override 180 public LocalizableMessage getTitle() 181 { 182 return INFO_CTRL_PANEL_REBUILD_INDEXES_TITLE.get(); 183 } 184 185 @Override 186 public Component getPreferredFocusComponent() 187 { 188 return baseDNs; 189 } 190 191 @Override 192 public void configurationChanged(final ConfigurationChangeEvent ev) 193 { 194 refreshContents(ev.getNewDescriptor()); 195 } 196 197 /** 198 * Refresh the contents of the panel with the provided server descriptor. 199 * 200 * @param desc 201 * the server descriptor. 202 */ 203 private void refreshContents(final ServerDescriptor desc) 204 { 205 super.updateIndexMap(desc, hmIndexes); 206 filterIndexes(hmIndexes); 207 208 updateBaseDNComboBoxModel((DefaultComboBoxModel) baseDNs.getModel(), desc); 209 210 if (!allDisabled(desc.getBackends())) 211 { 212 updateErrorPaneAndOKButtonIfAuthRequired(desc, 213 isLocal() ? INFO_CTRL_PANEL_AUTHENTICATION_REQUIRED_FOR_DISABLE_BACKEND.get() 214 : INFO_CTRL_PANEL_CANNOT_CONNECT_TO_REMOTE_DETAILS.get(desc.getHostname())); 215 } 216 SwingUtilities.invokeLater(new Runnable() 217 { 218 @Override 219 public void run() 220 { 221 ViewPositions pos; 222 JScrollPane scroll = Utilities.getContainingScroll(RebuildIndexPanel.this); 223 if (scroll != null) 224 { 225 pos = Utilities.getViewPositions(scroll); 226 } 227 else 228 { 229 pos = Utilities.getViewPositions(RebuildIndexPanel.this); 230 } 231 232 boolean comboVisible = baseDNs.getModel().getSize() > 0; 233 baseDNs.setVisible(comboVisible); 234 lNoBaseDNsFound.setVisible(!comboVisible); 235 addRemove.getAvailableList().repaint(); 236 addRemove.getSelectedList().repaint(); 237 238 Utilities.updateViewPositions(pos); 239 if (!desc.isLocal()) 240 { 241 displayErrorMessage(INFO_CTRL_PANEL_SERVER_REMOTE_SUMMARY.get(), 242 INFO_CTRL_PANEL_SERVER_MUST_BE_LOCAL_REBUILD_INDEX_SUMMARY.get()); 243 setEnabledOK(false); 244 } 245 else 246 { 247 displayMainPanel(); 248 setEnabledOK(true); 249 } 250 } 251 }); 252 } 253 254 private boolean allDisabled(Set<BackendDescriptor> backends) 255 { 256 for (BackendDescriptor backend : backends) 257 { 258 if (displayBackend(backend) && backend.isEnabled()) 259 { 260 return false; 261 } 262 } 263 return true; 264 } 265 266 @Override 267 public void cancelClicked() 268 { 269 setPrimaryValid(lBaseDN); 270 setSecondaryValid(addRemove.getSelectedLabel()); 271 super.cancelClicked(); 272 } 273 274 @Override 275 public void okClicked() 276 { 277 setPrimaryValid(lBaseDN); 278 setSecondaryValid(addRemove.getSelectedLabel()); 279 280 final Set<LocalizableMessage> errors = new LinkedHashSet<>(); 281 String baseDN = getSelectedBaseDN(); 282 283 if (baseDN == null) 284 { 285 setPrimaryInvalid(lBaseDN); 286 if (baseDNs.getItemCount() == 0) 287 { 288 errors.add(ERR_CTRL_PANEL_NO_BASE_DNS_DEFINED_LABEL.get()); 289 } 290 else 291 { 292 errors.add(ERR_CTRL_PANEL_MUST_SELECT_BASE_DN.get()); 293 } 294 } 295 296 SortableListModel<AbstractIndexDescriptor> model = addRemove.getSelectedListModel(); 297 if (model.getSize() == 0) 298 { 299 setSecondaryInvalid(addRemove.getSelectedLabel()); 300 errors.add(ERR_CTRL_PANEL_MUST_SELECT_INDEX_TO_REBUILD.get()); 301 } 302 303 if (errors.isEmpty()) 304 { 305 ProgressDialog progressDialog = 306 new ProgressDialog(Utilities.createFrame(), Utilities.getParentDialog(this), getTitle(), getInfo()); 307 Set<String> baseDNs = new HashSet<>(); 308 baseDNs.add(getSelectedBaseDN()); 309 RebuildIndexTask newTask = 310 new RebuildIndexTask(getInfo(), progressDialog, baseDNs, addRemove.getSelectedListModel().getData()); 311 for (Task task : getInfo().getTasks()) 312 { 313 task.canLaunch(newTask, errors); 314 } 315 boolean confirmed = true; 316 317 if (errors.isEmpty() && isServerRunning()) 318 { 319 String backendName = newTask.getBackends().iterator().next(); 320 confirmed = 321 displayConfirmationDialog(INFO_CTRL_PANEL_CONFIRMATION_REQUIRED_SUMMARY.get(), 322 INFO_CTRL_PANEL_CONFIRM_REBUILD_INDEX_DETAILS.get(backendName)); 323 } 324 if (errors.isEmpty() && confirmed) 325 { 326 launchOperation(newTask, INFO_CTRL_PANEL_REBUILDING_INDEXES_SUMMARY.get(baseDN), 327 INFO_CTRL_PANEL_REBUILDING_INDEXES_SUCCESSFUL_SUMMARY.get(), 328 INFO_CTRL_PANEL_REBUILDING_INDEXES_SUCCESSFUL_DETAILS.get(), 329 ERR_CTRL_PANEL_REBUILDING_INDEXES_ERROR_SUMMARY.get(), null, 330 ERR_CTRL_PANEL_REBUILDING_INDEXES_ERROR_DETAILS, progressDialog); 331 progressDialog.setVisible(true); 332 Utilities.getParentDialog(this).setVisible(false); 333 } 334 } 335 if (!errors.isEmpty()) 336 { 337 displayErrorDialog(errors); 338 } 339 } 340 341 @Override 342 protected boolean displayBackend(final BackendDescriptor backend) 343 { 344 return !backend.isConfigBackend() && backend.getType() == BackendDescriptor.Type.PLUGGABLE; 345 } 346 347 private String getSelectedBaseDN() 348 { 349 CategorizedComboBoxElement o = (CategorizedComboBoxElement) baseDNs.getSelectedItem(); 350 return o != null ? (String) o.getValue() : null; 351 } 352 353 private void filterIndexes(final Map<String, SortedSet<AbstractIndexDescriptor>> hmIndexes) 354 { 355 // Remove the indexes that are not to be added. 356 for (SortedSet<AbstractIndexDescriptor> indexes : hmIndexes.values()) 357 { 358 for (Iterator<AbstractIndexDescriptor> it = indexes.iterator(); it.hasNext();) 359 { 360 if (!mustBeDisplayed(it.next())) 361 { 362 it.remove(); 363 } 364 } 365 } 366 } 367 368 private boolean mustBeDisplayed(final AbstractIndexDescriptor index) 369 { 370 if (index instanceof IndexDescriptor) 371 { 372 for (String name : RebuildIndexTask.INDEXES_NOT_TO_SPECIFY) 373 { 374 if (name.equalsIgnoreCase(index.getName())) 375 { 376 return false; 377 } 378 } 379 } 380 return true; 381 } 382}