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 010 * trunk/opends/resource/legal-notices/OpenDS.LICENSE 011 * or https://OpenDS.dev.java.net/OpenDS.LICENSE. 012 * See the License for the specific language governing permissions 013 * and limitations under the License. 014 * 015 * When distributing Covered Code, include this CDDL HEADER in each 016 * file and include the License file at 017 * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, 018 * add the following below this CDDL HEADER, with the fields enclosed 019 * by brackets "[]" replaced with your own identifying information: 020 * Portions Copyright [yyyy] [name of copyright owner] 021 * 022 * CDDL HEADER END 023 * 024 * 025 * Copyright 2006-2008 Sun Microsystems, Inc. 026 */ 027 package org.opends.server.tools; 028 029 030 031 import org.opends.server.api.Backend; 032 import org.opends.server.api.ErrorLogPublisher; 033 import org.opends.server.api.DebugLogPublisher; 034 import org.opends.server.backends.jeb.BackendImpl; 035 import org.opends.server.backends.jeb.VerifyConfig; 036 import org.opends.server.config.ConfigException; 037 import org.opends.server.core.CoreConfigManager; 038 import org.opends.server.core.DirectoryServer; 039 import org.opends.server.core.LockFileManager; 040 import org.opends.server.extensions.ConfigFileHandler; 041 import org.opends.server.loggers.TextWriter; 042 import org.opends.server.loggers.ErrorLogger; 043 import org.opends.server.loggers.TextErrorLogPublisher; 044 import org.opends.server.loggers.debug.TextDebugLogPublisher; 045 import org.opends.server.loggers.debug.DebugLogger; 046 import org.opends.server.types.DirectoryException; 047 import org.opends.server.types.DN; 048 import org.opends.server.types.InitializationException; 049 import org.opends.server.types.NullOutputStream; 050 import org.opends.server.util.args.ArgumentException; 051 import org.opends.server.util.args.ArgumentParser; 052 import org.opends.server.util.args.BooleanArgument; 053 import org.opends.server.util.args.StringArgument; 054 055 import java.io.OutputStream; 056 import java.io.PrintStream; 057 import java.util.ArrayList; 058 import java.util.List; 059 060 import static org.opends.server.loggers.ErrorLogger.*; 061 import static org.opends.messages.ToolMessages.*; 062 import org.opends.messages.Message; 063 064 import static org.opends.server.util.ServerConstants.*; 065 import static org.opends.server.util.StaticUtils.*; 066 import static org.opends.server.tools.ToolConstants.*; 067 import org.opends.server.admin.std.server.BackendCfg; 068 069 070 /** 071 * This program provides a utility to verify the contents of the indexes 072 * of a Directory Server backend. This will be a process that is 073 * intended to run separate from Directory Server and not internally within the 074 * server process (e.g., via the tasks interface). 075 */ 076 public class VerifyIndex 077 { 078 /** 079 * Processes the command-line arguments and invokes the verify process. 080 * 081 * @param args The command-line arguments provided to this program. 082 */ 083 public static void main(String[] args) 084 { 085 int retCode = mainVerifyIndex(args, true, System.out, System.err); 086 087 if(retCode != 0) 088 { 089 System.exit(filterExitCode(retCode)); 090 } 091 } 092 093 /** 094 * Processes the command-line arguments and invokes the verify process. 095 * 096 * @param args The command-line arguments provided to this 097 * program. 098 * @param initializeServer Indicates whether to initialize the server. 099 * @param outStream The output stream to use for standard output, or 100 * {@code null} if standard output is not needed. 101 * @param errStream The output stream to use for standard error, or 102 * {@code null} if standard error is not needed. 103 * 104 * @return The error code. 105 */ 106 public static int mainVerifyIndex(String[] args, boolean initializeServer, 107 OutputStream outStream, 108 OutputStream errStream) 109 { 110 PrintStream out; 111 if (outStream == null) 112 { 113 out = NullOutputStream.printStream(); 114 } 115 else 116 { 117 out = new PrintStream(outStream); 118 } 119 120 PrintStream err; 121 if (errStream == null) 122 { 123 err = NullOutputStream.printStream(); 124 } 125 else 126 { 127 err = new PrintStream(errStream); 128 } 129 130 // Define the command-line arguments that may be used with this program. 131 StringArgument configClass = null; 132 StringArgument configFile = null; 133 StringArgument baseDNString = null; 134 StringArgument indexList = null; 135 BooleanArgument cleanMode = null; 136 BooleanArgument countErrors = null; 137 BooleanArgument displayUsage = null; 138 139 140 // Create the command-line argument parser for use with this program. 141 Message toolDescription = INFO_VERIFYINDEX_TOOL_DESCRIPTION.get(); 142 ArgumentParser argParser = 143 new ArgumentParser("org.opends.server.tools.VerifyIndex", 144 toolDescription, false); 145 146 147 // Initialize all the command-line argument types and register them with the 148 // parser. 149 try 150 { 151 configClass = 152 new StringArgument("configclass", OPTION_SHORT_CONFIG_CLASS, 153 OPTION_LONG_CONFIG_CLASS, true, false, 154 true, INFO_CONFIGCLASS_PLACEHOLDER.get(), 155 ConfigFileHandler.class.getName(), null, 156 INFO_DESCRIPTION_CONFIG_CLASS.get()); 157 configClass.setHidden(true); 158 argParser.addArgument(configClass); 159 160 161 configFile = 162 new StringArgument("configfile", 'f', "configFile", true, false, 163 true, INFO_CONFIGFILE_PLACEHOLDER.get(), null, 164 null, 165 INFO_DESCRIPTION_CONFIG_FILE.get()); 166 configFile.setHidden(true); 167 argParser.addArgument(configFile); 168 169 170 baseDNString = 171 new StringArgument("basedn", OPTION_SHORT_BASEDN, 172 OPTION_LONG_BASEDN, true, false, true, 173 INFO_BASEDN_PLACEHOLDER.get(), null, null, 174 INFO_VERIFYINDEX_DESCRIPTION_BASE_DN.get()); 175 argParser.addArgument(baseDNString); 176 177 178 indexList = 179 new StringArgument("index", 'i', "index", 180 false, true, true, 181 INFO_INDEX_PLACEHOLDER.get(), null, null, 182 INFO_VERIFYINDEX_DESCRIPTION_INDEX_NAME.get()); 183 argParser.addArgument(indexList); 184 185 cleanMode = 186 new BooleanArgument("clean", 'c', "clean", 187 INFO_VERIFYINDEX_DESCRIPTION_VERIFY_CLEAN.get()); 188 argParser.addArgument(cleanMode); 189 190 countErrors = 191 new BooleanArgument("counterrors", null, "countErrors", 192 INFO_VERIFYINDEX_DESCRIPTION_COUNT_ERRORS.get()); 193 argParser.addArgument(countErrors); 194 195 displayUsage = 196 new BooleanArgument("help", OPTION_SHORT_HELP, OPTION_LONG_HELP, 197 INFO_DESCRIPTION_USAGE.get()); 198 argParser.addArgument(displayUsage); 199 argParser.setUsageArgument(displayUsage); 200 } 201 catch (ArgumentException ae) 202 { 203 204 Message message = ERR_CANNOT_INITIALIZE_ARGS.get(ae.getMessage()); 205 206 err.println(wrapText(message, MAX_LINE_WIDTH)); 207 return 1; 208 } 209 210 211 // Parse the command-line arguments provided to this program. 212 try 213 { 214 argParser.parseArguments(args); 215 } 216 catch (ArgumentException ae) 217 { 218 219 Message message = ERR_ERROR_PARSING_ARGS.get(ae.getMessage()); 220 221 err.println(wrapText(message, MAX_LINE_WIDTH)); 222 err.println(argParser.getUsage()); 223 return 1; 224 } 225 226 227 // If we should just display usage or version information, 228 // then print it and exit. 229 if (argParser.usageOrVersionDisplayed()) 230 { 231 return 0; 232 } 233 234 235 236 237 // If no arguments were provided, then display usage information and exit. 238 int numArgs = args.length; 239 if (numArgs == 0) 240 { 241 out.println(argParser.getUsage()); 242 return 1; 243 } 244 245 246 if (cleanMode.isPresent() && indexList.getValues().size() != 1) 247 { 248 Message message = 249 ERR_VERIFYINDEX_VERIFY_CLEAN_REQUIRES_SINGLE_INDEX.get(); 250 251 err.println(wrapText(message, MAX_LINE_WIDTH)); 252 out.println(argParser.getUsage()); 253 return 1; 254 } 255 256 // Perform the initial bootstrap of the Directory Server and process the 257 // configuration. 258 DirectoryServer directoryServer = DirectoryServer.getInstance(); 259 260 if (initializeServer) 261 { 262 try 263 { 264 DirectoryServer.bootstrapClient(); 265 DirectoryServer.initializeJMX(); 266 } 267 catch (Exception e) 268 { 269 Message message = 270 ERR_SERVER_BOOTSTRAP_ERROR.get(getExceptionMessage(e)); 271 err.println(wrapText(message, MAX_LINE_WIDTH)); 272 return 1; 273 } 274 275 try 276 { 277 directoryServer.initializeConfiguration(configClass.getValue(), 278 configFile.getValue()); 279 } 280 catch (InitializationException ie) 281 { 282 Message message = 283 ERR_CANNOT_LOAD_CONFIG.get(ie.getMessage()); 284 err.println(wrapText(message, MAX_LINE_WIDTH)); 285 return 1; 286 } 287 catch (Exception e) 288 { 289 Message message = ERR_CANNOT_LOAD_CONFIG.get(getExceptionMessage(e)); 290 err.println(wrapText(message, MAX_LINE_WIDTH)); 291 return 1; 292 } 293 294 295 296 // Initialize the Directory Server schema elements. 297 try 298 { 299 directoryServer.initializeSchema(); 300 } 301 catch (ConfigException ce) 302 { 303 Message message = ERR_CANNOT_LOAD_SCHEMA.get(ce.getMessage()); 304 err.println(wrapText(message, MAX_LINE_WIDTH)); 305 return 1; 306 } 307 catch (InitializationException ie) 308 { 309 Message message = ERR_CANNOT_LOAD_SCHEMA.get(ie.getMessage()); 310 err.println(wrapText(message, MAX_LINE_WIDTH)); 311 return 1; 312 } 313 catch (Exception e) 314 { 315 Message message = ERR_CANNOT_LOAD_SCHEMA.get(getExceptionMessage(e)); 316 err.println(wrapText(message, MAX_LINE_WIDTH)); 317 return 1; 318 } 319 320 321 // Initialize the Directory Server core configuration. 322 try 323 { 324 CoreConfigManager coreConfigManager = new CoreConfigManager(); 325 coreConfigManager.initializeCoreConfig(); 326 } 327 catch (ConfigException ce) 328 { 329 Message message = 330 ERR_CANNOT_INITIALIZE_CORE_CONFIG.get(ce.getMessage()); 331 err.println(wrapText(message, MAX_LINE_WIDTH)); 332 return 1; 333 } 334 catch (InitializationException ie) 335 { 336 Message message = 337 ERR_CANNOT_INITIALIZE_CORE_CONFIG.get(ie.getMessage()); 338 err.println(wrapText(message, MAX_LINE_WIDTH)); 339 return 1; 340 } 341 catch (Exception e) 342 { 343 Message message = 344 ERR_CANNOT_INITIALIZE_CORE_CONFIG.get(getExceptionMessage(e)); 345 err.println(wrapText(message, MAX_LINE_WIDTH)); 346 return 1; 347 } 348 349 350 // Initialize the Directory Server crypto manager. 351 try 352 { 353 directoryServer.initializeCryptoManager(); 354 } 355 catch (ConfigException ce) 356 { 357 Message message = 358 ERR_CANNOT_INITIALIZE_CRYPTO_MANAGER.get(ce.getMessage()); 359 err.println(wrapText(message, MAX_LINE_WIDTH)); 360 return 1; 361 } 362 catch (InitializationException ie) 363 { 364 Message message = 365 ERR_CANNOT_INITIALIZE_CRYPTO_MANAGER.get(ie.getMessage()); 366 err.println(wrapText(message, MAX_LINE_WIDTH)); 367 return 1; 368 } 369 catch (Exception e) 370 { 371 Message message = 372 ERR_CANNOT_INITIALIZE_CRYPTO_MANAGER.get( 373 getExceptionMessage(e)); 374 err.println(wrapText(message, MAX_LINE_WIDTH)); 375 return 1; 376 } 377 378 379 try 380 { 381 ErrorLogPublisher errorLogPublisher = 382 TextErrorLogPublisher.getStartupTextErrorPublisher( 383 new TextWriter.STREAM(out)); 384 DebugLogPublisher debugLogPublisher = 385 TextDebugLogPublisher.getStartupTextDebugPublisher( 386 new TextWriter.STREAM(out)); 387 ErrorLogger.addErrorLogPublisher(errorLogPublisher); 388 DebugLogger.addDebugLogPublisher(debugLogPublisher); 389 } 390 catch(Exception e) 391 { 392 err.println("Error installing the custom error logger: " + 393 stackTraceToSingleLineString(e)); 394 } 395 } 396 397 398 // Decode the base DN provided by the user. 399 DN verifyBaseDN ; 400 try 401 { 402 verifyBaseDN = DN.decode(baseDNString.getValue()); 403 } 404 catch (DirectoryException de) 405 { 406 Message message = ERR_CANNOT_DECODE_BASE_DN.get( 407 baseDNString.getValue(), de.getMessageObject()); 408 logError(message); 409 return 1; 410 } 411 catch (Exception e) 412 { 413 Message message = ERR_CANNOT_DECODE_BASE_DN.get( 414 baseDNString.getValue(), getExceptionMessage(e)); 415 logError(message); 416 return 1; 417 } 418 419 420 // Get information about the backends defined in the server. Iterate 421 // through them, finding the one backend to be verified. 422 Backend backend = null; 423 424 ArrayList<Backend> backendList = new ArrayList<Backend>(); 425 ArrayList<BackendCfg> entryList = new ArrayList<BackendCfg>(); 426 ArrayList<List<DN>> dnList = new ArrayList<List<DN>>(); 427 BackendToolUtils.getBackends(backendList, entryList, dnList); 428 429 int numBackends = backendList.size(); 430 for (int i=0; i < numBackends; i++) 431 { 432 Backend b = backendList.get(i); 433 List<DN> baseDNs = dnList.get(i); 434 435 for (DN baseDN : baseDNs) 436 { 437 if (baseDN.equals(verifyBaseDN)) 438 { 439 if (backend == null) 440 { 441 backend = b; 442 } 443 else 444 { 445 Message message = 446 ERR_MULTIPLE_BACKENDS_FOR_BASE.get(baseDNString.getValue()); 447 logError(message); 448 return 1; 449 } 450 break; 451 } 452 } 453 } 454 455 if (backend == null) 456 { 457 Message message = ERR_NO_BACKENDS_FOR_BASE.get(baseDNString.getValue()); 458 logError(message); 459 return 1; 460 } 461 462 if (!(backend instanceof BackendImpl)) 463 { 464 Message message = ERR_BACKEND_NO_INDEXING_SUPPORT.get(); 465 logError(message); 466 return 1; 467 } 468 469 // Initialize the verify configuration. 470 VerifyConfig verifyConfig = new VerifyConfig(); 471 verifyConfig.setBaseDN(verifyBaseDN); 472 if (cleanMode.isPresent()) 473 { 474 for (String s : indexList.getValues()) 475 { 476 verifyConfig.addCleanIndex(s); 477 } 478 } 479 else 480 { 481 for (String s : indexList.getValues()) 482 { 483 verifyConfig.addCompleteIndex(s); 484 } 485 } 486 487 488 // Acquire a shared lock for the backend. 489 try 490 { 491 String lockFile = LockFileManager.getBackendLockFileName(backend); 492 StringBuilder failureReason = new StringBuilder(); 493 if (! LockFileManager.acquireSharedLock(lockFile, failureReason)) 494 { 495 Message message = ERR_VERIFYINDEX_CANNOT_LOCK_BACKEND.get( 496 backend.getBackendID(), String.valueOf(failureReason)); 497 logError(message); 498 return 1; 499 } 500 } 501 catch (Exception e) 502 { 503 Message message = ERR_VERIFYINDEX_CANNOT_LOCK_BACKEND.get( 504 backend.getBackendID(), getExceptionMessage(e)); 505 logError(message); 506 return 1; 507 } 508 509 510 // Launch the verify process. 511 int returnCode = 0 ; 512 try 513 { 514 BackendImpl jebBackend = (BackendImpl)backend; 515 long errorCount = jebBackend.verifyBackend(verifyConfig, null); 516 if (countErrors.isPresent()) 517 { 518 if (errorCount > Integer.MAX_VALUE) 519 { 520 returnCode = Integer.MAX_VALUE; 521 } 522 else 523 { 524 returnCode = (int) errorCount; 525 } 526 } 527 } 528 catch (Exception e) 529 { 530 Message message = ERR_VERIFYINDEX_ERROR_DURING_VERIFY.get( 531 stackTraceToSingleLineString(e)); 532 logError(message); 533 returnCode = 1; 534 } 535 536 537 // Release the shared lock on the backend. 538 try 539 { 540 String lockFile = LockFileManager.getBackendLockFileName(backend); 541 StringBuilder failureReason = new StringBuilder(); 542 if (! LockFileManager.releaseLock(lockFile, failureReason)) 543 { 544 Message message = WARN_VERIFYINDEX_CANNOT_UNLOCK_BACKEND.get( 545 backend.getBackendID(), String.valueOf(failureReason)); 546 logError(message); 547 } 548 } 549 catch (Exception e) 550 { 551 Message message = WARN_VERIFYINDEX_CANNOT_UNLOCK_BACKEND.get( 552 backend.getBackendID(), getExceptionMessage(e)); 553 logError(message); 554 } 555 556 return returnCode; 557 } 558 }