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 2006-2008 Sun Microsystems, Inc. 015 * Portions Copyright 2012-2016 ForgeRock AS. 016 */ 017package org.opends.server.tools; 018 019import static com.forgerock.opendj.cli.ArgumentConstants.*; 020import static com.forgerock.opendj.cli.CommonArguments.*; 021import static com.forgerock.opendj.cli.Utils.*; 022 023import static org.opends.messages.ToolMessages.*; 024import static org.opends.server.util.StaticUtils.*; 025 026import java.io.OutputStream; 027import java.io.PrintStream; 028import java.util.ArrayList; 029import java.util.List; 030 031import org.forgerock.i18n.LocalizableMessage; 032import org.forgerock.opendj.ldap.DN; 033import org.forgerock.opendj.server.config.server.BackendCfg; 034import org.opends.server.api.Backend; 035import org.opends.server.api.Backend.BackendOperation; 036import org.opends.server.backends.VerifyConfig; 037import org.opends.server.core.DirectoryServer; 038import org.opends.server.core.DirectoryServer.DirectoryServerVersionHandler; 039import org.opends.server.core.LockFileManager; 040import org.opends.server.loggers.JDKLogging; 041import org.opends.server.types.InitializationException; 042import org.opends.server.types.NullOutputStream; 043import org.opends.server.util.BuildVersion; 044 045import com.forgerock.opendj.cli.ArgumentException; 046import com.forgerock.opendj.cli.ArgumentParser; 047import com.forgerock.opendj.cli.BooleanArgument; 048import com.forgerock.opendj.cli.StringArgument; 049 050/** 051 * This program provides a utility to verify the contents of the indexes 052 * of a Directory Server backend. This will be a process that is 053 * intended to run separate from Directory Server and not internally within the 054 * server process (e.g., via the tasks interface). 055 */ 056public class VerifyIndex 057{ 058 059 /** 060 * Processes the command-line arguments and invokes the verify process. 061 * 062 * @param args The command-line arguments provided to this program. 063 */ 064 public static void main(String[] args) 065 { 066 int retCode = mainVerifyIndex(args, true, System.err); 067 if(retCode != 0) 068 { 069 System.exit(filterExitCode(retCode)); 070 } 071 } 072 073 /** 074 * Processes the command-line arguments and invokes the verify process. 075 * 076 * @param args The command-line arguments provided to this 077 * program. 078 * @param initializeServer Indicates whether to initialize the server. 079 * @param errStream The output stream to use for standard error, or 080 * {@code null} if standard error is not needed. 081 * @return The error code. 082 */ 083 public static int mainVerifyIndex(String[] args, boolean initializeServer, 084 OutputStream errStream) 085 { 086 PrintStream err = NullOutputStream.wrapOrNullStream(errStream); 087 JDKLogging.enableConsoleLoggingForOpenDJTool(); 088 089 // Define the command-line arguments that may be used with this program. 090 StringArgument configFile = null; 091 StringArgument baseDNString = null; 092 StringArgument indexList = null; 093 BooleanArgument cleanMode = null; 094 BooleanArgument countErrors = null; 095 BooleanArgument displayUsage = null; 096 097 098 // Create the command-line argument parser for use with this program. 099 LocalizableMessage toolDescription = INFO_VERIFYINDEX_TOOL_DESCRIPTION.get(); 100 ArgumentParser argParser = 101 new ArgumentParser("org.opends.server.tools.VerifyIndex", 102 toolDescription, false); 103 argParser.setShortToolDescription(REF_SHORT_DESC_VERIFY_INDEX.get()); 104 argParser.setVersionHandler(new DirectoryServerVersionHandler()); 105 106 // Initialize all the command-line argument types and register them with the parser. 107 try 108 { 109 configFile = 110 StringArgument.builder("configFile") 111 .shortIdentifier('f') 112 .description(INFO_DESCRIPTION_CONFIG_FILE.get()) 113 .hidden() 114 .required() 115 .valuePlaceholder(INFO_CONFIGFILE_PLACEHOLDER.get()) 116 .buildAndAddToParser(argParser); 117 baseDNString = 118 StringArgument.builder(OPTION_LONG_BASEDN) 119 .shortIdentifier(OPTION_SHORT_BASEDN) 120 .description(INFO_VERIFYINDEX_DESCRIPTION_BASE_DN.get()) 121 .required() 122 .valuePlaceholder(INFO_BASEDN_PLACEHOLDER.get()) 123 .buildAndAddToParser(argParser); 124 indexList = 125 StringArgument.builder("index") 126 .shortIdentifier('i') 127 .description(INFO_VERIFYINDEX_DESCRIPTION_INDEX_NAME.get()) 128 .multiValued() 129 .valuePlaceholder(INFO_INDEX_PLACEHOLDER.get()) 130 .buildAndAddToParser(argParser); 131 cleanMode = 132 BooleanArgument.builder("clean") 133 .shortIdentifier('c') 134 .description(INFO_VERIFYINDEX_DESCRIPTION_VERIFY_CLEAN.get()) 135 .buildAndAddToParser(argParser); 136 countErrors = 137 BooleanArgument.builder("countErrors") 138 .description(INFO_VERIFYINDEX_DESCRIPTION_COUNT_ERRORS.get()) 139 .buildAndAddToParser(argParser); 140 141 displayUsage = showUsageArgument(); 142 argParser.addArgument(displayUsage); 143 argParser.setUsageArgument(displayUsage); 144 } 145 catch (ArgumentException ae) 146 { 147 printWrappedText(err, ERR_CANNOT_INITIALIZE_ARGS.get(ae.getMessage())); 148 return 1; 149 } 150 151 152 // Parse the command-line arguments provided to this program. 153 try 154 { 155 argParser.parseArguments(args); 156 } 157 catch (ArgumentException ae) 158 { 159 argParser.displayMessageAndUsageReference(err, ERR_ERROR_PARSING_ARGS.get(ae.getMessage())); 160 return 1; 161 } 162 163 164 // If we should just display usage or version information, 165 // then print it and exit. 166 if (argParser.usageOrVersionDisplayed()) 167 { 168 return 0; 169 } 170 171 if (cleanMode.isPresent() && indexList.getValues().size() != 1) 172 { 173 argParser.displayMessageAndUsageReference(err, ERR_VERIFYINDEX_VERIFY_CLEAN_REQUIRES_SINGLE_INDEX.get()); 174 return 1; 175 } 176 177 // Checks the version - if upgrade required, the tool is unusable 178 try 179 { 180 BuildVersion.checkVersionMismatch(); 181 } 182 catch (InitializationException e) 183 { 184 printWrappedText(err, e.getMessage()); 185 return 1; 186 } 187 188 if (initializeServer) 189 { 190 try 191 { 192 new DirectoryServer.InitializationBuilder(configFile.getValue()) 193 .requireCryptoServices() 194 .initialize(); 195 } 196 catch (InitializationException ie) 197 { 198 printWrappedText(err, ERR_CANNOT_INITIALIZE_SERVER_COMPONENTS.get(ie.getLocalizedMessage())); 199 return 1; 200 } 201 } 202 203 // Decode the base DN provided by the user. 204 DN verifyBaseDN ; 205 try 206 { 207 verifyBaseDN = DN.valueOf(baseDNString.getValue()); 208 } 209 catch (Exception e) 210 { 211 printWrappedText(err, ERR_CANNOT_DECODE_BASE_DN.get(baseDNString.getValue(), getExceptionMessage(e))); 212 return 1; 213 } 214 215 216 // Get information about the backends defined in the server. Iterate 217 // through them, finding the one backend to be verified. 218 List<Backend<?>> backendList = new ArrayList<>(); 219 List<BackendCfg> entryList = new ArrayList<>(); 220 List<List<DN>> dnList = new ArrayList<>(); 221 BackendToolUtils.getBackends(backendList, entryList, dnList); 222 223 Backend<?> backend = null; 224 int numBackends = backendList.size(); 225 for (int i=0; i < numBackends; i++) 226 { 227 Backend<?> b = backendList.get(i); 228 List<DN> baseDNs = dnList.get(i); 229 230 if (baseDNs.contains(verifyBaseDN)) 231 { 232 if (backend != null) 233 { 234 printWrappedText(err, ERR_MULTIPLE_BACKENDS_FOR_BASE.get(baseDNString.getValue())); 235 return 1; 236 } 237 backend = b; 238 } 239 } 240 241 if (backend == null) 242 { 243 printWrappedText(err, ERR_NO_BACKENDS_FOR_BASE.get(baseDNString.getValue())); 244 return 1; 245 } 246 247 if (!backend.supports(BackendOperation.INDEXING)) 248 { 249 printWrappedText(err, ERR_BACKEND_NO_INDEXING_SUPPORT.get()); 250 return 1; 251 } 252 253 // Initialize the verify configuration. 254 VerifyConfig verifyConfig = new VerifyConfig(); 255 verifyConfig.setBaseDN(verifyBaseDN); 256 if (cleanMode.isPresent()) 257 { 258 for (String s : indexList.getValues()) 259 { 260 verifyConfig.addCleanIndex(s); 261 } 262 } 263 else 264 { 265 for (String s : indexList.getValues()) 266 { 267 verifyConfig.addCompleteIndex(s); 268 } 269 } 270 271 272 // Acquire a shared lock for the backend. 273 try 274 { 275 String lockFile = LockFileManager.getBackendLockFileName(backend); 276 StringBuilder failureReason = new StringBuilder(); 277 if (! LockFileManager.acquireSharedLock(lockFile, failureReason)) 278 { 279 printWrappedText(err, ERR_VERIFYINDEX_CANNOT_LOCK_BACKEND.get(backend.getBackendID(), failureReason)); 280 return 1; 281 } 282 } 283 catch (Exception e) 284 { 285 printWrappedText(err, ERR_VERIFYINDEX_CANNOT_LOCK_BACKEND.get(backend.getBackendID(), getExceptionMessage(e))); 286 return 1; 287 } 288 289 290 try 291 { 292 // Launch the verify process. 293 final long errorCount = backend.verifyBackend(verifyConfig); 294 if (countErrors.isPresent()) 295 { 296 if (errorCount > Integer.MAX_VALUE) 297 { 298 return Integer.MAX_VALUE; 299 } 300 return (int) errorCount; 301 } 302 return 0; 303 } 304 catch (InitializationException e) 305 { 306 printWrappedText(err, ERR_VERIFYINDEX_ERROR_DURING_VERIFY.get(e.getMessage())); 307 return 1; 308 } 309 catch (Exception e) 310 { 311 printWrappedText(err, ERR_VERIFYINDEX_ERROR_DURING_VERIFY.get(stackTraceToSingleLineString(e))); 312 return 1; 313 } 314 finally 315 { 316 // Release the shared lock on the backend. 317 try 318 { 319 String lockFile = LockFileManager.getBackendLockFileName(backend); 320 StringBuilder failureReason = new StringBuilder(); 321 if (! LockFileManager.releaseLock(lockFile, failureReason)) 322 { 323 printWrappedText(err, WARN_VERIFYINDEX_CANNOT_UNLOCK_BACKEND.get(backend.getBackendID(), failureReason)); 324 } 325 } 326 catch (Exception e) 327 { 328 printWrappedText(err, 329 WARN_VERIFYINDEX_CANNOT_UNLOCK_BACKEND.get(backend.getBackendID(), getExceptionMessage(e))); 330 } 331 } 332 } 333}