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