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 import org.opends.server.loggers.debug.DebugTracer;
030 import static org.opends.server.loggers.debug.DebugLogger.getTracer;
031 import static org.opends.server.loggers.debug.DebugLogger.debugEnabled;
032 import static org.opends.server.util.StaticUtils.*;
033 import org.opends.server.util.args.*;
034 import static org.opends.server.util.ServerConstants.MAX_LINE_WIDTH;
035 import org.opends.server.util.StaticUtils;
036 import org.opends.server.util.table.TableBuilder;
037 import org.opends.server.util.table.TextTablePrinter;
038 import org.opends.server.types.*;
039 import static org.opends.messages.ToolMessages.*;
040 import org.opends.messages.Message;
041 import static org.opends.server.tools.ToolConstants.OPTION_SHORT_CONFIG_CLASS;
042 import static org.opends.server.tools.ToolConstants.OPTION_LONG_CONFIG_CLASS;
043 import static org.opends.server.tools.ToolConstants.OPTION_SHORT_HELP;
044 import static org.opends.server.tools.ToolConstants.OPTION_LONG_HELP;
045 import org.opends.server.extensions.ConfigFileHandler;
046 import org.opends.server.core.DirectoryServer;
047 import org.opends.server.core.LockFileManager;
048 import org.opends.server.config.ConfigException;
049 import org.opends.server.api.Backend;
050 import org.opends.server.admin.std.server.BackendCfg;
051 import org.opends.server.admin.std.server.LocalDBBackendCfg;
052 import org.opends.server.backends.jeb.*;
053 import org.opends.server.protocols.asn1.ASN1OctetString;
054 import org.opends.server.protocols.asn1.ASN1Element;
055
056 import java.io.*;
057 import java.util.*;
058
059 import com.sleepycat.je.*;
060
061 /**
062 * This program provides a utility that may be used to debug a JE backend. This
063 * tool provides the ability list various containers in the backend as well as
064 * dump the contents of database containers. This will be
065 * a process that is intended to run separate from Directory Server and not
066 * internally within the server process (e.g., via the tasks interface).
067 */
068 public class DBTest
069 {
070 /**
071 * The tracer object for the debug logger.
072 */
073 private static final DebugTracer TRACER = getTracer();
074
075 // The error stream which this application should use.
076 private final PrintStream err;
077
078 // The output stream which this application should use.
079 private final PrintStream out;
080
081 // Flag indicating whether or not the global arguments have
082 // already been initialized.
083 private boolean globalArgumentsInitialized = false;
084
085 // The command-line argument parser.
086 private final SubCommandArgumentParser parser;
087
088 // The argument which should be used to request usage information.
089 private BooleanArgument showUsageArgument;
090
091 // The argument which should be used to specify the config class.
092 private StringArgument configClass;
093
094 // THe argument which should be used to specify the config file.
095 private StringArgument configFile;
096
097 // Flag indicating whether or not the sub-commands have
098 // already been initialized.
099 private boolean subCommandsInitialized = false;
100
101
102
103 /**
104 * Provides the command-line arguments to the main application for
105 * processing.
106 *
107 * @param args
108 * The set of command-line arguments provided to this
109 * program.
110 */
111 public static void main(String[] args) {
112 int exitCode = main(args, true, System.out, System.err);
113 if (exitCode != 0) {
114 System.exit(filterExitCode(exitCode));
115 }
116 }
117
118
119 /**
120 * Provides the command-line arguments to the main application for
121 * processing and returns the exit code as an integer.
122 *
123 * @param args
124 * The set of command-line arguments provided to this
125 * program.
126 * @param initializeServer
127 * Indicates whether to perform basic initialization (which
128 * should not be done if the tool is running in the same
129 * JVM as the server).
130 * @param outStream
131 * The output stream for standard output.
132 * @param errStream
133 * The output stream for standard error.
134 * @return Zero to indicate that the program completed successfully,
135 * or non-zero to indicate that an error occurred.
136 */
137 public static int main(String[] args, boolean initializeServer,
138 OutputStream outStream, OutputStream errStream) {
139 DBTest app = new DBTest(outStream, errStream);
140
141 // Run the application.
142 return app.run(args, initializeServer);
143 }
144
145 /**
146 * Creates a new dsconfig application instance.
147 *
148 * @param out
149 * The application output stream.
150 * @param err
151 * The application error stream.
152 */
153 public DBTest(OutputStream out, OutputStream err)
154 {
155 if (out != null) {
156 this.out = new PrintStream(out);
157 } else {
158 this.out = NullOutputStream.printStream();
159 }
160
161 if (err != null) {
162 this.err = new PrintStream(err);
163 } else {
164 this.err = NullOutputStream.printStream();
165 }
166
167 Message toolDescription = INFO_DESCRIPTION_DBTEST_TOOL.get();
168 this.parser = new SubCommandArgumentParser(this.getClass().getName(),
169 toolDescription, false);
170 }
171
172 // Displays the provided message followed by a help usage reference.
173 private void displayMessageAndUsageReference(Message message) {
174 printMessage(message);
175 printMessage(Message.EMPTY);
176 printMessage(parser.getHelpUsageReference());
177 }
178
179
180
181 /**
182 * Registers the global arguments with the argument parser.
183 *
184 * @throws ArgumentException
185 * If a global argument could not be registered.
186 */
187 private void initializeGlobalArguments() throws ArgumentException {
188 if (!globalArgumentsInitialized) {
189 configClass =
190 new StringArgument("configclass", OPTION_SHORT_CONFIG_CLASS,
191 OPTION_LONG_CONFIG_CLASS, true, false,
192 true, INFO_CONFIGCLASS_PLACEHOLDER.get(),
193 ConfigFileHandler.class.getName(), null,
194 INFO_DESCRIPTION_CONFIG_CLASS.get());
195 configClass.setHidden(true);
196
197 configFile =
198 new StringArgument("configfile", 'f', "configFile", true, false,
199 true, INFO_CONFIGFILE_PLACEHOLDER.get(), null,
200 null,
201 INFO_DESCRIPTION_CONFIG_FILE.get());
202 configFile.setHidden(true);
203
204
205 showUsageArgument =
206 new BooleanArgument("help", OPTION_SHORT_HELP, OPTION_LONG_HELP,
207 INFO_DESCRIPTION_USAGE.get());
208
209 // Register the global arguments.
210 parser.addGlobalArgument(showUsageArgument);
211 parser.setUsageArgument(showUsageArgument, out);
212 parser.addGlobalArgument(configClass);
213 parser.addGlobalArgument(configFile);
214
215 globalArgumentsInitialized = true;
216 }
217 }
218
219
220
221 /**
222 * Registers the sub-commands with the argument parser.
223 *
224 * @throws ArgumentException
225 * If a sub-command could not be created.
226 */
227 private void initializeSubCommands() throws ArgumentException {
228 if (!subCommandsInitialized) {
229 StringArgument backendID;
230 StringArgument baseDN;
231 StringArgument databaseName;
232 BooleanArgument skipDecode;
233 StringArgument maxKeyValue;
234 StringArgument minKeyValue;
235 IntegerArgument maxDataSize;
236 IntegerArgument minDataSize;
237 SubCommand sub;
238
239 sub = new SubCommand(parser, "list-root-containers",
240 INFO_DESCRIPTION_DBTEST_SUBCMD_LIST_ROOT_CONTAINERS.get());
241
242
243 sub = new SubCommand(parser, "list-entry-containers",
244 INFO_DESCRIPTION_DBTEST_SUBCMD_LIST_ENTRY_CONTAINERS.get());
245 backendID =
246 new StringArgument("backendid", 'n', "backendID", true, false, true,
247 INFO_BACKENDNAME_PLACEHOLDER.get(), null, null,
248 INFO_DESCRIPTION_DBTEST_BACKEND_ID.get());
249 sub.addArgument(backendID);
250
251
252 sub = new SubCommand(parser, "list-database-containers",
253 INFO_DESCRIPTION_DBTEST_SUBCMD_LIST_DATABASE_CONTAINERS.get());
254 backendID =
255 new StringArgument("backendid", 'n', "backendID", true, false, true,
256 INFO_BACKENDNAME_PLACEHOLDER.get(), null, null,
257 INFO_DESCRIPTION_DBTEST_BACKEND_ID.get());
258 sub.addArgument(backendID);
259 baseDN =
260 new StringArgument("basedn", 'b', "baseDN", false,
261 false, true, INFO_BASEDN_PLACEHOLDER.get(), null,
262 null,
263 INFO_DESCRIPTION_DBTEST_BASE_DN.get());
264 sub.addArgument(baseDN);
265
266
267 sub = new SubCommand(parser, "dump-database-container",
268 INFO_DESCRIPTION_DBTEST_SUBCMD_DUMP_DATABASE_CONTAINER.get());
269 backendID =
270 new StringArgument("backendid", 'n', "backendID", true, false, true,
271 INFO_BACKENDNAME_PLACEHOLDER.get(), null, null,
272 INFO_DESCRIPTION_DBTEST_BACKEND_ID.get());
273 sub.addArgument(backendID);
274 baseDN =
275 new StringArgument("basedn", 'b', "baseDN", true,
276 false, true, INFO_BASEDN_PLACEHOLDER.get(), null,
277 null,
278 INFO_DESCRIPTION_DBTEST_BASE_DN.get());
279 sub.addArgument(baseDN);
280 databaseName =
281 new StringArgument("databasename", 'd', "databaseName", true,
282 false, true, INFO_DATABASE_NAME_PLACEHOLDER.get(),
283 null, null,
284 INFO_DESCRIPTION_DBTEST_DATABASE_NAME.get());
285 sub.addArgument(databaseName);
286 skipDecode =
287 new BooleanArgument("skipdecode", 'p', "skipDecode",
288 INFO_DESCRIPTION_DBTEST_SKIP_DECODE.get());
289 sub.addArgument(skipDecode);
290 maxKeyValue = new StringArgument("maxkeyvalue", 'K', "maxKeyValue", false,
291 false, true,
292 INFO_MAX_KEY_VALUE_PLACEHOLDER.get(),
293 null, null,
294 INFO_DESCRIPTION_DBTEST_MAX_KEY_VALUE.get());
295 sub.addArgument(maxKeyValue);
296 minKeyValue = new StringArgument("minkeyvalue", 'k', "minKeyValue", false,
297 false, true,
298 INFO_MIN_KEY_VALUE_PLACEHOLDER.get(),
299 null,
300 null,
301 INFO_DESCRIPTION_DBTEST_MIN_KEY_VALUE.get());
302 sub.addArgument(minKeyValue);
303 maxDataSize = new IntegerArgument("maxdatasize", 'S', "maxDataSize",
304 false, false, true,
305 INFO_MAX_DATA_SIZE_PLACEHOLDER.get(),
306 -1,
307 null,
308 INFO_DESCRIPTION_DBTEST_MAX_DATA_SIZE.get());
309 sub.addArgument(maxDataSize);
310 minDataSize = new IntegerArgument("mindatasize", 's', "minDataSize",
311 false, false, true,
312 INFO_MIN_DATA_SIZE_PLACEHOLDER.get(),
313 -1,
314 null,
315 INFO_DESCRIPTION_DBTEST_MIN_DATA_SIZE.get());
316 sub.addArgument(minDataSize);
317
318
319 sub = new SubCommand(parser, "list-index-status",
320 INFO_DESCRIPTION_DBTEST_SUBCMD_LIST_INDEX_STATUS.get());
321 backendID =
322 new StringArgument("backendid", 'n', "backendID", true, false, true,
323 INFO_BACKENDNAME_PLACEHOLDER.get(), null, null,
324 INFO_DESCRIPTION_DBTEST_BACKEND_ID.get());
325 sub.addArgument(backendID);
326 baseDN =
327 new StringArgument("basedn", 'b', "baseDN", true,
328 true, true, INFO_BASEDN_PLACEHOLDER.get(), null,
329 null,
330 INFO_DESCRIPTION_DBTEST_BASE_DN.get());
331 sub.addArgument(baseDN);
332
333 subCommandsInitialized = true;
334 }
335 }
336
337
338 /**
339 * Parses the provided command-line arguments and makes the
340 * appropriate changes to the Directory Server configuration.
341 *
342 * @param args
343 * The command-line arguments provided to this program.
344 * @param initializeServer
345 * Indicates whether to perform basic initialization (which
346 * should not be done if the tool is running in the same
347 * JVM as the server).
348 * @return The exit code from the configuration processing. A
349 * nonzero value indicates that there was some kind of
350 * problem during the configuration processing.
351 */
352 private int run(String[] args, boolean initializeServer) {
353 // Register global arguments and sub-commands.
354 try {
355 initializeGlobalArguments();
356 initializeSubCommands();
357 } catch (ArgumentException e) {
358 Message message = ERR_CANNOT_INITIALIZE_ARGS.get(e.getMessage());
359 printMessage(message);
360 return 1;
361 }
362
363 // Parse the command-line arguments provided to this program.
364 try {
365 parser.parseArguments(args);
366 } catch (ArgumentException ae) {
367 Message message = ERR_ERROR_PARSING_ARGS.get(ae.getMessage());
368 displayMessageAndUsageReference(message);
369 return 1;
370 }
371
372 // If the usage/version argument was provided, then we don't need
373 // to do anything else.
374 if (parser.usageOrVersionDisplayed()) {
375 return 0;
376 }
377
378 // Only initialize the server when run as a standalone
379 // application.
380 if (initializeServer) {
381 // Perform the initial bootstrap of the Directory Server and process the
382 // configuration.
383 DirectoryServer directoryServer = DirectoryServer.getInstance();
384 try
385 {
386 directoryServer.bootstrapClient();
387 directoryServer.initializeJMX();
388 }
389 catch (Exception e)
390 {
391 Message message = ERR_SERVER_BOOTSTRAP_ERROR.get(
392 getExceptionMessage(e));
393 printMessage(message);
394 return 1;
395 }
396
397 try
398 {
399 directoryServer.initializeConfiguration(configClass.getValue(),
400 configFile.getValue());
401 }
402 catch (InitializationException ie)
403 {
404 Message message = ERR_CANNOT_LOAD_CONFIG.get(
405 ie.getMessage());
406 printMessage(message);
407 return 1;
408 }
409 catch (Exception e)
410 {
411 Message message = ERR_CANNOT_LOAD_CONFIG.get(
412 getExceptionMessage(e));
413 printMessage(message);
414 return 1;
415 }
416
417
418
419 // Initialize the Directory Server schema elements.
420 try
421 {
422 directoryServer.initializeSchema();
423 }
424 catch (ConfigException ce)
425 {
426 Message message = ERR_CANNOT_LOAD_SCHEMA.get(
427 ce.getMessage());
428 printMessage(message);
429 return 1;
430 }
431 catch (InitializationException ie)
432 {
433 Message message = ERR_CANNOT_LOAD_SCHEMA.get(
434 ie.getMessage());
435 printMessage(message);
436 return 1;
437 }
438 catch (Exception e)
439 {
440 Message message = ERR_CANNOT_LOAD_SCHEMA.get(
441 getExceptionMessage(e));
442 printMessage(message);
443 return 1;
444 }
445 }
446
447 // Make sure that we have a sub-command.
448 if (parser.getSubCommand() == null)
449 {
450 Message message = ERR_DBTEST_MISSING_SUBCOMMAND.get();
451 displayMessageAndUsageReference(message);
452 return 1;
453 }
454
455 // Retrieve the sub-command implementation and run it.
456 SubCommand subCommand = parser.getSubCommand();
457 try {
458 if(subCommand.getName().equals("list-root-containers"))
459 {
460 return listRootContainers();
461 }
462 else if(subCommand.getName().equals("list-entry-containers"))
463 {
464 return listEntryContainers(subCommand.getArgument("backendid"));
465 }
466 else if(subCommand.getName().equals("list-database-containers"))
467 {
468 return listDatabaseContainers(subCommand.getArgument("backendid"),
469 subCommand.getArgument("basedn"));
470 }
471 else if(subCommand.getName().equals("dump-database-container"))
472 {
473 return dumpDatabaseContainer(subCommand.getArgument("backendid"),
474 subCommand.getArgument("basedn"),
475 subCommand.getArgument("databasename"),
476 subCommand.getArgument("skipdecode"),
477 subCommand.getArgument("maxkeyvalue"),
478 subCommand.getArgument("minkeyvalue"),
479 subCommand.getArgument("maxdatasize"),
480 subCommand.getArgument("mindatasize"));
481 }
482 else if(subCommand.getName().equals("list-index-status"))
483 {
484 return listIndexStatus(subCommand.getArgument("backendid"),
485 subCommand.getArgument("basedn"));
486 }
487 {
488 return 0;
489 }
490 } catch (Exception e) {
491 if (debugEnabled()) {
492 TRACER.debugCaught(DebugLogLevel.ERROR, e);
493 }
494 printMessage(Message.raw(StaticUtils.stackTraceToString(e)));
495 return 1;
496 }
497 }
498
499 private int listRootContainers()
500 {
501 TreeMap<LocalDBBackendCfg, BackendImpl> jeBackends = getJEBackends();
502 int count = 0;
503
504 // Create a table of their properties.
505 TableBuilder builder = new TableBuilder();
506
507 builder.appendHeading(INFO_LABEL_DBTEST_BACKEND_ID.get());
508 builder.appendHeading(INFO_LABEL_DBTEST_DB_DIRECTORY.get());
509
510 for(Map.Entry<LocalDBBackendCfg, BackendImpl> backend :
511 jeBackends.entrySet())
512 {
513 builder.startRow();
514 builder.appendCell(backend.getValue().getBackendID());
515 builder.appendCell(backend.getKey().getDBDirectory());
516 count++;
517 }
518
519 TextTablePrinter printer = new TextTablePrinter(out);
520 builder.print(printer);
521 out.format("%nTotal: %d%n", count);
522
523 return 0;
524 }
525
526 private int listEntryContainers(Argument backendID)
527 {
528 TreeMap<LocalDBBackendCfg, BackendImpl> jeBackends = getJEBackends();
529 BackendImpl backend = null;
530
531 for(BackendImpl b : jeBackends.values())
532 {
533 if(b.getBackendID().equalsIgnoreCase(backendID.getValue()))
534 {
535 backend = b;
536 break;
537 }
538 }
539
540 if(backend == null)
541 {
542 printMessage(ERR_DBTEST_NO_BACKENDS_FOR_ID.get(backendID.getValue()));
543 return 1;
544 }
545
546 // Acquire an shared lock for the backend.
547 try
548 {
549 String lockFile = LockFileManager.getBackendLockFileName(backend);
550 StringBuilder failureReason = new StringBuilder();
551 if (! LockFileManager.acquireSharedLock(lockFile, failureReason))
552 {
553 Message message = ERR_DBTEST_CANNOT_LOCK_BACKEND.get(
554 backend.getBackendID(), String.valueOf(failureReason));
555 printMessage(message);
556 return 1;
557 }
558 }
559 catch (Exception e)
560 {
561 Message message = ERR_DBTEST_CANNOT_LOCK_BACKEND.get(
562 backend.getBackendID(), getExceptionMessage(e));
563 printMessage(message);
564 return 1;
565 }
566
567 RootContainer rc;
568 try
569 {
570 rc = backend.getReadOnlyRootContainer();
571 }
572 catch(Exception e)
573 {
574 printMessage(ERR_DBTEST_ERROR_INITIALIZING_BACKEND.get(
575 backend.getBackendID(),
576 StaticUtils.stackTraceToSingleLineString(e)));
577 return 1;
578 }
579
580 try
581 {
582 // Create a table of their properties.
583 TableBuilder builder = new TableBuilder();
584 int count = 0;
585
586 builder.appendHeading(INFO_LABEL_DBTEST_BASE_DN.get());
587 builder.appendHeading(INFO_LABEL_DBTEST_JE_DATABASE_PREFIX.get());
588 builder.appendHeading(INFO_LABEL_DBTEST_ENTRY_COUNT.get());
589
590 for(EntryContainer ec : rc.getEntryContainers())
591 {
592 builder.startRow();
593 builder.appendCell(ec.getBaseDN().toNormalizedString());
594 builder.appendCell(ec.getDatabasePrefix());
595 builder.appendCell(ec.getEntryCount());
596 count++;
597 }
598
599 TextTablePrinter printer = new TextTablePrinter(out);
600 builder.print(printer);
601 out.format("%nTotal: %d%n", count);
602
603 return 0;
604
605
606 }
607 catch(DatabaseException de)
608 {
609 printMessage(ERR_DBTEST_ERROR_READING_DATABASE.get(
610 StaticUtils.stackTraceToSingleLineString(de)));
611 return 1;
612 }
613 finally
614 {
615 try
616 {
617 // Close the root container
618 rc.close();
619 }
620 catch(DatabaseException de)
621 {
622 // Ignore.
623 }
624
625 // Release the shared lock on the backend.
626 try
627 {
628 String lockFile = LockFileManager.getBackendLockFileName(backend);
629 StringBuilder failureReason = new StringBuilder();
630 if (! LockFileManager.releaseLock(lockFile, failureReason))
631 {
632 Message message = WARN_DBTEST_CANNOT_UNLOCK_BACKEND.get(
633 backend.getBackendID(), String.valueOf(failureReason));
634 printMessage(message);
635 }
636 }
637 catch (Exception e)
638 {
639 Message message = WARN_DBTEST_CANNOT_UNLOCK_BACKEND.get(
640 backend.getBackendID(), getExceptionMessage(e));
641 printMessage(message);
642 }
643 }
644 }
645
646 private int listDatabaseContainers(Argument backendID,
647 Argument baseDN)
648 {
649 TreeMap<LocalDBBackendCfg, BackendImpl> jeBackends = getJEBackends();
650 BackendImpl backend = null;
651 DN base = null;
652
653 for(BackendImpl b : jeBackends.values())
654 {
655 if(b.getBackendID().equalsIgnoreCase(backendID.getValue()))
656 {
657 backend = b;
658 break;
659 }
660 }
661
662 if(backend == null)
663 {
664 printMessage(ERR_DBTEST_NO_BACKENDS_FOR_ID.get(backendID.getValue()));
665 return 1;
666 }
667
668 if(baseDN.isPresent())
669 {
670 try
671 {
672 base = DN.decode(baseDN.getValue());
673 }
674 catch(DirectoryException de)
675 {
676 printMessage(ERR_DBTEST_DECODE_BASE_DN.get(baseDN.getValue(),
677 getExceptionMessage(de)));
678 return 1;
679 }
680 }
681
682 // Acquire an shared lock for the backend.
683 try
684 {
685 String lockFile = LockFileManager.getBackendLockFileName(backend);
686 StringBuilder failureReason = new StringBuilder();
687 if (! LockFileManager.acquireSharedLock(lockFile, failureReason))
688 {
689 Message message = ERR_DBTEST_CANNOT_LOCK_BACKEND.get(
690 backend.getBackendID(), String.valueOf(failureReason));
691 printMessage(message);
692 return 1;
693 }
694 }
695 catch (Exception e)
696 {
697 Message message = ERR_DBTEST_CANNOT_LOCK_BACKEND.get(
698 backend.getBackendID(), getExceptionMessage(e));
699 printMessage(message);
700 return 1;
701 }
702
703 RootContainer rc;
704 try
705 {
706 rc = backend.getReadOnlyRootContainer();
707 }
708 catch(Exception e)
709 {
710 printMessage(ERR_DBTEST_ERROR_INITIALIZING_BACKEND.get(
711 backend.getBackendID(),
712 StaticUtils.stackTraceToSingleLineString(e)));
713 return 1;
714 }
715
716
717 try
718 {
719 // Create a table of their properties.
720 TableBuilder builder = new TableBuilder();
721 int count = 0;
722
723 builder.appendHeading(INFO_LABEL_DBTEST_DATABASE_NAME.get());
724 builder.appendHeading(INFO_LABEL_DBTEST_DATABASE_TYPE.get());
725 builder.appendHeading(INFO_LABEL_DBTEST_JE_DATABASE_NAME.get());
726 builder.appendHeading(INFO_LABEL_DBTEST_ENTRY_COUNT.get());
727
728 if(base != null)
729 {
730 EntryContainer ec = rc.getEntryContainer(base);
731
732 if(ec == null)
733 {
734 printMessage(ERR_DBTEST_NO_ENTRY_CONTAINERS_FOR_BASE_DN.get(
735 base.toNormalizedString(), backend.getBackendID()));
736 return 1;
737 }
738
739 ArrayList<DatabaseContainer> databaseContainers =
740 new ArrayList<DatabaseContainer>();
741 ec.listDatabases(databaseContainers);
742 for(DatabaseContainer dc : databaseContainers)
743 {
744 builder.startRow();
745 builder.appendCell(dc.getName().replace(ec.getDatabasePrefix()+"_",
746 ""));
747 builder.appendCell(dc.getClass().getSimpleName());
748 builder.appendCell(dc.getName());
749 builder.appendCell(dc.getRecordCount());
750 count++;
751 }
752 }
753 else
754 {
755 for(EntryContainer ec : rc.getEntryContainers())
756 {
757 builder.startRow();
758 ArrayList<DatabaseContainer> databaseContainers =
759 new ArrayList<DatabaseContainer>();
760 ec.listDatabases(databaseContainers);
761 builder.appendCell("Base DN: " +
762 ec.getBaseDN().toNormalizedString());
763 for(DatabaseContainer dc : databaseContainers)
764 {
765 builder.startRow();
766 builder.appendCell(dc.getName().replace(
767 ec.getDatabasePrefix()+"_",""));
768 builder.appendCell(dc.getClass().getSimpleName());
769 builder.appendCell(dc.getName());
770 builder.appendCell(dc.getRecordCount());
771 count++;
772 }
773 }
774 }
775
776 TextTablePrinter printer = new TextTablePrinter(out);
777 builder.print(printer);
778 out.format("%nTotal: %d%n", count);
779 return 0;
780
781 }
782 catch(DatabaseException de)
783 {
784 printMessage(ERR_DBTEST_ERROR_READING_DATABASE.get(
785 StaticUtils.stackTraceToSingleLineString(de)));
786 return 1;
787 }
788 finally
789 {
790 try
791 {
792 // Close the root container
793 rc.close();
794 }
795 catch(DatabaseException de)
796 {
797 // Ignore.
798 }
799
800 // Release the shared lock on the backend.
801 try
802 {
803 String lockFile = LockFileManager.getBackendLockFileName(backend);
804 StringBuilder failureReason = new StringBuilder();
805 if (! LockFileManager.releaseLock(lockFile, failureReason))
806 {
807 Message message = WARN_DBTEST_CANNOT_UNLOCK_BACKEND.get(
808 backend.getBackendID(), String.valueOf(failureReason));
809 printMessage(message);
810 }
811 }
812 catch (Exception e)
813 {
814 Message message = WARN_DBTEST_CANNOT_UNLOCK_BACKEND.get(
815 backend.getBackendID(), getExceptionMessage(e));
816 printMessage(message);
817 }
818 }
819 }
820
821 private int listIndexStatus(Argument backendID,
822 Argument baseDN)
823 {
824 TreeMap<LocalDBBackendCfg, BackendImpl> jeBackends = getJEBackends();
825 BackendImpl backend = null;
826 DN base = null;
827
828 for(BackendImpl b : jeBackends.values())
829 {
830 if(b.getBackendID().equalsIgnoreCase(backendID.getValue()))
831 {
832 backend = b;
833 break;
834 }
835 }
836
837 if(backend == null)
838 {
839 printMessage(ERR_DBTEST_NO_BACKENDS_FOR_ID.get(backendID.getValue()));
840 return 1;
841 }
842
843 if(baseDN.isPresent())
844 {
845 try
846 {
847 base = DN.decode(baseDN.getValue());
848 }
849 catch(DirectoryException de)
850 {
851 printMessage(ERR_DBTEST_DECODE_BASE_DN.get(baseDN.getValue(),
852 getExceptionMessage(de)));
853 return 1;
854 }
855 }
856
857 // Acquire an shared lock for the backend.
858 try
859 {
860 String lockFile = LockFileManager.getBackendLockFileName(backend);
861 StringBuilder failureReason = new StringBuilder();
862 if (! LockFileManager.acquireSharedLock(lockFile, failureReason))
863 {
864 Message message = ERR_DBTEST_CANNOT_LOCK_BACKEND.get(
865 backend.getBackendID(), String.valueOf(failureReason));
866 printMessage(message);
867 return 1;
868 }
869 }
870 catch (Exception e)
871 {
872 Message message = ERR_DBTEST_CANNOT_LOCK_BACKEND.get(
873 backend.getBackendID(), getExceptionMessage(e));
874 printMessage(message);
875 return 1;
876 }
877
878 RootContainer rc;
879 try
880 {
881 rc = backend.getReadOnlyRootContainer();
882 }
883 catch(Exception e)
884 {
885 printMessage(ERR_DBTEST_ERROR_INITIALIZING_BACKEND.get(
886 backend.getBackendID(),
887 StaticUtils.stackTraceToSingleLineString(e)));
888 return 1;
889 }
890
891
892 try
893 {
894 // Create a table of their properties.
895 TableBuilder builder = new TableBuilder();
896 int count = 0;
897
898 builder.appendHeading(INFO_LABEL_DBTEST_INDEX_NAME.get());
899 builder.appendHeading(INFO_LABEL_DBTEST_INDEX_TYPE.get());
900 builder.appendHeading(INFO_LABEL_DBTEST_JE_DATABASE_NAME.get());
901 builder.appendHeading(INFO_LABEL_DBTEST_INDEX_STATUS.get());
902
903 EntryContainer ec = rc.getEntryContainer(base);
904
905 if(ec == null)
906 {
907 printMessage(ERR_DBTEST_NO_ENTRY_CONTAINERS_FOR_BASE_DN.get(
908 base.toNormalizedString(), backend.getBackendID()));
909 return 1;
910 }
911
912 ArrayList<DatabaseContainer> databaseContainers =
913 new ArrayList<DatabaseContainer>();
914 ec.listDatabases(databaseContainers);
915 for(DatabaseContainer dc : databaseContainers)
916 {
917 if(dc instanceof Index || dc instanceof VLVIndex)
918 {
919 builder.startRow();
920 builder.appendCell(dc.getName().replace(ec.getDatabasePrefix()+"_",
921 ""));
922 builder.appendCell(dc.getClass().getSimpleName());
923 builder.appendCell(dc.getName());
924 if(dc instanceof Index)
925 {
926 builder.appendCell(ec.getState().getIndexTrustState(null,
927 ((Index)dc)));
928 }
929 else if(dc instanceof VLVIndex)
930 {
931 builder.appendCell(ec.getState().getIndexTrustState(null,
932 ((VLVIndex)dc)));
933 }
934 count++;
935 }
936 }
937
938 TextTablePrinter printer = new TextTablePrinter(out);
939 builder.print(printer);
940 out.format("%nTotal: %d%n", count);
941 return 0;
942 }
943 catch(DatabaseException de)
944 {
945 printMessage(ERR_DBTEST_ERROR_READING_DATABASE.get(
946 StaticUtils.stackTraceToSingleLineString(de)));
947 return 1;
948 }
949 finally
950 {
951 try
952 {
953 // Close the root container
954 rc.close();
955 }
956 catch(DatabaseException de)
957 {
958 // Ignore.
959 }
960
961 // Release the shared lock on the backend.
962 try
963 {
964 String lockFile = LockFileManager.getBackendLockFileName(backend);
965 StringBuilder failureReason = new StringBuilder();
966 if (! LockFileManager.releaseLock(lockFile, failureReason))
967 {
968 Message message = WARN_DBTEST_CANNOT_UNLOCK_BACKEND.get(
969 backend.getBackendID(), String.valueOf(failureReason));
970 printMessage(message);
971 }
972 }
973 catch (Exception e)
974 {
975 Message message = WARN_DBTEST_CANNOT_UNLOCK_BACKEND.get(
976 backend.getBackendID(), getExceptionMessage(e));
977 printMessage(message);
978 }
979 }
980 }
981
982 private int dumpDatabaseContainer(Argument backendID, Argument baseDN,
983 Argument databaseName, Argument skipDecode,
984 Argument maxKeyValue, Argument minKeyValue,
985 Argument maxDataSize,
986 Argument minDataSize)
987 {
988 TreeMap<LocalDBBackendCfg, BackendImpl> jeBackends = getJEBackends();
989 BackendImpl backend = null;
990 DN base = null;
991
992 for(BackendImpl b : jeBackends.values())
993 {
994 if(b.getBackendID().equalsIgnoreCase(backendID.getValue()))
995 {
996 backend = b;
997 break;
998 }
999 }
1000
1001 if(backend == null)
1002 {
1003 printMessage(ERR_DBTEST_NO_BACKENDS_FOR_ID.get(backendID.getValue()));
1004 return 1;
1005 }
1006
1007 try
1008 {
1009 base = DN.decode(baseDN.getValue());
1010 }
1011 catch(DirectoryException de)
1012 {
1013 printMessage(ERR_DBTEST_DECODE_BASE_DN.get(baseDN.getValue(),
1014 getExceptionMessage(de)));
1015 return 1;
1016 }
1017
1018 // Acquire an shared lock for the backend.
1019 try
1020 {
1021 String lockFile = LockFileManager.getBackendLockFileName(backend);
1022 StringBuilder failureReason = new StringBuilder();
1023 if (! LockFileManager.acquireSharedLock(lockFile, failureReason))
1024 {
1025 Message message = ERR_DBTEST_CANNOT_LOCK_BACKEND.get(
1026 backend.getBackendID(), String.valueOf(failureReason));
1027 printMessage(message);
1028 return 1;
1029 }
1030 }
1031 catch (Exception e)
1032 {
1033 Message message = ERR_DBTEST_CANNOT_LOCK_BACKEND.get(
1034 backend.getBackendID(), getExceptionMessage(e));
1035 printMessage(message);
1036 return 1;
1037 }
1038
1039 RootContainer rc;
1040 try
1041 {
1042 rc = backend.getReadOnlyRootContainer();
1043 }
1044 catch(Exception e)
1045 {
1046 printMessage(ERR_DBTEST_ERROR_INITIALIZING_BACKEND.get(
1047 backend.getBackendID(),
1048 StaticUtils.stackTraceToSingleLineString(e)));
1049 return 1;
1050 }
1051
1052 try
1053 {
1054 EntryContainer ec = rc.getEntryContainer(base);
1055
1056 if(ec == null)
1057 {
1058 printMessage(ERR_DBTEST_NO_ENTRY_CONTAINERS_FOR_BASE_DN.get(
1059 base.toNormalizedString(), backend.getBackendID()));
1060 return 1;
1061 }
1062
1063 DatabaseContainer databaseContainer = null;
1064 ArrayList<DatabaseContainer> databaseContainers =
1065 new ArrayList<DatabaseContainer>();
1066 ec.listDatabases(databaseContainers);
1067 for(DatabaseContainer dc : databaseContainers)
1068 {
1069 if(dc.getName().replace(ec.getDatabasePrefix()+"_","").
1070 equalsIgnoreCase(databaseName.getValue()))
1071 {
1072 databaseContainer = dc;
1073 break;
1074 }
1075 }
1076
1077 if(databaseContainer == null)
1078 {
1079 printMessage(ERR_DBTEST_NO_DATABASE_CONTAINERS_FOR_NAME.get(
1080 databaseName.getValue(), base.toNormalizedString(),
1081 backend.getBackendID()));
1082 return 1;
1083 }
1084
1085 int count = 0;
1086 long totalKeySize = 0;
1087 long totalDataSize = 0;
1088 int indent = 4;
1089
1090 Cursor cursor =
1091 databaseContainer.openCursor(null, CursorConfig.DEFAULT);
1092
1093 try
1094 {
1095 DatabaseEntry key = new DatabaseEntry();
1096 DatabaseEntry data = new DatabaseEntry();
1097 LockMode lockMode = LockMode.DEFAULT;
1098 OperationStatus status;
1099 Comparator<byte[]> defaultComparator =
1100 new AttributeIndex.KeyComparator();
1101 Comparator<byte[]> dnComparator =
1102 new EntryContainer.KeyReverseComparator();
1103 byte[] start = null;
1104 byte[] end = null;
1105 int minSize = -1;
1106 int maxSize = -1;
1107
1108 if(maxDataSize.isPresent())
1109 {
1110 try
1111 {
1112 maxSize = maxDataSize.getIntValue();
1113 }
1114 catch(Exception e)
1115 {
1116 printMessage(ERR_DBTEST_CANNOT_DECODE_SIZE.get(
1117 maxDataSize.getValue(), getExceptionMessage(e)));
1118 return 1;
1119 }
1120 }
1121
1122 if(minDataSize.isPresent())
1123 {
1124 try
1125 {
1126 minSize = minDataSize.getIntValue();
1127 }
1128 catch(Exception e)
1129 {
1130 printMessage(ERR_DBTEST_CANNOT_DECODE_SIZE.get(
1131 minDataSize.getValue(), getExceptionMessage(e)));
1132 return 1;
1133 }
1134 }
1135
1136 // Parse the min value if given
1137 if(minKeyValue.isPresent())
1138 {
1139 try
1140 {
1141 if(minKeyValue.getValue().startsWith("0x"))
1142 {
1143 start =
1144 StaticUtils.hexStringToByteArray(minKeyValue.getValue().
1145 substring(2));
1146 }
1147 else
1148 {
1149 if(databaseContainer instanceof DN2ID ||
1150 databaseContainer instanceof DN2URI)
1151 {
1152 // Encode the value as a DN
1153 start = StaticUtils.getBytes(
1154 DN.decode(minKeyValue.getValue()).toNormalizedString());
1155 }
1156 else if(databaseContainer instanceof ID2Entry)
1157 {
1158 // Encode the value as an entryID
1159 start = JebFormat.entryIDToDatabase(
1160 Long.parseLong(minKeyValue.getValue()));
1161 }
1162 else if(databaseContainer instanceof VLVIndex)
1163 {
1164 // Encode the value as a size/value pair
1165 byte[] vBytes =
1166 new ASN1OctetString(minKeyValue.getValue()).value();
1167 byte[] vLength = ASN1Element.encodeLength(vBytes.length);
1168 start = new byte[vBytes.length + vLength.length];
1169 System.arraycopy(vLength, 0, start, 0, vLength.length);
1170 System.arraycopy(vBytes, 0, start, vLength.length,
1171 vBytes.length);
1172 }
1173 else
1174 {
1175 start = new ASN1OctetString(minKeyValue.getValue()).value();
1176 }
1177 }
1178 }
1179 catch(Exception e)
1180 {
1181 printMessage(ERR_DBTEST_CANNOT_DECODE_KEY.get(
1182 minKeyValue.getValue(), getExceptionMessage(e)));
1183 return 1;
1184 }
1185 }
1186
1187 // Parse the max value if given
1188 if(maxKeyValue.isPresent())
1189 {
1190 try
1191 {
1192 if(maxKeyValue.getValue().startsWith("0x"))
1193 {
1194 end =
1195 StaticUtils.hexStringToByteArray(maxKeyValue.getValue().
1196 substring(2));
1197 }
1198 else
1199 {
1200 if(databaseContainer instanceof DN2ID ||
1201 databaseContainer instanceof DN2URI)
1202 {
1203 // Encode the value as a DN
1204 end = StaticUtils.getBytes(
1205 DN.decode(maxKeyValue.getValue()).toNormalizedString());
1206 }
1207 else if(databaseContainer instanceof ID2Entry)
1208 {
1209 // Encode the value as an entryID
1210 end = JebFormat.entryIDToDatabase(
1211 Long.parseLong(maxKeyValue.getValue()));
1212 }
1213 else if(databaseContainer instanceof VLVIndex)
1214 {
1215 // Encode the value as a size/value pair
1216 byte[] vBytes =
1217 new ASN1OctetString(maxKeyValue.getValue()).value();
1218 byte[] vLength = ASN1Element.encodeLength(vBytes.length);
1219 end = new byte[vBytes.length + vLength.length];
1220 System.arraycopy(vLength, 0, end, 0, vLength.length);
1221 System.arraycopy(vBytes, 0, end, vLength.length,
1222 vBytes.length);
1223 }
1224 else
1225 {
1226 end = new ASN1OctetString(maxKeyValue.getValue()).value();
1227 }
1228 }
1229 }
1230 catch(Exception e)
1231 {
1232 printMessage(ERR_DBTEST_CANNOT_DECODE_KEY.get(
1233 maxKeyValue.getValue(), getExceptionMessage(e)));
1234 return 1;
1235 }
1236 }
1237
1238
1239 if(start != null)
1240 {
1241 key.setData(start);
1242 status = cursor.getSearchKey(key, data, lockMode);
1243 }
1244 else
1245 {
1246 status = cursor.getFirst(key, data, lockMode);
1247 }
1248
1249 while(status == OperationStatus.SUCCESS)
1250 {
1251 // Make sure this record is within the value size params
1252 if((minSize > 0 && data.getSize() < minSize) ||
1253 (maxSize > 0 && data.getSize() > maxSize))
1254 {
1255 status = cursor.getNext(key, data, lockMode);
1256 continue;
1257 }
1258
1259 // Make sure we haven't gone pass the max value yet
1260 if(end != null)
1261 {
1262 if(databaseContainer instanceof DN2ID)
1263 {
1264 if(dnComparator.compare(key.getData(), end) > 0)
1265 {
1266 break;
1267 }
1268 }
1269 else if(databaseContainer instanceof DN2URI)
1270 {
1271 if(dnComparator.compare(key.getData(), end) > 0)
1272 {
1273 break;
1274 }
1275 }
1276 else if(databaseContainer instanceof Index)
1277 {
1278 if(((Index)databaseContainer).indexer.getComparator().
1279 compare(key.getData(), end) > 0)
1280 {
1281 break;
1282 }
1283 }
1284 else if(databaseContainer instanceof VLVIndex)
1285 {
1286 if(((VLVIndex)databaseContainer).comparator.
1287 compare(key.getData(), end) > 0)
1288 {
1289 break;
1290 }
1291 }
1292 else
1293 {
1294 if(defaultComparator.compare(key.getData(),
1295 end) > 0)
1296 {
1297 break;
1298 }
1299 }
1300 }
1301
1302 Message keyLabel = INFO_LABEL_DBTEST_KEY.get();
1303 Message dataLabel = INFO_LABEL_DBTEST_DATA.get();
1304
1305 String formatedKey = null;
1306 String formatedData = null;
1307
1308 if(!skipDecode.isPresent())
1309 {
1310 if(databaseContainer instanceof DN2ID)
1311 {
1312 try
1313 {
1314 formatedKey = DN.decode(new ASN1OctetString(
1315 key.getData())).toNormalizedString();
1316 keyLabel = INFO_LABEL_DBTEST_ENTRY_DN.get();
1317 }
1318 catch(Exception e)
1319 {
1320 Message message =
1321 ERR_DBTEST_DECODE_FAIL.get(getExceptionMessage(e));
1322 printMessage(message);
1323 }
1324 formatedData = String.valueOf(
1325 JebFormat.entryIDFromDatabase(data.getData()));
1326 dataLabel = INFO_LABEL_DBTEST_ENTRY_ID.get();
1327 }
1328 else if(databaseContainer instanceof ID2Entry)
1329 {
1330 formatedKey = String.valueOf(
1331 JebFormat.entryIDFromDatabase(key.getData()));
1332 keyLabel = INFO_LABEL_DBTEST_ENTRY_ID.get();
1333 try
1334 {
1335 formatedData = System.getProperty("line.separator") +
1336 JebFormat.entryFromDatabase(data.getData(),
1337 ec.getRootContainer().getCompressedSchema()).
1338 toLDIFString();
1339 dataLabel = INFO_LABEL_DBTEST_ENTRY.get();
1340 }
1341 catch(Exception e)
1342 {
1343 Message message =
1344 ERR_DBTEST_DECODE_FAIL.get(getExceptionMessage(e));
1345 printMessage(message);
1346 }
1347 }
1348 else if(databaseContainer instanceof DN2URI)
1349 {
1350 try
1351 {
1352 formatedKey = DN.decode(new ASN1OctetString(
1353 key.getData())).toNormalizedString();
1354 keyLabel = INFO_LABEL_DBTEST_ENTRY_DN.get();
1355 }
1356 catch(Exception e)
1357 {
1358 Message message =
1359 ERR_DBTEST_DECODE_FAIL.get(getExceptionMessage(e));
1360 printMessage(message);
1361 }
1362 formatedData = new ASN1OctetString(key.getData()).stringValue();
1363 dataLabel = INFO_LABEL_DBTEST_URI.get();
1364 }
1365 else if(databaseContainer instanceof Index)
1366 {
1367 formatedKey = new ASN1OctetString(key.getData()).stringValue();
1368 keyLabel = INFO_LABEL_DBTEST_INDEX_VALUE.get();
1369
1370 EntryIDSet idSet = new EntryIDSet(key.getData(),
1371 data.getData());
1372 if(idSet.isDefined())
1373 {
1374 int lineCount = 0;
1375 StringBuilder builder = new StringBuilder();
1376
1377 Iterator<EntryID> i = idSet.iterator();
1378 while(i.hasNext())
1379 {
1380 builder.append(i.next());
1381 if(lineCount == 10)
1382 {
1383 builder.append(System.getProperty("line.separator"));
1384 lineCount = 0;
1385 }
1386 else
1387 {
1388 builder.append(" ");
1389 lineCount++;
1390 }
1391 }
1392 formatedData = builder.toString();
1393 }
1394 else
1395 {
1396 formatedData = idSet.toString();
1397 }
1398 dataLabel = INFO_LABEL_DBTEST_INDEX_ENTRY_ID_LIST.get();
1399 }
1400 else if(databaseContainer instanceof VLVIndex)
1401 {
1402 VLVIndex index = (VLVIndex)databaseContainer;
1403 SortKey[] sortKeys = index.sortOrder.getSortKeys();
1404
1405 int pos = 0;
1406 byte[] keyBytes = key.getData();
1407 if(keyBytes.length > 0)
1408 {
1409 StringBuilder builder = new StringBuilder();
1410
1411 // Decode the attribute values
1412 for(SortKey sortKey : sortKeys)
1413 {
1414 int valueLength = keyBytes[pos] & 0x7F;
1415 if (keyBytes[pos++] != valueLength)
1416 {
1417 int numLengthBytes = valueLength;
1418 valueLength = 0;
1419 for (int k=0; k < numLengthBytes; k++, pos++)
1420 {
1421 valueLength = (valueLength << 8) |
1422 (keyBytes[pos] & 0xFF);
1423 }
1424 }
1425
1426 byte[] valueBytes = new byte[valueLength];
1427 System.arraycopy(keyBytes, pos, valueBytes, 0,
1428 valueLength);
1429 builder.append(sortKey.getAttributeType().getNameOrOID());
1430 builder.append(": ");
1431 if(valueBytes.length == 0)
1432 {
1433 builder.append("NULL");
1434 }
1435 else
1436 {
1437 builder.append(
1438 new ASN1OctetString(valueBytes).stringValue());
1439 }
1440 builder.append(" ");
1441 pos += valueLength;
1442 }
1443
1444 byte[] entryIDBytes = new byte[8];
1445 System.arraycopy(keyBytes, pos, entryIDBytes, 0,
1446 entryIDBytes.length);
1447 long entryID = JebFormat.entryIDFromDatabase(entryIDBytes);
1448
1449 formatedKey = System.getProperty("line.separator") +
1450 String.valueOf(entryID) + ": " + builder.toString();
1451 }
1452 else
1453 {
1454 formatedKey = "UNBOUNDED";
1455 }
1456 keyLabel = INFO_LABEL_DBTEST_VLV_INDEX_LAST_SORT_KEYS.get();
1457
1458 try
1459 {
1460 StringBuilder builder = new StringBuilder();
1461 SortValuesSet svs = new SortValuesSet(key.getData(),
1462 data.getData(),
1463 index);
1464 long[] entryIDs = svs.getEntryIDs();
1465 for(int i = 0; i < entryIDs.length; i++)
1466 {
1467 builder.append(String.valueOf(entryIDs[i]));
1468 builder.append(": ");
1469 for(int j = 0; j < sortKeys.length; j++)
1470 {
1471 SortKey sortKey = index.sortOrder.getSortKeys()[j];
1472 byte[] value = svs.getValue(i * sortKeys.length + j);
1473 builder.append(sortKey.getAttributeType().getNameOrOID());
1474 builder.append(": ");
1475 if(value == null)
1476 {
1477 builder.append("NULL");
1478 }
1479 else if(value.length == 0)
1480 {
1481 builder.append("SIZE-EXCEEDED");
1482 }
1483 else
1484 {
1485 builder.append(
1486 new ASN1OctetString(value).stringValue());
1487 }
1488 builder.append(" ");
1489 }
1490 builder.append(System.getProperty("line.separator"));
1491 }
1492 formatedData = System.getProperty("line.separator") +
1493 builder.toString();
1494 dataLabel = INFO_LABEL_DBTEST_INDEX_ENTRY_ID_LIST.get();
1495 }
1496 catch(Exception e)
1497 {
1498 Message message =
1499 ERR_DBTEST_DECODE_FAIL.get(getExceptionMessage(e));
1500 printMessage(message);
1501 }
1502 }
1503 }
1504
1505 if(formatedKey == null)
1506 {
1507 StringBuilder keyBuilder = new StringBuilder();
1508 StaticUtils.byteArrayToHexPlusAscii(keyBuilder, key.getData(),
1509 indent);
1510 formatedKey = System.getProperty("line.separator") +
1511 keyBuilder.toString();
1512 }
1513 if(formatedData == null)
1514 {
1515 StringBuilder dataBuilder = new StringBuilder();
1516 StaticUtils.byteArrayToHexPlusAscii(dataBuilder, data.getData(),
1517 indent);
1518 formatedData = System.getProperty("line.separator") +
1519 dataBuilder.toString();
1520 }
1521
1522 out.format("%s (%d bytes): %s%n", keyLabel,
1523 key.getData().length, formatedKey);
1524 out.format("%s (%d bytes): %s%n%n", dataLabel,
1525 data.getData().length, formatedData);
1526
1527 status = cursor.getNext(key, data, lockMode);
1528 count++;
1529 totalKeySize += key.getData().length;
1530 totalDataSize += data.getData().length;
1531 }
1532 }
1533 finally
1534 {
1535 cursor.close();
1536 }
1537 out.format("%nTotal Records: %d%n", count);
1538 if(count > 0)
1539 {
1540 out.format("Total / Average Key Size: %d bytes / %d bytes%n",
1541 totalKeySize, totalKeySize / count);
1542 out.format("Total / Average Data Size: %d bytes / %d bytes%n",
1543 totalDataSize, totalDataSize / count);
1544 }
1545 return 0;
1546 }
1547 catch(DatabaseException de)
1548 {
1549 printMessage(ERR_DBTEST_ERROR_READING_DATABASE.get(
1550 StaticUtils.stackTraceToSingleLineString(de)));
1551 return 1;
1552 }
1553 finally
1554 {
1555 try
1556 {
1557 // Close the root container
1558 rc.close();
1559 }
1560 catch(DatabaseException de)
1561 {
1562 // Ignore.
1563 }
1564
1565 // Release the shared lock on the backend.
1566 try
1567 {
1568 String lockFile = LockFileManager.getBackendLockFileName(backend);
1569 StringBuilder failureReason = new StringBuilder();
1570 if (! LockFileManager.releaseLock(lockFile, failureReason))
1571 {
1572 Message message = WARN_DBTEST_CANNOT_UNLOCK_BACKEND.get(
1573 backend.getBackendID(), String.valueOf(failureReason));
1574 printMessage(message);
1575 }
1576 }
1577 catch (Exception e)
1578 {
1579 Message message = WARN_DBTEST_CANNOT_UNLOCK_BACKEND.get(
1580 backend.getBackendID(), getExceptionMessage(e));
1581 printMessage(message);
1582 }
1583 }
1584 }
1585
1586 private TreeMap<LocalDBBackendCfg, BackendImpl> getJEBackends()
1587 {
1588 ArrayList<Backend> backendList = new ArrayList<Backend>();
1589 ArrayList<BackendCfg> entryList = new ArrayList<BackendCfg>();
1590 ArrayList<List<DN>> dnList = new ArrayList<List<DN>>();
1591 int code = BackendToolUtils.getBackends(backendList, entryList, dnList);
1592 // TODO: Throw error if return code is not 0
1593
1594 TreeMap<LocalDBBackendCfg, BackendImpl> jeBackends =
1595 new TreeMap<LocalDBBackendCfg, BackendImpl>();
1596 for(int i = 0; i < backendList.size(); i++)
1597 {
1598 Backend backend = backendList.get(i);
1599 if(backend instanceof BackendImpl)
1600 {
1601 jeBackends.put((LocalDBBackendCfg)entryList.get(i),
1602 (BackendImpl)backend);
1603 }
1604 }
1605
1606 return jeBackends;
1607 }
1608
1609 /**
1610 * Displays a message to the error stream.
1611 *
1612 * @param msg
1613 * The message.
1614 */
1615 public final void printMessage(Message msg) {
1616 err.println(wrapText(msg.toString(), MAX_LINE_WIDTH));
1617 }
1618 }