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.task; 028 029import static org.opends.guitools.controlpanel.util.Utilities.*; 030import static org.opends.messages.AdminToolMessages.*; 031 032import java.util.ArrayList; 033import java.util.Collection; 034import java.util.HashSet; 035import java.util.List; 036import java.util.Set; 037import java.util.TreeSet; 038 039import javax.naming.ldap.InitialLdapContext; 040import javax.swing.SwingUtilities; 041 042import org.forgerock.i18n.LocalizableMessage; 043import org.opends.guitools.controlpanel.datamodel.AbstractIndexDescriptor; 044import org.opends.guitools.controlpanel.datamodel.ControlPanelInfo; 045import org.opends.guitools.controlpanel.datamodel.VLVIndexDescriptor; 046import org.opends.guitools.controlpanel.ui.ColorAndFontConstants; 047import org.opends.guitools.controlpanel.ui.ProgressDialog; 048import org.opends.guitools.controlpanel.util.ConfigReader; 049import org.opends.guitools.controlpanel.util.Utilities; 050import org.opends.server.admin.client.ManagementContext; 051import org.opends.server.admin.client.ldap.JNDIDirContextAdaptor; 052import org.opends.server.admin.client.ldap.LDAPManagementContext; 053import org.opends.server.admin.std.client.BackendCfgClient; 054import org.opends.server.admin.std.client.LocalDBBackendCfgClient; 055import org.opends.server.admin.std.client.PluggableBackendCfgClient; 056import org.opends.server.admin.std.client.RootCfgClient; 057import org.opends.server.backends.jeb.RemoveOnceLocalDBBackendIsPluggable; 058import org.opends.server.core.DirectoryServer; 059import org.opends.server.types.DN; 060import org.opends.server.types.OpenDsException; 061 062/** 063 * The task that is launched when an index must be deleted. 064 */ 065public class DeleteIndexTask extends Task 066{ 067 private final Set<String> backendSet; 068 private final List<AbstractIndexDescriptor> indexesToDelete = new ArrayList<>(); 069 private final List<AbstractIndexDescriptor> deletedIndexes = new ArrayList<>(); 070 071 /** 072 * Constructor of the task. 073 * 074 * @param info 075 * the control panel information. 076 * @param dlg 077 * the progress dialog where the task progress will be displayed. 078 * @param indexesToDelete 079 * the indexes that must be deleted. 080 */ 081 public DeleteIndexTask(ControlPanelInfo info, ProgressDialog dlg, List<AbstractIndexDescriptor> indexesToDelete) 082 { 083 super(info, dlg); 084 backendSet = new HashSet<>(); 085 for (final AbstractIndexDescriptor index : indexesToDelete) 086 { 087 backendSet.add(index.getBackend().getBackendID()); 088 } 089 this.indexesToDelete.addAll(indexesToDelete); 090 } 091 092 @Override 093 public Type getType() 094 { 095 return Type.DELETE_INDEX; 096 } 097 098 @Override 099 public Set<String> getBackends() 100 { 101 return backendSet; 102 } 103 104 @Override 105 public LocalizableMessage getTaskDescription() 106 { 107 if (backendSet.size() == 1) 108 { 109 return INFO_CTRL_PANEL_DELETE_INDEX_TASK_DESCRIPTION.get(getStringFromCollection(backendSet, ", ")); 110 } 111 else 112 { 113 return INFO_CTRL_PANEL_DELETE_INDEX_IN_BACKENDS_TASK_DESCRIPTION.get(getStringFromCollection(backendSet, ", ")); 114 } 115 } 116 117 @Override 118 public boolean canLaunch(Task taskToBeLaunched, Collection<LocalizableMessage> incompatibilityReasons) 119 { 120 boolean canLaunch = true; 121 if (state == State.RUNNING && runningOnSameServer(taskToBeLaunched)) 122 { 123 // All the operations are incompatible if they apply to this 124 // backend for safety. This is a short operation so the limitation 125 // has not a lot of impact. 126 final Set<String> backends = new TreeSet<>(taskToBeLaunched.getBackends()); 127 backends.retainAll(getBackends()); 128 if (!backends.isEmpty()) 129 { 130 incompatibilityReasons.add(getIncompatibilityMessage(this, taskToBeLaunched)); 131 canLaunch = false; 132 } 133 } 134 return canLaunch; 135 } 136 137 /** 138 * Update the configuration in the server. 139 * 140 * @throws OpenDsException 141 * if an error occurs. 142 */ 143 private void updateConfiguration() throws OpenDsException 144 { 145 boolean configHandlerUpdated = false; 146 final int totalNumber = indexesToDelete.size(); 147 int numberDeleted = 0; 148 try 149 { 150 if (!isServerRunning()) 151 { 152 configHandlerUpdated = true; 153 getInfo().stopPooling(); 154 if (getInfo().mustDeregisterConfig()) 155 { 156 DirectoryServer.deregisterBaseDN(DN.valueOf("cn=config")); 157 } 158 DirectoryServer.getInstance().initializeConfiguration( 159 org.opends.server.extensions.ConfigFileHandler.class.getName(), ConfigReader.configFile); 160 getInfo().setMustDeregisterConfig(true); 161 } 162 boolean isFirst = true; 163 for (final AbstractIndexDescriptor index : indexesToDelete) 164 { 165 if (!isFirst) 166 { 167 SwingUtilities.invokeLater(new Runnable() 168 { 169 @Override 170 public void run() 171 { 172 getProgressDialog().appendProgressHtml("<br><br>"); 173 } 174 }); 175 } 176 isFirst = false; 177 if (isServerRunning()) 178 { 179 SwingUtilities.invokeLater(new Runnable() 180 { 181 @Override 182 public void run() 183 { 184 final List<String> args = getObfuscatedCommandLineArguments(getDSConfigCommandLineArguments(index)); 185 args.removeAll(getConfigCommandLineArguments()); 186 printEquivalentCommandLine(getConfigCommandLineName(index), args, 187 INFO_CTRL_PANEL_EQUIVALENT_CMD_TO_DELETE_INDEX.get()); 188 } 189 }); 190 } 191 SwingUtilities.invokeLater(new Runnable() 192 { 193 @Override 194 public void run() 195 { 196 if (isVLVIndex(index)) 197 { 198 getProgressDialog().appendProgressHtml( 199 Utilities.getProgressWithPoints(INFO_CTRL_PANEL_DELETING_VLV_INDEX.get(index.getName()), 200 ColorAndFontConstants.progressFont)); 201 } 202 else 203 { 204 getProgressDialog().appendProgressHtml( 205 Utilities.getProgressWithPoints(INFO_CTRL_PANEL_DELETING_INDEX.get(index.getName()), 206 ColorAndFontConstants.progressFont)); 207 } 208 } 209 }); 210 if (isServerRunning()) 211 { 212 deleteIndex(getInfo().getDirContext(), index); 213 } 214 else 215 { 216 deleteIndex(index); 217 } 218 numberDeleted++; 219 final int fNumberDeleted = numberDeleted; 220 SwingUtilities.invokeLater(new Runnable() 221 { 222 @Override 223 public void run() 224 { 225 getProgressDialog().getProgressBar().setIndeterminate(false); 226 getProgressDialog().getProgressBar().setValue((fNumberDeleted * 100) / totalNumber); 227 getProgressDialog().appendProgressHtml(Utilities.getProgressDone(ColorAndFontConstants.progressFont)); 228 } 229 }); 230 deletedIndexes.add(index); 231 } 232 } 233 finally 234 { 235 if (configHandlerUpdated) 236 { 237 DirectoryServer.getInstance().initializeConfiguration(ConfigReader.configClassName, ConfigReader.configFile); 238 getInfo().startPooling(); 239 } 240 } 241 } 242 243 /** 244 * Returns <CODE>true</CODE> if the index is a VLV index and 245 * <CODE>false</CODE> otherwise. 246 * 247 * @param index 248 * the index. 249 * @return <CODE>true</CODE> if the index is a VLV index and 250 * <CODE>false</CODE> otherwise. 251 */ 252 private boolean isVLVIndex(AbstractIndexDescriptor index) 253 { 254 return index instanceof VLVIndexDescriptor; 255 } 256 257 /** 258 * Deletes an index. The code assumes that the server is not running and that 259 * the configuration file can be edited. 260 * 261 * @param index 262 * the index to be deleted. 263 * @throws OpenDsException 264 * if an error occurs. 265 */ 266 private void deleteIndex(AbstractIndexDescriptor index) throws OpenDsException 267 { 268 final String backendId = Utilities.getRDNString("ds-cfg-backend-id", index.getBackend().getBackendID()); 269 String dn; 270 if (isVLVIndex(index)) 271 { 272 dn = getRDNString("ds-cfg-name", index.getName()) + ",cn=VLV Index," + backendId + ",cn=Backends,cn=config"; 273 } 274 else 275 { 276 dn = getRDNString("ds-cfg-attribute", index.getName()) + ",cn=Index," + backendId + ",cn=Backends,cn=config"; 277 } 278 DirectoryServer.getConfigHandler().deleteEntry(DN.valueOf(dn), null); 279 } 280 281 /** 282 * Deletes an index. The code assumes that the server is running and that the 283 * provided connection is active. 284 * 285 * @param index 286 * the index to be deleted. 287 * @param ctx 288 * the connection to the server. 289 * @throws OpenDsException 290 * if an error occurs. 291 */ 292 private void deleteIndex(final InitialLdapContext ctx, final AbstractIndexDescriptor index) throws OpenDsException 293 { 294 final ManagementContext mCtx = LDAPManagementContext.createFromContext(JNDIDirContextAdaptor.adapt(ctx)); 295 final RootCfgClient root = mCtx.getRootConfiguration(); 296 final BackendCfgClient backend = root.getBackend(index.getBackend().getBackendID()); 297 298 if (backend instanceof LocalDBBackendCfgClient) 299 { 300 removeLocalDBIndex((LocalDBBackendCfgClient) backend, index); 301 } 302 else 303 { 304 removeBackendIndex((PluggableBackendCfgClient) backend, index); 305 } 306 backend.commit(); 307 } 308 309 private void removeBackendIndex(final PluggableBackendCfgClient backend, final AbstractIndexDescriptor index) 310 throws OpenDsException 311 { 312 final String indexName = index.getName(); 313 if (isVLVIndex(index)) 314 { 315 backend.removeBackendVLVIndex(indexName); 316 } 317 else 318 { 319 backend.removeBackendIndex(indexName); 320 } 321 } 322 323 @RemoveOnceLocalDBBackendIsPluggable 324 private void removeLocalDBIndex(final LocalDBBackendCfgClient backend, final AbstractIndexDescriptor index) 325 throws OpenDsException 326 { 327 final String indexName = index.getName(); 328 if (isVLVIndex(index)) 329 { 330 backend.removeLocalDBVLVIndex(indexName); 331 } 332 else 333 { 334 backend.removeLocalDBIndex(indexName); 335 } 336 } 337 338 @Override 339 protected String getCommandLinePath() 340 { 341 return null; 342 } 343 344 @Override 345 protected ArrayList<String> getCommandLineArguments() 346 { 347 return new ArrayList<>(); 348 } 349 350 /** 351 * Returns the path of the command line to be used to delete the specified 352 * index. 353 * 354 * @param index 355 * the index to be deleted. 356 * @return the path of the command line to be used to delete the specified 357 * index. 358 */ 359 private String getConfigCommandLineName(AbstractIndexDescriptor index) 360 { 361 if (isServerRunning()) 362 { 363 return getCommandLinePath("dsconfig"); 364 } 365 else 366 { 367 return null; 368 } 369 } 370 371 @Override 372 public void runTask() 373 { 374 state = State.RUNNING; 375 lastException = null; 376 377 try 378 { 379 updateConfiguration(); 380 state = State.FINISHED_SUCCESSFULLY; 381 } 382 catch (final Throwable t) 383 { 384 lastException = t; 385 state = State.FINISHED_WITH_ERROR; 386 } 387 finally 388 { 389 for (final AbstractIndexDescriptor index : deletedIndexes) 390 { 391 getInfo().unregisterModifiedIndex(index); 392 } 393 } 394 } 395 396 /** 397 * Return the dsconfig arguments required to delete an index. 398 * 399 * @param index 400 * the index to be deleted. 401 * @return the dsconfig arguments required to delete an index. 402 */ 403 private List<String> getDSConfigCommandLineArguments(AbstractIndexDescriptor index) 404 { 405 final List<String> args = new ArrayList<>(); 406 if (isVLVIndex(index)) 407 { 408 args.add("delete-local-db-vlv-index"); 409 } 410 else 411 { 412 args.add("delete-local-db-index"); 413 } 414 args.add("--backend-name"); 415 args.add(index.getBackend().getBackendID()); 416 417 args.add("--index-name"); 418 args.add(index.getName()); 419 420 args.addAll(getConnectionCommandLineArguments()); 421 args.add("--no-prompt"); 422 args.add(getNoPropertiesFileArgument()); 423 424 return args; 425 } 426}