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.tasks;
028 import org.opends.messages.Message;
029 import org.opends.messages.TaskMessages;
030
031 import static org.opends.messages.TaskMessages.*;
032 import static org.opends.messages.ToolMessages.*;
033 import static org.opends.server.loggers.debug.DebugLogger.*;
034 import org.opends.server.loggers.debug.DebugTracer;
035 import org.opends.server.types.DebugLogLevel;
036 import static org.opends.server.util.StaticUtils.*;
037 import static org.opends.server.config.ConfigConstants.*;
038 import static org.opends.server.core.DirectoryServer.getAttributeType;
039
040 import org.opends.server.backends.task.Task;
041 import org.opends.server.backends.task.TaskState;
042 import org.opends.server.core.DirectoryServer;
043 import org.opends.server.core.LockFileManager;
044 import org.opends.server.api.Backend;
045 import org.opends.server.api.ClientConnection;
046 import org.opends.server.types.Attribute;
047 import org.opends.server.types.AttributeType;
048 import org.opends.server.types.DirectoryException;
049 import org.opends.server.types.DN;
050 import org.opends.server.types.Entry;
051
052
053 import org.opends.server.types.ExistingFileBehavior;
054 import org.opends.server.types.LDIFImportConfig;
055 import org.opends.server.types.Operation;
056 import org.opends.server.types.Privilege;
057 import org.opends.server.types.ResultCode;
058 import org.opends.server.types.SearchFilter;
059
060 import java.util.HashSet;
061 import java.util.ArrayList;
062 import java.util.List;
063 import java.util.Map;
064 import java.util.HashMap;
065
066 /**
067 * This class provides an implementation of a Directory Server task that can
068 * be used to import data from an LDIF file into a backend.
069 */
070 public class ImportTask extends Task
071 {
072 /**
073 * The tracer object for the debug logger.
074 */
075 private static final DebugTracer TRACER = getTracer();
076
077
078 /**
079 * Stores mapping between configuration attribute name and its label.
080 */
081 static private Map<String,Message> argDisplayMap =
082 new HashMap<String,Message>();
083
084 static {
085 argDisplayMap.put(
086 ATTR_IMPORT_LDIF_FILE,
087 INFO_IMPORT_ARG_LDIF_FILE.get());
088
089 argDisplayMap.put(
090 ATTR_IMPORT_APPEND,
091 INFO_IMPORT_ARG_APPEND.get());
092
093 argDisplayMap.put(
094 ATTR_IMPORT_REPLACE_EXISTING,
095 INFO_IMPORT_ARG_REPLACE_EXISTING.get());
096
097 argDisplayMap.put(
098 ATTR_IMPORT_BACKEND_ID,
099 INFO_IMPORT_ARG_BACKEND_ID.get());
100
101 argDisplayMap.put(
102 ATTR_IMPORT_INCLUDE_BRANCH,
103 INFO_IMPORT_ARG_INCL_BRANCH.get());
104
105 argDisplayMap.put(
106 ATTR_IMPORT_EXCLUDE_BRANCH,
107 INFO_IMPORT_ARG_EXCL_BRANCH.get());
108
109 argDisplayMap.put(
110 ATTR_IMPORT_INCLUDE_ATTRIBUTE,
111 INFO_IMPORT_ARG_INCL_ATTR.get());
112
113 argDisplayMap.put(
114 ATTR_IMPORT_EXCLUDE_ATTRIBUTE,
115 INFO_IMPORT_ARG_EXCL_ATTR.get());
116
117 argDisplayMap.put(
118 ATTR_IMPORT_INCLUDE_FILTER,
119 INFO_IMPORT_ARG_INCL_FILTER.get());
120
121 argDisplayMap.put(
122 ATTR_IMPORT_EXCLUDE_FILTER,
123 INFO_IMPORT_ARG_EXCL_FILTER.get());
124
125 argDisplayMap.put(
126 ATTR_IMPORT_REJECT_FILE,
127 INFO_IMPORT_ARG_REJECT_FILE.get());
128
129 argDisplayMap.put(
130 ATTR_IMPORT_SKIP_FILE,
131 INFO_IMPORT_ARG_SKIP_FILE.get());
132
133 argDisplayMap.put(
134 ATTR_IMPORT_OVERWRITE,
135 INFO_IMPORT_ARG_OVERWRITE.get());
136
137 argDisplayMap.put(
138 ATTR_IMPORT_SKIP_SCHEMA_VALIDATION,
139 INFO_IMPORT_ARG_SKIP_SCHEMA_VALIDATION.get());
140
141 argDisplayMap.put(
142 ATTR_IMPORT_IS_COMPRESSED,
143 INFO_IMPORT_ARG_IS_COMPRESSED.get());
144
145 argDisplayMap.put(
146 ATTR_IMPORT_IS_ENCRYPTED,
147 INFO_IMPORT_ARG_IS_ENCRYPTED.get());
148
149 argDisplayMap.put(
150 ATTR_IMPORT_CLEAR_BACKEND,
151 INFO_IMPORT_ARG_CLEAR_BACKEND.get());
152 }
153
154
155 boolean append = false;
156 boolean isCompressed = false;
157 boolean isEncrypted = false;
158 boolean overwrite = false;
159 boolean replaceExisting = false;
160 boolean skipSchemaValidation = false;
161 boolean clearBackend = false;
162 String backendID = null;
163 String rejectFile = null;
164 String skipFile = null;
165 ArrayList<String> excludeAttributeStrings = null;
166 ArrayList<String> excludeBranchStrings = null;
167 ArrayList<String> excludeFilterStrings = null;
168 ArrayList<String> includeAttributeStrings = null;
169 ArrayList<String> includeBranchStrings = null;
170 ArrayList<String> includeFilterStrings = null;
171 ArrayList<String> ldifFiles = null;
172
173 private LDIFImportConfig importConfig;
174
175 /**
176 * {@inheritDoc}
177 */
178 public Message getDisplayName() {
179 return INFO_TASK_IMPORT_NAME.get();
180 }
181
182 /**
183 * {@inheritDoc}
184 */
185 public Message getAttributeDisplayName(String name) {
186 return argDisplayMap.get(name);
187 }
188
189 /**
190 * {@inheritDoc}
191 */
192 @Override public void initializeTask() throws DirectoryException
193 {
194 // If the client connection is available, then make sure the associated
195 // client has the LDIF_IMPORT privilege.
196 Operation operation = getOperation();
197 if (operation != null)
198 {
199 ClientConnection clientConnection = operation.getClientConnection();
200 if (! clientConnection.hasPrivilege(Privilege.LDIF_IMPORT, operation))
201 {
202 Message message = ERR_TASK_LDIFIMPORT_INSUFFICIENT_PRIVILEGES.get();
203 throw new DirectoryException(ResultCode.INSUFFICIENT_ACCESS_RIGHTS,
204 message);
205 }
206 }
207
208
209 Entry taskEntry = getTaskEntry();
210
211 AttributeType typeLdifFile;
212 AttributeType typeAppend;
213 AttributeType typeReplaceExisting;
214 AttributeType typeBackendID;
215 AttributeType typeIncludeBranch;
216 AttributeType typeExcludeBranch;
217 AttributeType typeIncludeAttribute;
218 AttributeType typeExcludeAttribute;
219 AttributeType typeIncludeFilter;
220 AttributeType typeExcludeFilter;
221 AttributeType typeRejectFile;
222 AttributeType typeSkipFile;
223 AttributeType typeOverwrite;
224 AttributeType typeSkipSchemaValidation;
225 AttributeType typeIsCompressed;
226 AttributeType typeIsEncrypted;
227 AttributeType typeClearBackend;
228
229 typeLdifFile =
230 getAttributeType(ATTR_IMPORT_LDIF_FILE, true);
231 typeAppend =
232 getAttributeType(ATTR_IMPORT_APPEND, true);
233 typeReplaceExisting =
234 getAttributeType(ATTR_IMPORT_REPLACE_EXISTING, true);
235 typeBackendID =
236 getAttributeType(ATTR_IMPORT_BACKEND_ID, true);
237 typeIncludeBranch =
238 getAttributeType(ATTR_IMPORT_INCLUDE_BRANCH, true);
239 typeExcludeBranch =
240 getAttributeType(ATTR_IMPORT_EXCLUDE_BRANCH, true);
241 typeIncludeAttribute =
242 getAttributeType(ATTR_IMPORT_INCLUDE_ATTRIBUTE, true);
243 typeExcludeAttribute =
244 getAttributeType(ATTR_IMPORT_EXCLUDE_ATTRIBUTE, true);
245 typeIncludeFilter =
246 getAttributeType(ATTR_IMPORT_INCLUDE_FILTER, true);
247 typeExcludeFilter =
248 getAttributeType(ATTR_IMPORT_EXCLUDE_FILTER, true);
249 typeRejectFile =
250 getAttributeType(ATTR_IMPORT_REJECT_FILE, true);
251 typeSkipFile =
252 getAttributeType(ATTR_IMPORT_SKIP_FILE, true);
253 typeOverwrite =
254 getAttributeType(ATTR_IMPORT_OVERWRITE, true);
255 typeSkipSchemaValidation =
256 getAttributeType(ATTR_IMPORT_SKIP_SCHEMA_VALIDATION, true);
257 typeIsCompressed =
258 getAttributeType(ATTR_IMPORT_IS_COMPRESSED, true);
259 typeIsEncrypted =
260 getAttributeType(ATTR_IMPORT_IS_ENCRYPTED, true);
261 typeClearBackend =
262 getAttributeType(ATTR_IMPORT_CLEAR_BACKEND, true);
263
264 List<Attribute> attrList;
265
266 attrList = taskEntry.getAttribute(typeLdifFile);
267 ldifFiles = TaskUtils.getMultiValueString(attrList);
268
269 attrList = taskEntry.getAttribute(typeAppend);
270 append = TaskUtils.getBoolean(attrList, false);
271
272 attrList = taskEntry.getAttribute(typeReplaceExisting);
273 replaceExisting = TaskUtils.getBoolean(attrList, false);
274
275 attrList = taskEntry.getAttribute(typeBackendID);
276 backendID = TaskUtils.getSingleValueString(attrList);
277
278 attrList = taskEntry.getAttribute(typeIncludeBranch);
279 includeBranchStrings = TaskUtils.getMultiValueString(attrList);
280
281 attrList = taskEntry.getAttribute(typeExcludeBranch);
282 excludeBranchStrings = TaskUtils.getMultiValueString(attrList);
283
284 attrList = taskEntry.getAttribute(typeIncludeAttribute);
285 includeAttributeStrings = TaskUtils.getMultiValueString(attrList);
286
287 attrList = taskEntry.getAttribute(typeExcludeAttribute);
288 excludeAttributeStrings = TaskUtils.getMultiValueString(attrList);
289
290 attrList = taskEntry.getAttribute(typeIncludeFilter);
291 includeFilterStrings = TaskUtils.getMultiValueString(attrList);
292
293 attrList = taskEntry.getAttribute(typeExcludeFilter);
294 excludeFilterStrings = TaskUtils.getMultiValueString(attrList);
295
296 attrList = taskEntry.getAttribute(typeRejectFile);
297 rejectFile = TaskUtils.getSingleValueString(attrList);
298
299 attrList = taskEntry.getAttribute(typeSkipFile);
300 skipFile = TaskUtils.getSingleValueString(attrList);
301
302 attrList = taskEntry.getAttribute(typeOverwrite);
303 overwrite = TaskUtils.getBoolean(attrList, false);
304
305 attrList = taskEntry.getAttribute(typeSkipSchemaValidation);
306 skipSchemaValidation = TaskUtils.getBoolean(attrList, false);
307
308 attrList = taskEntry.getAttribute(typeIsCompressed);
309 isCompressed = TaskUtils.getBoolean(attrList, false);
310
311 attrList = taskEntry.getAttribute(typeIsEncrypted);
312 isEncrypted = TaskUtils.getBoolean(attrList, false);
313
314 attrList = taskEntry.getAttribute(typeClearBackend);
315 clearBackend = TaskUtils.getBoolean(attrList, false);
316
317 // Make sure that either the "includeBranchStrings" argument or the
318 // "backendID" argument was provided.
319 if(includeBranchStrings.isEmpty() && backendID == null)
320 {
321 Message message = ERR_LDIFIMPORT_MISSING_BACKEND_ARGUMENT.get(
322 typeIncludeBranch.getNameOrOID(), typeBackendID.getNameOrOID());
323 throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message);
324 }
325
326 Backend backend = null;
327 ArrayList<DN> defaultIncludeBranches;
328 ArrayList<DN> excludeBranches =
329 new ArrayList<DN>(excludeBranchStrings.size());
330 ArrayList<DN> includeBranches =
331 new ArrayList<DN>(includeBranchStrings.size());
332
333 for (String s : includeBranchStrings)
334 {
335 DN includeBranch;
336 try
337 {
338 includeBranch = DN.decode(s);
339 }
340 catch (DirectoryException de)
341 {
342 Message message = ERR_LDIFIMPORT_CANNOT_DECODE_INCLUDE_BASE.get(
343 s, de.getMessageObject());
344 throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message);
345 }
346 catch (Exception e)
347 {
348 Message message = ERR_LDIFIMPORT_CANNOT_DECODE_INCLUDE_BASE.get(
349 s, getExceptionMessage(e));
350 throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message);
351 }
352
353 if(! includeBranches.contains(includeBranch))
354 {
355 includeBranches.add(includeBranch);
356 }
357 }
358 for (String s : excludeBranchStrings)
359 {
360 DN excludeBranch;
361 try
362 {
363 excludeBranch = DN.decode(s);
364 }
365 catch (DirectoryException de)
366 {
367 Message message = ERR_LDIFIMPORT_CANNOT_DECODE_EXCLUDE_BASE.get(
368 s, de.getMessageObject());
369 throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message);
370 }
371 catch (Exception e)
372 {
373 Message message = ERR_LDIFIMPORT_CANNOT_DECODE_EXCLUDE_BASE.get(
374 s, getExceptionMessage(e));
375 throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message);
376 }
377
378 if (! excludeBranches.contains(excludeBranch))
379 {
380 excludeBranches.add(excludeBranch);
381 }
382 }
383
384 for (String filterString : excludeFilterStrings)
385 {
386 try
387 {
388 SearchFilter.createFilterFromString(filterString);
389 }
390 catch (DirectoryException de)
391 {
392 Message message = ERR_LDIFIMPORT_CANNOT_PARSE_EXCLUDE_FILTER.get(
393 filterString, de.getMessageObject());
394 throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message);
395 }
396 }
397
398 for (String filterString : includeFilterStrings)
399 {
400 try
401 {
402 SearchFilter.createFilterFromString(filterString);
403 }
404 catch (DirectoryException de)
405 {
406 Message message = ERR_LDIFIMPORT_CANNOT_PARSE_INCLUDE_FILTER.get(
407 filterString, de.getMessageObject());
408 throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message);
409 }
410 }
411
412 if(backendID != null)
413 {
414 backend = DirectoryServer.getBackend(backendID);
415 if (backend == null)
416 {
417 Message message = ERR_LDIFIMPORT_NO_BACKENDS_FOR_ID.get();
418 throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message);
419 }
420 else if (! backend.supportsLDIFImport())
421 {
422 Message message = ERR_LDIFIMPORT_CANNOT_IMPORT.get(backendID);
423 throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message);
424 }
425 // Make sure that if the "backendID" argument was provided, no include
426 // base was included, and the "append" ption was not provided, the
427 // "clearBackend" argument was also provided if there are more then one
428 // baseDNs for the backend being imported.
429 else if(!append && includeBranchStrings.isEmpty() &&
430 backend.getBaseDNs().length > 1 && !clearBackend)
431 {
432 StringBuilder builder = new StringBuilder();
433 for(DN dn : backend.getBaseDNs())
434 {
435 builder.append(dn.toNormalizedString());
436 builder.append(" ");
437 }
438 Message message = ERR_LDIFIMPORT_MISSING_CLEAR_BACKEND.get(
439 builder.toString(), typeClearBackend.getNameOrOID());
440 throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message);
441 }
442 }
443 else
444 {
445 // Find the backend that includes all the branches.
446 for(DN includeBranch : includeBranches)
447 {
448 Backend locatedBackend = DirectoryServer.getBackend(includeBranch);
449 if(locatedBackend != null)
450 {
451 if(backend == null)
452 {
453 backend = locatedBackend;
454 }
455 else if(backend != locatedBackend)
456 {
457 // The include branches span across multiple backends.
458 Message message = ERR_LDIFIMPORT_INVALID_INCLUDE_BASE.get(
459 includeBranch.toNormalizedString(), backend.getBackendID());
460 throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM,
461 message);
462 }
463 }
464 }
465 }
466
467 // Make sure the selected backend will handle all the include branches
468 defaultIncludeBranches = new ArrayList<DN>(backend.getBaseDNs().length);
469 for (DN dn : backend.getBaseDNs())
470 {
471 defaultIncludeBranches.add(dn);
472 }
473
474 for(DN includeBranch : includeBranches)
475 {
476 if (! Backend.handlesEntry(includeBranch, defaultIncludeBranches,
477 excludeBranches))
478 {
479 Message message = ERR_LDIFIMPORT_INVALID_INCLUDE_BASE.get(
480 includeBranch.toNormalizedString(), backend.getBackendID());
481 throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message);
482 }
483 }
484 }
485
486
487 /**
488 * {@inheritDoc}
489 */
490 public void interruptTask(TaskState interruptState, Message interruptReason)
491 {
492 if (TaskState.STOPPED_BY_ADMINISTRATOR.equals(interruptState) &&
493 importConfig != null)
494 {
495 addLogMessage(TaskMessages.INFO_TASK_STOPPED_BY_ADMIN.get(
496 interruptReason));
497 setTaskInterruptState(interruptState);
498 importConfig.cancel();
499 }
500 }
501
502
503 /**
504 * {@inheritDoc}
505 */
506 public boolean isInterruptable()
507 {
508 return true;
509 }
510
511
512 /**
513 * {@inheritDoc}
514 */
515 protected TaskState runTask()
516 {
517 // See if there were any user-defined sets of include/exclude attributes or
518 // filters. If so, then process them.
519 HashSet<AttributeType> excludeAttributes =
520 new HashSet<AttributeType>(excludeAttributeStrings.size());
521 for (String attrName : excludeAttributeStrings)
522 {
523 String lowerName = attrName.toLowerCase();
524 AttributeType attrType = DirectoryServer.getAttributeType(lowerName);
525 if (attrType == null)
526 {
527 attrType = DirectoryServer.getDefaultAttributeType(attrName);
528 }
529
530 excludeAttributes.add(attrType);
531 }
532
533 HashSet<AttributeType> includeAttributes =
534 new HashSet<AttributeType>(includeAttributeStrings.size());
535 for (String attrName : includeAttributeStrings)
536 {
537 String lowerName = attrName.toLowerCase();
538 AttributeType attrType = DirectoryServer.getAttributeType(lowerName);
539 if (attrType == null)
540 {
541 attrType = DirectoryServer.getDefaultAttributeType(attrName);
542 }
543
544 includeAttributes.add(attrType);
545 }
546
547 ArrayList<SearchFilter> excludeFilters =
548 new ArrayList<SearchFilter>(excludeFilterStrings.size());
549 for (String filterString : excludeFilterStrings)
550 {
551 try
552 {
553 excludeFilters.add(SearchFilter.createFilterFromString(filterString));
554 }
555 catch (DirectoryException de)
556 {
557 Message message = ERR_LDIFIMPORT_CANNOT_PARSE_EXCLUDE_FILTER.get(
558 filterString, de.getMessageObject());
559 logError(message);
560 return TaskState.STOPPED_BY_ERROR;
561 }
562 }
563
564 ArrayList<SearchFilter> includeFilters =
565 new ArrayList<SearchFilter>(includeFilterStrings.size());
566 for (String filterString : includeFilterStrings)
567 {
568 try
569 {
570 includeFilters.add(SearchFilter.createFilterFromString(filterString));
571 }
572 catch (DirectoryException de)
573 {
574 Message message = ERR_LDIFIMPORT_CANNOT_PARSE_INCLUDE_FILTER.get(
575 filterString, de.getMessageObject());
576 logError(message);
577 return TaskState.STOPPED_BY_ERROR;
578 }
579 }
580
581
582 // Get the backend into which the LDIF should be imported.
583 Backend backend = null;
584 ArrayList<DN> defaultIncludeBranches;
585 ArrayList<DN> excludeBranches =
586 new ArrayList<DN>(excludeBranchStrings.size());
587 ArrayList<DN> includeBranches =
588 new ArrayList<DN>(includeBranchStrings.size());
589
590 for (String s : includeBranchStrings)
591 {
592 DN includeBranch;
593 try
594 {
595 includeBranch = DN.decode(s);
596 }
597 catch (DirectoryException de)
598 {
599 Message message = ERR_LDIFIMPORT_CANNOT_DECODE_INCLUDE_BASE.get(
600 s, de.getMessageObject());
601 logError(message);
602 return TaskState.STOPPED_BY_ERROR;
603 }
604 catch (Exception e)
605 {
606 Message message = ERR_LDIFIMPORT_CANNOT_DECODE_INCLUDE_BASE.get(
607 s, getExceptionMessage(e));
608 logError(message);
609 return TaskState.STOPPED_BY_ERROR;
610 }
611
612 if(! includeBranches.contains(includeBranch))
613 {
614 includeBranches.add(includeBranch);
615 }
616 }
617
618 if(backendID != null)
619 {
620 backend = DirectoryServer.getBackend(backendID);
621
622 if (backend == null)
623 {
624 Message message = ERR_LDIFIMPORT_NO_BACKENDS_FOR_ID.get();
625 logError(message);
626 return TaskState.STOPPED_BY_ERROR;
627 }
628 else if (! backend.supportsLDIFImport())
629 {
630 Message message = ERR_LDIFIMPORT_CANNOT_IMPORT.get(backendID);
631 logError(message);
632 return TaskState.STOPPED_BY_ERROR;
633 }
634 // Make sure that if the "backendID" argument was provided, no include
635 // base was included, and the "append" ption was not provided, the
636 // "clearBackend" argument was also provided if there are more then one
637 // baseDNs for the backend being imported.
638 else if(!append && includeBranches.isEmpty() &&
639 backend.getBaseDNs().length > 1 && !clearBackend)
640 {
641 StringBuilder builder = new StringBuilder();
642 builder.append(backend.getBaseDNs()[0].toNormalizedString());
643 for(int i = 1; i < backend.getBaseDNs().length; i++)
644 {
645 builder.append(" / ");
646 builder.append(backend.getBaseDNs()[i].toNormalizedString());
647 }
648 Message message = ERR_LDIFIMPORT_MISSING_CLEAR_BACKEND.get(
649 builder.toString(), ATTR_IMPORT_CLEAR_BACKEND);
650 logError(message);
651 return TaskState.STOPPED_BY_ERROR;
652 }
653 }
654 else
655 {
656 // Find the backend that includes all the branches.
657 for(DN includeBranch : includeBranches)
658 {
659 Backend locatedBackend = DirectoryServer.getBackend(includeBranch);
660 if(locatedBackend != null)
661 {
662 if(backend == null)
663 {
664 backend = locatedBackend;
665 }
666 else if(backend != locatedBackend)
667 {
668 // The include branches span across multiple backends.
669 Message message = ERR_LDIFIMPORT_INVALID_INCLUDE_BASE.get(
670 includeBranch.toNormalizedString(), backend.getBackendID());
671 logError(message);
672 return TaskState.STOPPED_BY_ERROR;
673 }
674 }
675 }
676 }
677
678 // Find backends with subordinate base DNs that should be excluded from the
679 // import.
680
681 defaultIncludeBranches = new ArrayList<DN>(backend.getBaseDNs().length);
682 for (DN dn : backend.getBaseDNs())
683 {
684 defaultIncludeBranches.add(dn);
685 }
686
687 if (backend.getSubordinateBackends() != null)
688 {
689 for (Backend subBackend : backend.getSubordinateBackends())
690 {
691 for (DN baseDN : subBackend.getBaseDNs())
692 {
693 for (DN importBase : defaultIncludeBranches)
694 {
695 if (baseDN.isDescendantOf(importBase) &&
696 (! baseDN.equals(importBase)))
697 {
698 if (! excludeBranches.contains(baseDN))
699 {
700 excludeBranches.add(baseDN);
701 }
702
703 break;
704 }
705 }
706 }
707 }
708 }
709
710 for (String s : excludeBranchStrings)
711 {
712 DN excludeBranch;
713 try
714 {
715 excludeBranch = DN.decode(s);
716 }
717 catch (DirectoryException de)
718 {
719 Message message = ERR_LDIFIMPORT_CANNOT_DECODE_EXCLUDE_BASE.get(
720 s, de.getMessageObject());
721 logError(message);
722 return TaskState.STOPPED_BY_ERROR;
723 }
724 catch (Exception e)
725 {
726 Message message = ERR_LDIFIMPORT_CANNOT_DECODE_EXCLUDE_BASE.get(
727 s, getExceptionMessage(e));
728 logError(message);
729 return TaskState.STOPPED_BY_ERROR;
730 }
731
732 if (! excludeBranches.contains(excludeBranch))
733 {
734 excludeBranches.add(excludeBranch);
735 }
736 }
737
738 if (includeBranchStrings.isEmpty())
739 {
740 includeBranches = defaultIncludeBranches;
741 }
742 else
743 {
744 // Make sure the selected backend will handle all the include branches
745 for(DN includeBranch : includeBranches)
746 {
747 if (! Backend.handlesEntry(includeBranch, defaultIncludeBranches,
748 excludeBranches))
749 {
750 Message message = ERR_LDIFIMPORT_INVALID_INCLUDE_BASE.get(
751 includeBranch.toNormalizedString(), backend.getBackendID());
752 logError(message);
753 return TaskState.STOPPED_BY_ERROR;
754 }
755 }
756 }
757
758 // Create the LDIF import configuration to use when reading the LDIF.
759 ArrayList<String> fileList = new ArrayList<String>(ldifFiles);
760 importConfig = new LDIFImportConfig(fileList);
761 importConfig.setAppendToExistingData(append);
762 importConfig.setReplaceExistingEntries(replaceExisting);
763 importConfig.setCompressed(isCompressed);
764 importConfig.setEncrypted(isEncrypted);
765 importConfig.setClearBackend(clearBackend);
766 importConfig.setExcludeAttributes(excludeAttributes);
767 importConfig.setExcludeBranches(excludeBranches);
768 importConfig.setExcludeFilters(excludeFilters);
769 importConfig.setIncludeAttributes(includeAttributes);
770 importConfig.setIncludeBranches(includeBranches);
771 importConfig.setIncludeFilters(includeFilters);
772 importConfig.setValidateSchema(!skipSchemaValidation);
773
774 // FIXME -- Should this be conditional?
775 importConfig.setInvokeImportPlugins(true);
776
777 if (rejectFile != null)
778 {
779 try
780 {
781 ExistingFileBehavior existingBehavior;
782 if (overwrite)
783 {
784 existingBehavior = ExistingFileBehavior.OVERWRITE;
785 }
786 else
787 {
788 existingBehavior = ExistingFileBehavior.APPEND;
789 }
790
791 importConfig.writeRejectedEntries(rejectFile, existingBehavior);
792 }
793 catch (Exception e)
794 {
795 Message message = ERR_LDIFIMPORT_CANNOT_OPEN_REJECTS_FILE.get(
796 rejectFile, getExceptionMessage(e));
797 logError(message);
798 return TaskState.STOPPED_BY_ERROR;
799 }
800 }
801
802 if (skipFile != null)
803 {
804 try
805 {
806 ExistingFileBehavior existingBehavior;
807 if (overwrite)
808 {
809 existingBehavior = ExistingFileBehavior.OVERWRITE;
810 }
811 else
812 {
813 existingBehavior = ExistingFileBehavior.APPEND;
814 }
815
816 importConfig.writeRejectedEntries(skipFile, existingBehavior);
817 }
818 catch (Exception e)
819 {
820 Message message = ERR_LDIFIMPORT_CANNOT_OPEN_SKIP_FILE.get(
821 skipFile, getExceptionMessage(e));
822 logError(message);
823 return TaskState.STOPPED_BY_ERROR;
824 }
825 }
826
827 // Get the set of base DNs for the backend as an array.
828 DN[] baseDNs = new DN[defaultIncludeBranches.size()];
829 defaultIncludeBranches.toArray(baseDNs);
830
831 // Notify the task listeners that an import is going to start
832 // this must be done before disabling the backend to allow
833 // listeners to get access to the backend configuration
834 // and to take appropriate actions.
835 DirectoryServer.notifyImportBeginning(backend, importConfig);
836
837 // Disable the backend.
838 try
839 {
840 TaskUtils.disableBackend(backend.getBackendID());
841 }
842 catch (DirectoryException e)
843 {
844 if (debugEnabled())
845 {
846 TRACER.debugCaught(DebugLogLevel.ERROR, e);
847 }
848
849 logError(e.getMessageObject());
850 return TaskState.STOPPED_BY_ERROR;
851 }
852
853
854 try
855 {
856 // Acquire an exclusive lock for the backend.
857 try
858 {
859 String lockFile = LockFileManager.getBackendLockFileName(backend);
860 StringBuilder failureReason = new StringBuilder();
861 if (! LockFileManager.acquireExclusiveLock(lockFile, failureReason))
862 {
863 Message message = ERR_LDIFIMPORT_CANNOT_LOCK_BACKEND.get(
864 backend.getBackendID(), String.valueOf(failureReason));
865 logError(message);
866 return TaskState.STOPPED_BY_ERROR;
867 }
868 }
869 catch (Exception e)
870 {
871 if (debugEnabled())
872 {
873 TRACER.debugCaught(DebugLogLevel.ERROR, e);
874 }
875
876 Message message = ERR_LDIFIMPORT_CANNOT_LOCK_BACKEND.get(
877 backend.getBackendID(), getExceptionMessage(e));
878 logError(message);
879 return TaskState.STOPPED_BY_ERROR;
880 }
881
882
883 // Launch the import.
884 try
885 {
886 backend.importLDIF(importConfig);
887 }
888 catch (DirectoryException de)
889 {
890 if (debugEnabled())
891 {
892 TRACER.debugCaught(DebugLogLevel.ERROR, de);
893 }
894
895 DirectoryServer.notifyImportEnded(backend, importConfig, false);
896 Message message =
897 ERR_LDIFIMPORT_ERROR_DURING_IMPORT.get(de.getMessageObject());
898 logError(message);
899 return TaskState.STOPPED_BY_ERROR;
900 }
901 catch (Exception e)
902 {
903 if (debugEnabled())
904 {
905 TRACER.debugCaught(DebugLogLevel.ERROR, e);
906 }
907
908 DirectoryServer.notifyImportEnded(backend, importConfig, false);
909 Message message =
910 ERR_LDIFIMPORT_ERROR_DURING_IMPORT.get(getExceptionMessage(e));
911 logError(message);
912 return TaskState.STOPPED_BY_ERROR;
913 }
914 finally
915 {
916 // Release the exclusive lock on the backend.
917 try
918 {
919 String lockFile = LockFileManager.getBackendLockFileName(backend);
920 StringBuilder failureReason = new StringBuilder();
921 if (! LockFileManager.releaseLock(lockFile, failureReason))
922 {
923 Message message = WARN_LDIFIMPORT_CANNOT_UNLOCK_BACKEND.get(
924 backend.getBackendID(), String.valueOf(failureReason));
925 logError(message);
926 return TaskState.COMPLETED_WITH_ERRORS;
927 }
928 }
929 catch (Exception e)
930 {
931 if (debugEnabled())
932 {
933 TRACER.debugCaught(DebugLogLevel.ERROR, e);
934 }
935
936 Message message = WARN_LDIFIMPORT_CANNOT_UNLOCK_BACKEND.get(
937 backend.getBackendID(), getExceptionMessage(e));
938 logError(message);
939 return TaskState.COMPLETED_WITH_ERRORS;
940 }
941
942 }
943 }
944 finally
945 {
946 // Enable the backend.
947 try
948 {
949 TaskUtils.enableBackend(backend.getBackendID());
950 // It is necessary to retrieve the backend structure again
951 // because disabling and enabling it again may have resulted
952 // in a new backend being registered to the server.
953 backend = DirectoryServer.getBackend(backend.getBackendID());
954 }
955 catch (DirectoryException e)
956 {
957 if (debugEnabled())
958 {
959 TRACER.debugCaught(DebugLogLevel.ERROR, e);
960 }
961
962 logError(e.getMessageObject());
963 return TaskState.STOPPED_BY_ERROR;
964 }
965 DirectoryServer.notifyImportEnded(backend, importConfig, true);
966 }
967
968
969 // Clean up after the import by closing the import config.
970 importConfig.close();
971 return getFinalTaskState();
972 }
973 }