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 2007-2008 Sun Microsystems, Inc. 026 */ 027 package org.opends.server.backends.jeb; 028 import org.opends.messages.Message; 029 030 import java.io.IOException; 031 import java.io.File; 032 import java.util.concurrent.atomic.AtomicInteger; 033 import java.util.concurrent.locks.Lock; 034 035 import java.io.FileInputStream; 036 import java.io.FilenameFilter; 037 import java.util.*; 038 import java.util.zip.Adler32; 039 import java.util.zip.CheckedInputStream; 040 041 import com.sleepycat.je.DatabaseException; 042 import com.sleepycat.je.EnvironmentConfig; 043 import com.sleepycat.je.RunRecoveryException; 044 045 import org.opends.server.admin.std.meta.LocalDBIndexCfgDefn; 046 import org.opends.server.admin.std.server.MonitorProviderCfg; 047 import org.opends.server.api.Backend; 048 import org.opends.server.api.MonitorProvider; 049 import org.opends.server.api.AlertGenerator; 050 import org.opends.server.config.ConfigException; 051 import org.opends.server.core.AddOperation; 052 import org.opends.server.core.DeleteOperation; 053 import org.opends.server.core.DirectoryServer; 054 import org.opends.server.core.ModifyOperation; 055 import org.opends.server.core.ModifyDNOperation; 056 import org.opends.server.core.SearchOperation; 057 import org.opends.server.util.LDIFException; 058 import org.opends.server.util.Validator; 059 import static org.opends.server.util.StaticUtils.*; 060 061 import static org.opends.messages.BackendMessages.*; 062 import static org.opends.messages.JebMessages.*; 063 import static org.opends.server.loggers.ErrorLogger.logError; 064 import static org.opends.server.loggers.debug.DebugLogger.*; 065 import org.opends.server.loggers.debug.DebugTracer; 066 import org.opends.server.types.*; 067 import static org.opends.server.util.ServerConstants.*; 068 import org.opends.server.admin.std.server.LocalDBBackendCfg; 069 import org.opends.server.admin.Configuration; 070 import org.opends.server.admin.server.ConfigurationChangeListener; 071 import org.opends.server.types.DN; 072 import org.opends.server.backends.jeb.importLDIF.Importer; 073 074 /** 075 * This is an implementation of a Directory Server Backend which stores entries 076 * locally in a Berkeley DB JE database. 077 */ 078 public class BackendImpl 079 extends Backend 080 implements ConfigurationChangeListener<LocalDBBackendCfg>, AlertGenerator 081 { 082 /** 083 * The tracer object for the debug logger. 084 */ 085 private static final DebugTracer TRACER = getTracer(); 086 087 088 /** 089 * The fully-qualified name of this class. 090 */ 091 private static final String CLASS_NAME = 092 "org.opends.server.backends.jeb.BackendImpl"; 093 094 095 /** 096 * The configuration of this JE backend. 097 */ 098 private LocalDBBackendCfg cfg; 099 100 /** 101 * The root JE container to use for this backend. 102 */ 103 private RootContainer rootContainer; 104 105 /** 106 * A count of the total operation threads currently in the backend. 107 */ 108 private AtomicInteger threadTotalCount = new AtomicInteger(0); 109 110 /** 111 * A count of the write operation threads currently in the backend. 112 */ 113 private AtomicInteger threadWriteCount = new AtomicInteger(0); 114 115 /** 116 * A list of monitor providers created for this backend instance. 117 */ 118 private ArrayList<MonitorProvider<?>> monitorProviders = 119 new ArrayList<MonitorProvider<?>>(); 120 121 /** 122 * The base DNs defined for this backend instance. 123 */ 124 private DN[] baseDNs; 125 126 /** 127 * The controls supported by this backend. 128 */ 129 private static HashSet<String> supportedControls; 130 131 static 132 { 133 // Set our supported controls. 134 supportedControls = new HashSet<String>(); 135 supportedControls.add(OID_SUBTREE_DELETE_CONTROL); 136 supportedControls.add(OID_PAGED_RESULTS_CONTROL); 137 supportedControls.add(OID_MANAGE_DSAIT_CONTROL); 138 supportedControls.add(OID_SERVER_SIDE_SORT_REQUEST_CONTROL); 139 supportedControls.add(OID_VLV_REQUEST_CONTROL); 140 } 141 142 /** 143 * The features supported by this backend. 144 */ 145 private static HashSet<String> supportedFeatures; 146 147 static { 148 // Set our supported features. 149 supportedFeatures = new HashSet<String>(); 150 151 //NYI 152 } 153 154 155 156 /** 157 * Begin a Backend API method that reads the database. 158 */ 159 private void readerBegin() 160 { 161 threadTotalCount.getAndIncrement(); 162 } 163 164 165 166 /** 167 * End a Backend API method that reads the database. 168 */ 169 private void readerEnd() 170 { 171 threadTotalCount.getAndDecrement(); 172 } 173 174 175 176 /** 177 * Begin a Backend API method that writes the database. 178 */ 179 private void writerBegin() 180 { 181 threadTotalCount.getAndIncrement(); 182 threadWriteCount.getAndIncrement(); 183 } 184 185 186 187 /** 188 * End a Backend API method that writes the database. 189 */ 190 private void writerEnd() 191 { 192 threadWriteCount.getAndDecrement(); 193 threadTotalCount.getAndDecrement(); 194 } 195 196 197 198 /** 199 * Wait until there are no more threads accessing the database. It is assumed 200 * that new threads have been prevented from entering the database at the time 201 * this method is called. 202 */ 203 private void waitUntilQuiescent() 204 { 205 while (threadTotalCount.get() > 0) 206 { 207 // Still have threads in the database so sleep a little 208 try 209 { 210 Thread.sleep(500); 211 } 212 catch (InterruptedException e) 213 { 214 if (debugEnabled()) 215 { 216 TRACER.debugCaught(DebugLogLevel.ERROR, e); 217 } 218 } 219 } 220 } 221 222 /** 223 * This method will attempt to checksum the current JE db environment by 224 * computing the Adler-32 checksum on the latest JE log file available. 225 * 226 * @return The checksum of JE db environment or zero if checksum failed. 227 */ 228 private long checksumDbEnv() { 229 230 File parentDirectory = getFileForPath(cfg.getDBDirectory()); 231 File backendDirectory = new File(parentDirectory, cfg.getBackendId()); 232 233 List<File> jdbFiles = new ArrayList<File>(); 234 if(backendDirectory.isDirectory()) 235 { 236 jdbFiles = 237 Arrays.asList(backendDirectory.listFiles(new FilenameFilter() { 238 public boolean accept(File dir, String name) { 239 return name.endsWith(".jdb"); 240 } 241 })); 242 } 243 244 if ( !jdbFiles.isEmpty() ) { 245 Collections.sort(jdbFiles, Collections.reverseOrder()); 246 FileInputStream fis = null; 247 try { 248 fis = new FileInputStream(jdbFiles.get(0).toString()); 249 CheckedInputStream cis = new CheckedInputStream(fis, new Adler32()); 250 byte[] tempBuf = new byte[8192]; 251 while (cis.read(tempBuf) >= 0) { 252 } 253 254 return cis.getChecksum().getValue(); 255 } catch (Exception e) { 256 if (debugEnabled()) 257 { 258 TRACER.debugCaught(DebugLogLevel.ERROR, e); 259 } 260 } finally { 261 if (fis != null) { 262 try { 263 fis.close(); 264 } catch (Exception e) { 265 if (debugEnabled()) 266 { 267 TRACER.debugCaught(DebugLogLevel.ERROR, e); 268 } 269 } 270 } 271 } 272 } 273 274 return 0; 275 } 276 277 278 279 /** 280 * {@inheritDoc} 281 */ 282 public void configureBackend(Configuration cfg) 283 throws ConfigException 284 { 285 Validator.ensureNotNull(cfg); 286 Validator.ensureTrue(cfg instanceof LocalDBBackendCfg); 287 288 this.cfg = (LocalDBBackendCfg)cfg; 289 290 Set<DN> dnSet = this.cfg.getBaseDN(); 291 baseDNs = new DN[dnSet.size()]; 292 dnSet.toArray(baseDNs); 293 } 294 295 296 297 /** 298 * {@inheritDoc} 299 */ 300 @Override() 301 public void initializeBackend() 302 throws ConfigException, InitializationException 303 { 304 // Checksum this db environment and register its offline state id/checksum. 305 DirectoryServer.registerOfflineBackendStateID(this.getBackendID(), 306 checksumDbEnv()); 307 308 if(rootContainer == null) 309 { 310 EnvironmentConfig envConfig = 311 ConfigurableEnvironment.parseConfigEntry(cfg); 312 envConfig.setLockTimeout(0); 313 rootContainer = initializeRootContainer(envConfig); 314 } 315 316 // Preload the database cache. 317 rootContainer.preload(cfg.getPreloadTimeLimit()); 318 319 try 320 { 321 // Log an informational message about the number of entries. 322 Message message = NOTE_JEB_BACKEND_STARTED.get( 323 cfg.getBackendId(), rootContainer.getEntryCount()); 324 logError(message); 325 } 326 catch(DatabaseException databaseException) 327 { 328 if (debugEnabled()) 329 { 330 TRACER.debugCaught(DebugLogLevel.ERROR, databaseException); 331 } 332 Message message = 333 WARN_JEB_GET_ENTRY_COUNT_FAILED.get(databaseException.getMessage()); 334 throw new InitializationException( 335 message, databaseException); 336 } 337 338 for (DN dn : cfg.getBaseDN()) 339 { 340 try 341 { 342 DirectoryServer.registerBaseDN(dn, this, false); 343 } 344 catch (Exception e) 345 { 346 if (debugEnabled()) 347 { 348 TRACER.debugCaught(DebugLogLevel.ERROR, e); 349 } 350 351 Message message = ERR_BACKEND_CANNOT_REGISTER_BASEDN.get( 352 String.valueOf(dn), String.valueOf(e)); 353 throw new InitializationException(message, e); 354 } 355 } 356 357 // Register a monitor provider for the environment. 358 MonitorProvider<? extends MonitorProviderCfg> monitorProvider = 359 rootContainer.getMonitorProvider(); 360 monitorProviders.add(monitorProvider); 361 DirectoryServer.registerMonitorProvider(monitorProvider); 362 363 //Register as an AlertGenerator. 364 DirectoryServer.registerAlertGenerator(this); 365 // Register this backend as a change listener. 366 cfg.addLocalDBChangeListener(this); 367 } 368 369 370 371 /** 372 * {@inheritDoc} 373 */ 374 @Override() 375 public void finalizeBackend() 376 { 377 // Deregister as a change listener. 378 cfg.removeLocalDBChangeListener(this); 379 380 // Deregister our base DNs. 381 for (DN dn : rootContainer.getBaseDNs()) 382 { 383 try 384 { 385 DirectoryServer.deregisterBaseDN(dn); 386 } 387 catch (Exception e) 388 { 389 if (debugEnabled()) 390 { 391 TRACER.debugCaught(DebugLogLevel.ERROR, e); 392 } 393 } 394 } 395 396 // Deregister our monitor providers. 397 for (MonitorProvider<?> monitor : monitorProviders) 398 { 399 DirectoryServer.deregisterMonitorProvider( 400 monitor.getMonitorInstanceName().toLowerCase()); 401 } 402 monitorProviders = new ArrayList<MonitorProvider<?>>(); 403 404 // We presume the server will prevent more operations coming into this 405 // backend, but there may be existing operations already in the 406 // backend. We need to wait for them to finish. 407 waitUntilQuiescent(); 408 409 // Close the database. 410 try 411 { 412 rootContainer.close(); 413 rootContainer = null; 414 } 415 catch (DatabaseException e) 416 { 417 if (debugEnabled()) 418 { 419 TRACER.debugCaught(DebugLogLevel.ERROR, e); 420 } 421 Message message = ERR_JEB_DATABASE_EXCEPTION.get(e.getMessage()); 422 logError(message); 423 } 424 425 // Checksum this db environment and register its offline state id/checksum. 426 DirectoryServer.registerOfflineBackendStateID(this.getBackendID(), 427 checksumDbEnv()); 428 429 //Deregister the alert generator. 430 DirectoryServer.deregisterAlertGenerator(this); 431 432 // Make sure the thread counts are zero for next initialization. 433 threadTotalCount.set(0); 434 threadWriteCount.set(0); 435 436 // Log an informational message. 437 Message message = NOTE_BACKEND_OFFLINE.get(cfg.getBackendId()); 438 logError(message); 439 } 440 441 442 443 /** 444 * {@inheritDoc} 445 */ 446 @Override() 447 public boolean isLocal() 448 { 449 return true; 450 } 451 452 453 454 /** 455 * {@inheritDoc} 456 */ 457 @Override() 458 public boolean isIndexed(AttributeType attributeType, IndexType indexType) 459 { 460 try 461 { 462 EntryContainer ec = rootContainer.getEntryContainer(baseDNs[0]); 463 AttributeIndex ai = ec.getAttributeIndex(attributeType); 464 if (ai == null) 465 { 466 return false; 467 } 468 469 Set<LocalDBIndexCfgDefn.IndexType> indexTypes = 470 ai.getConfiguration().getIndexType(); 471 switch (indexType) 472 { 473 case PRESENCE: 474 return indexTypes.contains(LocalDBIndexCfgDefn.IndexType.PRESENCE); 475 476 case EQUALITY: 477 return indexTypes.contains(LocalDBIndexCfgDefn.IndexType.EQUALITY); 478 479 case SUBSTRING: 480 case SUBINITIAL: 481 case SUBANY: 482 case SUBFINAL: 483 return indexTypes.contains(LocalDBIndexCfgDefn.IndexType.SUBSTRING); 484 485 case GREATER_OR_EQUAL: 486 case LESS_OR_EQUAL: 487 return indexTypes.contains(LocalDBIndexCfgDefn.IndexType.ORDERING); 488 489 case APPROXIMATE: 490 return indexTypes.contains(LocalDBIndexCfgDefn.IndexType.APPROXIMATE); 491 492 default: 493 return false; 494 } 495 } 496 catch (Exception e) 497 { 498 if (debugEnabled()) 499 { 500 TRACER.debugCaught(DebugLogLevel.ERROR, e); 501 } 502 503 return false; 504 } 505 } 506 507 508 509 /** 510 * {@inheritDoc} 511 */ 512 @Override() 513 public boolean supportsLDIFExport() 514 { 515 return true; 516 } 517 518 519 520 /** 521 * {@inheritDoc} 522 */ 523 @Override() 524 public boolean supportsLDIFImport() 525 { 526 return true; 527 } 528 529 530 531 /** 532 * {@inheritDoc} 533 */ 534 @Override() 535 public boolean supportsBackup() 536 { 537 return true; 538 } 539 540 541 542 /** 543 * {@inheritDoc} 544 */ 545 @Override() 546 public boolean supportsBackup(BackupConfig backupConfig, 547 StringBuilder unsupportedReason) 548 { 549 return true; 550 } 551 552 553 554 /** 555 * {@inheritDoc} 556 */ 557 @Override() 558 public boolean supportsRestore() 559 { 560 return true; 561 } 562 563 564 565 /** 566 * {@inheritDoc} 567 */ 568 @Override() 569 public HashSet<String> getSupportedFeatures() 570 { 571 return supportedFeatures; 572 } 573 574 575 576 /** 577 * {@inheritDoc} 578 */ 579 @Override() 580 public HashSet<String> getSupportedControls() 581 { 582 return supportedControls; 583 } 584 585 586 587 /** 588 * {@inheritDoc} 589 */ 590 @Override() 591 public DN[] getBaseDNs() 592 { 593 return baseDNs; 594 } 595 596 597 598 /** 599 * {@inheritDoc} 600 */ 601 @Override() 602 public long getEntryCount() 603 { 604 if (rootContainer != null) 605 { 606 try 607 { 608 return rootContainer.getEntryCount(); 609 } 610 catch (Exception e) 611 { 612 if (debugEnabled()) 613 { 614 TRACER.debugCaught(DebugLogLevel.ERROR, e); 615 } 616 } 617 } 618 619 return -1; 620 } 621 622 623 624 /** 625 * {@inheritDoc} 626 */ 627 @Override() 628 public ConditionResult hasSubordinates(DN entryDN) 629 throws DirectoryException 630 { 631 long ret = numSubordinates(entryDN, false); 632 if(ret < 0) 633 { 634 return ConditionResult.UNDEFINED; 635 } 636 else if(ret == 0) 637 { 638 return ConditionResult.FALSE; 639 } 640 else 641 { 642 return ConditionResult.TRUE; 643 } 644 } 645 646 647 648 /** 649 * {@inheritDoc} 650 */ 651 @Override() 652 public long numSubordinates(DN entryDN, boolean subtree) 653 throws DirectoryException 654 { 655 EntryContainer ec; 656 if (rootContainer != null) 657 { 658 ec = rootContainer.getEntryContainer(entryDN); 659 } 660 else 661 { 662 Message message = ERR_ROOT_CONTAINER_NOT_INITIALIZED.get(getBackendID()); 663 throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), 664 message); 665 } 666 667 if(ec == null) 668 { 669 return -1; 670 } 671 672 readerBegin(); 673 ec.sharedLock.lock(); 674 try 675 { 676 long count = ec.getNumSubordinates(entryDN, subtree); 677 if(count == Long.MAX_VALUE) 678 { 679 // The index entry limit has exceeded and there is no count maintained. 680 return -1; 681 } 682 return count; 683 } 684 catch (DatabaseException e) 685 { 686 if (debugEnabled()) 687 { 688 TRACER.debugCaught(DebugLogLevel.ERROR, e); 689 } 690 throw createDirectoryException(e); 691 } 692 finally 693 { 694 ec.sharedLock.unlock(); 695 readerEnd(); 696 } 697 } 698 699 700 701 /** 702 * {@inheritDoc} 703 */ 704 @Override() 705 public Entry getEntry(DN entryDN) throws DirectoryException 706 { 707 readerBegin(); 708 709 EntryContainer ec; 710 if (rootContainer != null) 711 { 712 ec = rootContainer.getEntryContainer(entryDN); 713 } 714 else 715 { 716 Message message = ERR_ROOT_CONTAINER_NOT_INITIALIZED.get(getBackendID()); 717 throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), 718 message); 719 } 720 721 ec.sharedLock.lock(); 722 Entry entry; 723 try 724 { 725 entry = ec.getEntry(entryDN); 726 } 727 catch (DatabaseException e) 728 { 729 if (debugEnabled()) 730 { 731 TRACER.debugCaught(DebugLogLevel.ERROR, e); 732 } 733 throw createDirectoryException(e); 734 } 735 catch (JebException e) 736 { 737 if (debugEnabled()) 738 { 739 TRACER.debugCaught(DebugLogLevel.ERROR, e); 740 } 741 throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), 742 e.getMessageObject()); 743 } 744 finally 745 { 746 ec.sharedLock.unlock(); 747 readerEnd(); 748 } 749 750 return entry; 751 } 752 753 754 755 /** 756 * {@inheritDoc} 757 */ 758 @Override() 759 public void addEntry(Entry entry, AddOperation addOperation) 760 throws DirectoryException 761 { 762 writerBegin(); 763 DN entryDN = entry.getDN(); 764 765 EntryContainer ec; 766 if (rootContainer != null) 767 { 768 ec = rootContainer.getEntryContainer(entryDN); 769 } 770 else 771 { 772 Message message = ERR_ROOT_CONTAINER_NOT_INITIALIZED.get(getBackendID()); 773 throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), 774 message); 775 } 776 777 ec.sharedLock.lock(); 778 try 779 { 780 ec.addEntry(entry, addOperation); 781 } 782 catch (DatabaseException e) 783 { 784 if (debugEnabled()) 785 { 786 TRACER.debugCaught(DebugLogLevel.ERROR, e); 787 } 788 throw createDirectoryException(e); 789 } 790 catch (JebException e) 791 { 792 if (debugEnabled()) 793 { 794 TRACER.debugCaught(DebugLogLevel.ERROR, e); 795 } 796 throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), 797 e.getMessageObject()); 798 } 799 finally 800 { 801 ec.sharedLock.unlock(); 802 writerEnd(); 803 } 804 } 805 806 807 808 /** 809 * {@inheritDoc} 810 */ 811 @Override() 812 public void deleteEntry(DN entryDN, DeleteOperation deleteOperation) 813 throws DirectoryException 814 { 815 writerBegin(); 816 817 EntryContainer ec; 818 if (rootContainer != null) 819 { 820 ec = rootContainer.getEntryContainer(entryDN); 821 } 822 else 823 { 824 Message message = ERR_ROOT_CONTAINER_NOT_INITIALIZED.get(getBackendID()); 825 throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), 826 message); 827 } 828 829 ec.sharedLock.lock(); 830 try 831 { 832 ec.deleteEntry(entryDN, deleteOperation); 833 } 834 catch (DatabaseException e) 835 { 836 if (debugEnabled()) 837 { 838 TRACER.debugCaught(DebugLogLevel.ERROR, e); 839 } 840 throw createDirectoryException(e); 841 } 842 catch (JebException e) 843 { 844 if (debugEnabled()) 845 { 846 TRACER.debugCaught(DebugLogLevel.ERROR, e); 847 } 848 throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), 849 e.getMessageObject()); 850 } 851 finally 852 { 853 ec.sharedLock.unlock(); 854 writerEnd(); 855 } 856 } 857 858 859 860 /** 861 * {@inheritDoc} 862 */ 863 @Override() 864 public void replaceEntry(Entry entry, ModifyOperation modifyOperation) 865 throws DirectoryException 866 { 867 writerBegin(); 868 869 DN entryDN = entry.getDN(); 870 EntryContainer ec; 871 if (rootContainer != null) 872 { 873 ec = rootContainer.getEntryContainer(entryDN); 874 } 875 else 876 { 877 Message message = ERR_ROOT_CONTAINER_NOT_INITIALIZED.get(getBackendID()); 878 throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), 879 message); 880 } 881 882 ec.sharedLock.lock(); 883 884 try 885 { 886 ec.replaceEntry(entry, modifyOperation); 887 } 888 catch (DatabaseException e) 889 { 890 if (debugEnabled()) 891 { 892 TRACER.debugCaught(DebugLogLevel.ERROR, e); 893 } 894 throw createDirectoryException(e); 895 } 896 catch (JebException e) 897 { 898 if (debugEnabled()) 899 { 900 TRACER.debugCaught(DebugLogLevel.ERROR, e); 901 } 902 throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), 903 e.getMessageObject()); 904 } 905 finally 906 { 907 ec.sharedLock.unlock(); 908 writerEnd(); 909 } 910 } 911 912 913 914 /** 915 * {@inheritDoc} 916 */ 917 @Override() 918 public void renameEntry(DN currentDN, Entry entry, 919 ModifyDNOperation modifyDNOperation) 920 throws DirectoryException, CanceledOperationException { 921 writerBegin(); 922 923 EntryContainer currentContainer; 924 if (rootContainer != null) 925 { 926 currentContainer = rootContainer.getEntryContainer(currentDN); 927 } 928 else 929 { 930 Message message = ERR_ROOT_CONTAINER_NOT_INITIALIZED.get(getBackendID()); 931 throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), 932 message); 933 } 934 935 EntryContainer container = rootContainer.getEntryContainer(entry.getDN()); 936 937 if (currentContainer != container) 938 { 939 // FIXME: No reason why we cannot implement a move between containers 940 // since the containers share the same database environment. 941 Message msg = WARN_JEB_FUNCTION_NOT_SUPPORTED.get(); 942 throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, 943 msg); 944 } 945 946 Lock containerLock = currentContainer.sharedLock; 947 try 948 { 949 containerLock.lock(); 950 951 if(currentContainer.getNumSubordinates(currentDN, true) > 952 currentContainer.getSubtreeDeleteBatchSize()) 953 { 954 containerLock.unlock(); 955 containerLock = currentContainer.exclusiveLock; 956 containerLock.lock(); 957 } 958 959 currentContainer.renameEntry(currentDN, entry, modifyDNOperation); 960 } 961 catch (DatabaseException e) 962 { 963 if (debugEnabled()) 964 { 965 TRACER.debugCaught(DebugLogLevel.ERROR, e); 966 } 967 throw createDirectoryException(e); 968 } 969 catch (JebException e) 970 { 971 if (debugEnabled()) 972 { 973 TRACER.debugCaught(DebugLogLevel.ERROR, e); 974 } 975 throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), 976 e.getMessageObject()); 977 } 978 finally 979 { 980 containerLock.unlock(); 981 writerEnd(); 982 } 983 } 984 985 986 987 /** 988 * {@inheritDoc} 989 */ 990 @Override() 991 public void search(SearchOperation searchOperation) 992 throws DirectoryException 993 { 994 readerBegin(); 995 996 EntryContainer ec; 997 if (rootContainer != null) 998 { 999 ec = rootContainer.getEntryContainer(searchOperation.getBaseDN()); 1000 } 1001 else 1002 { 1003 Message message = ERR_ROOT_CONTAINER_NOT_INITIALIZED.get(getBackendID()); 1004 throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), 1005 message); 1006 } 1007 ec.sharedLock.lock(); 1008 1009 try 1010 { 1011 ec.search(searchOperation); 1012 } 1013 catch (DatabaseException e) 1014 { 1015 if (debugEnabled()) 1016 { 1017 TRACER.debugCaught(DebugLogLevel.ERROR, e); 1018 } 1019 throw createDirectoryException(e); 1020 } 1021 catch (JebException e) 1022 { 1023 if (debugEnabled()) 1024 { 1025 TRACER.debugCaught(DebugLogLevel.ERROR, e); 1026 } 1027 Message message = ERR_JEB_DATABASE_EXCEPTION.get(e.getMessage()); 1028 throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), 1029 message); 1030 } 1031 finally 1032 { 1033 ec.sharedLock.unlock(); 1034 readerEnd(); 1035 } 1036 } 1037 1038 1039 1040 /** 1041 * {@inheritDoc} 1042 */ 1043 @Override() 1044 public void exportLDIF(LDIFExportConfig exportConfig) 1045 throws DirectoryException 1046 { 1047 // If the backend already has the root container open, we must use the same 1048 // underlying root container 1049 boolean openRootContainer = rootContainer == null; 1050 1051 try 1052 { 1053 if(openRootContainer) 1054 { 1055 EnvironmentConfig envConfig = 1056 ConfigurableEnvironment.parseConfigEntry(cfg); 1057 1058 envConfig.setReadOnly(true); 1059 envConfig.setAllowCreate(false); 1060 envConfig.setTransactional(false); 1061 envConfig.setTxnNoSync(false); 1062 envConfig.setConfigParam("je.env.isLocking", "true"); 1063 envConfig.setConfigParam("je.env.runCheckpointer", "true"); 1064 1065 rootContainer = initializeRootContainer(envConfig); 1066 } 1067 1068 1069 ExportJob exportJob = new ExportJob(exportConfig); 1070 exportJob.exportLDIF(rootContainer); 1071 } 1072 catch (IOException ioe) 1073 { 1074 if (debugEnabled()) 1075 { 1076 TRACER.debugCaught(DebugLogLevel.ERROR, ioe); 1077 } 1078 Message message = ERR_JEB_IO_ERROR.get(ioe.getMessage()); 1079 throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), 1080 message); 1081 } 1082 catch (JebException je) 1083 { 1084 if (debugEnabled()) 1085 { 1086 TRACER.debugCaught(DebugLogLevel.ERROR, je); 1087 } 1088 throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), 1089 je.getMessageObject()); 1090 } 1091 catch (DatabaseException de) 1092 { 1093 if (debugEnabled()) 1094 { 1095 TRACER.debugCaught(DebugLogLevel.ERROR, de); 1096 } 1097 throw createDirectoryException(de); 1098 } 1099 catch (LDIFException e) 1100 { 1101 if (debugEnabled()) 1102 { 1103 TRACER.debugCaught(DebugLogLevel.ERROR, e); 1104 } 1105 throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), 1106 e.getMessageObject()); 1107 } 1108 catch (InitializationException ie) 1109 { 1110 if (debugEnabled()) 1111 { 1112 TRACER.debugCaught(DebugLogLevel.ERROR, ie); 1113 } 1114 throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), 1115 ie.getMessageObject()); 1116 } 1117 catch (ConfigException ce) 1118 { 1119 if (debugEnabled()) 1120 { 1121 TRACER.debugCaught(DebugLogLevel.ERROR, ce); 1122 } 1123 throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), 1124 ce.getMessageObject()); 1125 } 1126 finally 1127 { 1128 //If a root container was opened in this method as read only, close it 1129 //to leave the backend in the same state. 1130 if (openRootContainer && rootContainer != null) 1131 { 1132 try 1133 { 1134 rootContainer.close(); 1135 rootContainer = null; 1136 } 1137 catch (DatabaseException e) 1138 { 1139 if (debugEnabled()) 1140 { 1141 TRACER.debugCaught(DebugLogLevel.ERROR, e); 1142 } 1143 } 1144 } 1145 } 1146 } 1147 1148 1149 1150 /** 1151 * {@inheritDoc} 1152 */ 1153 @Override() 1154 public LDIFImportResult importLDIF(LDIFImportConfig importConfig) 1155 throws DirectoryException 1156 { 1157 // If the backend already has the root container open, we must use the same 1158 // underlying root container 1159 boolean openRootContainer = rootContainer == null; 1160 1161 // If the rootContainer is open, the backend is initialized by something 1162 // else. 1163 // We can't do import while the backend is online. 1164 if(!openRootContainer) 1165 { 1166 Message message = ERR_JEB_IMPORT_BACKEND_ONLINE.get(); 1167 throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), 1168 message); 1169 } 1170 1171 try 1172 { 1173 EnvironmentConfig envConfig = 1174 ConfigurableEnvironment.parseConfigEntry(cfg); 1175 if(!importConfig.appendToExistingData()) { 1176 if(importConfig.clearBackend() || cfg.getBaseDN().size() <= 1) { 1177 // We have the writer lock on the environment, now delete the 1178 // environment and re-open it. Only do this when we are 1179 // importing to all the base DNs in the backend or if the backend only 1180 // have one base DN. 1181 File parentDirectory = getFileForPath(cfg.getDBDirectory()); 1182 File backendDirectory = new File(parentDirectory, cfg.getBackendId()); 1183 // If the backend does not exist the import will create it. 1184 if (backendDirectory.exists()) { 1185 EnvManager.removeFiles(backendDirectory.getPath()); 1186 } 1187 } 1188 } 1189 envConfig.setReadOnly(false); 1190 envConfig.setAllowCreate(true); 1191 envConfig.setTransactional(false); 1192 envConfig.setTxnNoSync(false); 1193 envConfig.setConfigParam("je.env.isLocking", "false"); 1194 envConfig.setConfigParam("je.env.runCheckpointer", "false"); 1195 Importer importer = new Importer(importConfig); 1196 envConfig.setConfigParam("je.maxMemory", importer.getDBCacheSize()); 1197 rootContainer = initializeRootContainer(envConfig); 1198 return importer.processImport(rootContainer); 1199 } 1200 catch (IOException ioe) 1201 { 1202 if (debugEnabled()) 1203 { 1204 TRACER.debugCaught(DebugLogLevel.ERROR, ioe); 1205 } 1206 Message message = ERR_JEB_IO_ERROR.get(ioe.getMessage()); 1207 throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), 1208 message); 1209 } 1210 catch (JebException je) 1211 { 1212 if (debugEnabled()) 1213 { 1214 TRACER.debugCaught(DebugLogLevel.ERROR, je); 1215 } 1216 throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), 1217 je.getMessageObject()); 1218 } 1219 catch (DatabaseException de) 1220 { 1221 if (debugEnabled()) 1222 { 1223 TRACER.debugCaught(DebugLogLevel.ERROR, de); 1224 } 1225 throw createDirectoryException(de); 1226 } 1227 catch (InitializationException ie) 1228 { 1229 if (debugEnabled()) 1230 { 1231 TRACER.debugCaught(DebugLogLevel.ERROR, ie); 1232 } 1233 throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), 1234 ie.getMessageObject()); 1235 } 1236 catch (ConfigException ce) 1237 { 1238 if (debugEnabled()) 1239 { 1240 TRACER.debugCaught(DebugLogLevel.ERROR, ce); 1241 } 1242 throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), 1243 ce.getMessageObject()); 1244 } 1245 finally 1246 { 1247 // leave the backend in the same state. 1248 try 1249 { 1250 if (rootContainer != null) 1251 { 1252 long startTime = System.currentTimeMillis(); 1253 rootContainer.close(); 1254 long finishTime = System.currentTimeMillis(); 1255 long closeTime = (finishTime - startTime) / 1000; 1256 Message msg = 1257 NOTE_JEB_IMPORT_LDIF_ROOTCONTAINER_CLOSE.get(closeTime); 1258 logError(msg); 1259 rootContainer = null; 1260 } 1261 1262 // Sync the environment to disk. 1263 if (debugEnabled()) 1264 { 1265 Message message = NOTE_JEB_IMPORT_CLOSING_DATABASE.get(); 1266 TRACER.debugInfo(message.toString()); 1267 } 1268 } 1269 catch (DatabaseException de) 1270 { 1271 if (debugEnabled()) 1272 { 1273 TRACER.debugCaught(DebugLogLevel.ERROR, de); 1274 } 1275 } 1276 } 1277 } 1278 1279 1280 1281 /** 1282 * Verify the integrity of the backend instance. 1283 * @param verifyConfig The verify configuration. 1284 * @param statEntry Optional entry to save stats into. 1285 * @return The error count. 1286 * @throws ConfigException If an unrecoverable problem arises during 1287 * initialization. 1288 * @throws InitializationException If a problem occurs during initialization 1289 * that is not related to the server 1290 * configuration. 1291 * @throws DirectoryException If a Directory Server error occurs. 1292 */ 1293 public long verifyBackend(VerifyConfig verifyConfig, Entry statEntry) 1294 throws InitializationException, ConfigException, DirectoryException 1295 { 1296 // If the backend already has the root container open, we must use the same 1297 // underlying root container 1298 boolean openRootContainer = rootContainer == null; 1299 long errorCount = 0 ; 1300 1301 try 1302 { 1303 if(openRootContainer) 1304 { 1305 EnvironmentConfig envConfig = 1306 ConfigurableEnvironment.parseConfigEntry(cfg); 1307 1308 envConfig.setReadOnly(true); 1309 envConfig.setAllowCreate(false); 1310 envConfig.setTransactional(false); 1311 envConfig.setTxnNoSync(false); 1312 envConfig.setConfigParam("je.env.isLocking", "true"); 1313 envConfig.setConfigParam("je.env.runCheckpointer", "true"); 1314 1315 rootContainer = initializeRootContainer(envConfig); 1316 } 1317 1318 VerifyJob verifyJob = new VerifyJob(verifyConfig); 1319 errorCount = verifyJob.verifyBackend(rootContainer, statEntry); 1320 } 1321 catch (DatabaseException e) 1322 { 1323 if (debugEnabled()) 1324 { 1325 TRACER.debugCaught(DebugLogLevel.ERROR, e); 1326 } 1327 throw createDirectoryException(e); 1328 } 1329 catch (JebException e) 1330 { 1331 if (debugEnabled()) 1332 { 1333 TRACER.debugCaught(DebugLogLevel.ERROR, e); 1334 } 1335 throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), 1336 e.getMessageObject()); 1337 } 1338 finally 1339 { 1340 //If a root container was opened in this method as read only, close it 1341 //to leave the backend in the same state. 1342 if (openRootContainer && rootContainer != null) 1343 { 1344 try 1345 { 1346 rootContainer.close(); 1347 rootContainer = null; 1348 } 1349 catch (DatabaseException e) 1350 { 1351 if (debugEnabled()) 1352 { 1353 TRACER.debugCaught(DebugLogLevel.ERROR, e); 1354 } 1355 } 1356 } 1357 } 1358 return errorCount; 1359 } 1360 1361 1362 /** 1363 * Rebuild index(es) in the backend instance. Note that the server will not 1364 * explicitly initialize this backend before calling this method. 1365 * @param rebuildConfig The rebuild configuration. 1366 * @throws ConfigException If an unrecoverable problem arises during 1367 * initialization. 1368 * @throws InitializationException If a problem occurs during initialization 1369 * that is not related to the server 1370 * configuration. 1371 * @throws DirectoryException If a Directory Server error occurs. 1372 */ 1373 public void rebuildBackend(RebuildConfig rebuildConfig) 1374 throws InitializationException, ConfigException, DirectoryException 1375 { 1376 // If the backend already has the root container open, we must use the same 1377 // underlying root container 1378 boolean openRootContainer = rootContainer == null; 1379 1380 // If the rootContainer is open, the backend is initialized by something 1381 // else. 1382 // We can't do any rebuild of system indexes while others are using this 1383 // backend. Throw error. TODO: Need to make baseDNs disablable. 1384 if(!openRootContainer && rebuildConfig.includesSystemIndex()) 1385 { 1386 Message message = ERR_JEB_REBUILD_BACKEND_ONLINE.get(); 1387 throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), 1388 message); 1389 } 1390 1391 try 1392 { 1393 if (openRootContainer) 1394 { 1395 EnvironmentConfig envConfig = 1396 ConfigurableEnvironment.parseConfigEntry(cfg); 1397 1398 rootContainer = initializeRootContainer(envConfig); 1399 } 1400 1401 RebuildJob rebuildJob = new RebuildJob(rebuildConfig); 1402 rebuildJob.rebuildBackend(rootContainer); 1403 } 1404 catch (DatabaseException e) 1405 { 1406 if (debugEnabled()) 1407 { 1408 TRACER.debugCaught(DebugLogLevel.ERROR, e); 1409 } 1410 throw createDirectoryException(e); 1411 } 1412 catch (JebException e) 1413 { 1414 if (debugEnabled()) 1415 { 1416 TRACER.debugCaught(DebugLogLevel.ERROR, e); 1417 } 1418 throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), 1419 e.getMessageObject()); 1420 } 1421 finally 1422 { 1423 //If a root container was opened in this method as read only, close it 1424 //to leave the backend in the same state. 1425 if (openRootContainer && rootContainer != null) 1426 { 1427 try 1428 { 1429 rootContainer.close(); 1430 rootContainer = null; 1431 } 1432 catch (DatabaseException e) 1433 { 1434 if (debugEnabled()) 1435 { 1436 TRACER.debugCaught(DebugLogLevel.ERROR, e); 1437 } 1438 } 1439 } 1440 } 1441 } 1442 1443 1444 1445 /** 1446 * {@inheritDoc} 1447 */ 1448 @Override() 1449 public void createBackup(BackupConfig backupConfig) 1450 throws DirectoryException 1451 { 1452 BackupManager backupManager = 1453 new BackupManager(getBackendID()); 1454 File parentDir = getFileForPath(cfg.getDBDirectory()); 1455 File backendDir = new File(parentDir, cfg.getBackendId()); 1456 backupManager.createBackup(backendDir, backupConfig); 1457 } 1458 1459 1460 1461 /** 1462 * {@inheritDoc} 1463 */ 1464 @Override() 1465 public void removeBackup(BackupDirectory backupDirectory, String backupID) 1466 throws DirectoryException 1467 { 1468 BackupManager backupManager = 1469 new BackupManager(getBackendID()); 1470 backupManager.removeBackup(backupDirectory, backupID); 1471 } 1472 1473 1474 1475 /** 1476 * {@inheritDoc} 1477 */ 1478 @Override() 1479 public void restoreBackup(RestoreConfig restoreConfig) 1480 throws DirectoryException 1481 { 1482 BackupManager backupManager = 1483 new BackupManager(getBackendID()); 1484 File parentDir = getFileForPath(cfg.getDBDirectory()); 1485 File backendDir = new File(parentDir, cfg.getBackendId()); 1486 backupManager.restoreBackup(backendDir, restoreConfig); 1487 } 1488 1489 1490 1491 /** 1492 * {@inheritDoc} 1493 */ 1494 @Override() 1495 public boolean isConfigurationAcceptable(Configuration configuration, 1496 List<Message> unacceptableReasons) 1497 { 1498 LocalDBBackendCfg config = (LocalDBBackendCfg) configuration; 1499 return isConfigurationChangeAcceptable(config, unacceptableReasons); 1500 } 1501 1502 1503 1504 /** 1505 * {@inheritDoc} 1506 */ 1507 public boolean isConfigurationChangeAcceptable( 1508 LocalDBBackendCfg cfg, 1509 List<Message> unacceptableReasons) 1510 { 1511 // Make sure that the logging level value is acceptable. 1512 String loggingLevel = cfg.getDBLoggingLevel(); 1513 if (! (loggingLevel.equals("OFF") || 1514 loggingLevel.equals("SEVERE") || 1515 loggingLevel.equals("WARNING") || 1516 loggingLevel.equals("INFORMATION") || 1517 loggingLevel.equals("CONFIG") || 1518 loggingLevel.equals("FINE") || 1519 loggingLevel.equals("FINER") || 1520 loggingLevel.equals("FINEST") || 1521 loggingLevel.equals("OFF"))) 1522 { 1523 1524 Message message = ERR_JEB_INVALID_LOGGING_LEVEL.get( 1525 String.valueOf(cfg.getDBLoggingLevel()), 1526 String.valueOf(cfg.dn())); 1527 unacceptableReasons.add(message); 1528 return false; 1529 } 1530 1531 return true; 1532 } 1533 1534 1535 1536 /** 1537 * {@inheritDoc} 1538 */ 1539 public ConfigChangeResult applyConfigurationChange(LocalDBBackendCfg newCfg) 1540 { 1541 ConfigChangeResult ccr; 1542 ResultCode resultCode = ResultCode.SUCCESS; 1543 ArrayList<Message> messages = new ArrayList<Message>(); 1544 1545 1546 try 1547 { 1548 if(rootContainer != null) 1549 { 1550 DN[] newBaseDNs = new DN[newCfg.getBaseDN().size()]; 1551 newBaseDNs = newCfg.getBaseDN().toArray(newBaseDNs); 1552 1553 // Check for changes to the base DNs. 1554 for (DN baseDN : cfg.getBaseDN()) 1555 { 1556 boolean found = false; 1557 for (DN dn : newBaseDNs) 1558 { 1559 if (dn.equals(baseDN)) 1560 { 1561 found = true; 1562 } 1563 } 1564 if (!found) 1565 { 1566 // The base DN was deleted. 1567 DirectoryServer.deregisterBaseDN(baseDN); 1568 EntryContainer ec = 1569 rootContainer.unregisterEntryContainer(baseDN); 1570 ec.delete(); 1571 } 1572 } 1573 1574 for (DN baseDN : newBaseDNs) 1575 { 1576 if (!rootContainer.getBaseDNs().contains(baseDN)) 1577 { 1578 try 1579 { 1580 // The base DN was added. 1581 EntryContainer ec = 1582 rootContainer.openEntryContainer(baseDN, null); 1583 rootContainer.registerEntryContainer(baseDN, ec); 1584 DirectoryServer.registerBaseDN(baseDN, this, false); 1585 } 1586 catch (Exception e) 1587 { 1588 if (debugEnabled()) 1589 { 1590 TRACER.debugCaught(DebugLogLevel.ERROR, e); 1591 } 1592 1593 resultCode = DirectoryServer.getServerErrorResultCode(); 1594 1595 1596 messages.add(ERR_BACKEND_CANNOT_REGISTER_BASEDN.get( 1597 String.valueOf(baseDN), 1598 String.valueOf(e))); 1599 ccr = new ConfigChangeResult(resultCode, false, messages); 1600 return ccr; 1601 } 1602 } 1603 } 1604 1605 baseDNs = newBaseDNs; 1606 } 1607 // Put the new configuration in place. 1608 this.cfg = newCfg; 1609 } 1610 catch (Exception e) 1611 { 1612 messages.add(Message.raw(stackTraceToSingleLineString(e))); 1613 ccr = new ConfigChangeResult(DirectoryServer.getServerErrorResultCode(), 1614 false, messages); 1615 return ccr; 1616 } 1617 1618 ccr = new ConfigChangeResult(resultCode, false, messages); 1619 return ccr; 1620 } 1621 1622 /** 1623 * Returns a handle to the JE root container currently used by this backend. 1624 * The rootContainer could be NULL if the backend is not initialized. 1625 * 1626 * @return The RootContainer object currently used by this backend. 1627 */ 1628 public RootContainer getRootContainer() 1629 { 1630 return rootContainer; 1631 } 1632 1633 /** 1634 * Returns a new read-only handle to the JE root container for this backend. 1635 * The caller is responsible for closing the root container after use. 1636 * 1637 * @return The read-only RootContainer object for this backend. 1638 * 1639 * @throws ConfigException If an unrecoverable problem arises during 1640 * initialization. 1641 * @throws InitializationException If a problem occurs during initialization 1642 * that is not related to the server 1643 * configuration. 1644 */ 1645 public RootContainer getReadOnlyRootContainer() 1646 throws ConfigException, InitializationException 1647 { 1648 EnvironmentConfig envConfig = 1649 ConfigurableEnvironment.parseConfigEntry(cfg); 1650 1651 envConfig.setReadOnly(true); 1652 envConfig.setAllowCreate(false); 1653 envConfig.setTransactional(false); 1654 envConfig.setTxnNoSync(false); 1655 envConfig.setConfigParam("je.env.isLocking", "true"); 1656 envConfig.setConfigParam("je.env.runCheckpointer", "true"); 1657 1658 return initializeRootContainer(envConfig); 1659 } 1660 1661 /** 1662 * Clears all the entries from the backend. This method is for test cases 1663 * that use the JE backend. 1664 * 1665 * @throws ConfigException If an unrecoverable problem arises in the 1666 * process of performing the initialization. 1667 * 1668 * @throws JebException If an error occurs while removing the data. 1669 */ 1670 public void clearBackend() 1671 throws ConfigException, JebException 1672 { 1673 // Determine the backend database directory. 1674 File parentDirectory = getFileForPath(cfg.getDBDirectory()); 1675 File backendDirectory = new File(parentDirectory, cfg.getBackendId()); 1676 EnvManager.removeFiles(backendDirectory.getPath()); 1677 } 1678 1679 /** 1680 * Creates a customized DirectoryException from the DatabaseException thrown 1681 * by JE backend. 1682 * 1683 * @param e The DatabaseException to be converted. 1684 * @return DirectoryException created from exception. 1685 */ 1686 DirectoryException createDirectoryException(DatabaseException e) 1687 { 1688 ResultCode resultCode = DirectoryServer.getServerErrorResultCode(); 1689 Message message = null; 1690 if(e instanceof RunRecoveryException) 1691 { 1692 message = NOTE_BACKEND_ENVIRONMENT_UNUSABLE.get(getBackendID()); 1693 logError(message); 1694 DirectoryServer.sendAlertNotification(DirectoryServer.getInstance(), 1695 ALERT_TYPE_BACKEND_ENVIRONMENT_UNUSABLE, message); 1696 } 1697 1698 String jeMessage = e.getMessage(); 1699 if (jeMessage == null) 1700 { 1701 jeMessage = stackTraceToSingleLineString(e); 1702 } 1703 message = ERR_JEB_DATABASE_EXCEPTION.get(jeMessage); 1704 return new DirectoryException(resultCode, message, e); 1705 } 1706 1707 /** 1708 * {@inheritDoc} 1709 */ 1710 public String getClassName() 1711 { 1712 return CLASS_NAME; 1713 } 1714 1715 /** 1716 * {@inheritDoc} 1717 */ 1718 public LinkedHashMap<String,String> getAlerts() 1719 { 1720 LinkedHashMap<String,String> alerts = new LinkedHashMap<String,String>(); 1721 1722 alerts.put(ALERT_TYPE_BACKEND_ENVIRONMENT_UNUSABLE, 1723 ALERT_DESCRIPTION_BACKEND_ENVIRONMENT_UNUSABLE); 1724 return alerts; 1725 } 1726 1727 /** 1728 * {@inheritDoc} 1729 */ 1730 public DN getComponentEntryDN() 1731 { 1732 return cfg.dn(); 1733 } 1734 1735 private RootContainer initializeRootContainer(EnvironmentConfig envConfig) 1736 throws ConfigException, InitializationException 1737 { 1738 // Open the database environment 1739 try 1740 { 1741 RootContainer rc = new RootContainer(this, cfg); 1742 rc.open(envConfig); 1743 return rc; 1744 } 1745 catch (DatabaseException e) 1746 { 1747 if (debugEnabled()) 1748 { 1749 TRACER.debugCaught(DebugLogLevel.ERROR, e); 1750 } 1751 Message message = ERR_JEB_OPEN_ENV_FAIL.get(e.getMessage()); 1752 throw new InitializationException(message, e); 1753 } 1754 } 1755 1756 /** 1757 * {@inheritDoc} 1758 */ 1759 public void preloadEntryCache() throws 1760 UnsupportedOperationException 1761 { 1762 EntryCachePreloader preloader = 1763 new EntryCachePreloader(this); 1764 preloader.preload(); 1765 } 1766 }