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 }