001 /*
002 * CDDL HEADER START
003 *
004 * The contents of this file are subject to the terms of the
005 * Common Development and Distribution License, Version 1.0 only
006 * (the "License"). You may not use this file except in compliance
007 * with the License.
008 *
009 * You can obtain a copy of the license at
010 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
011 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
012 * See the License for the specific language governing permissions
013 * and limitations under the License.
014 *
015 * When distributing Covered Code, include this CDDL HEADER in each
016 * file and include the License file at
017 * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable,
018 * add the following below this CDDL HEADER, with the fields enclosed
019 * by brackets "[]" replaced with your own identifying information:
020 * Portions Copyright [yyyy] [name of copyright owner]
021 *
022 * CDDL HEADER END
023 *
024 *
025 * Copyright 2006-2008 Sun Microsystems, Inc.
026 */
027 package org.opends.server.tools;
028
029
030
031 import java.io.File;
032 import java.io.OutputStream;
033 import java.io.PrintStream;
034 import java.util.ArrayList;
035 import java.util.HashSet;
036 import java.util.List;
037 import java.util.Random;
038
039 import org.opends.server.admin.std.server.BackendCfg;
040 import org.opends.server.api.Backend;
041 import org.opends.server.api.ErrorLogPublisher;
042 import org.opends.server.api.DebugLogPublisher;
043 import org.opends.server.api.plugin.PluginType;
044 import org.opends.server.config.ConfigException;
045 import static org.opends.server.config.ConfigConstants.*;
046 import org.opends.server.core.CoreConfigManager;
047 import org.opends.server.core.DirectoryServer;
048 import org.opends.server.core.LockFileManager;
049 import org.opends.server.extensions.ConfigFileHandler;
050 import org.opends.server.loggers.TextWriter;
051 import org.opends.server.loggers.TextErrorLogPublisher;
052 import org.opends.server.loggers.ErrorLogger;
053 import org.opends.server.loggers.debug.TextDebugLogPublisher;
054 import org.opends.server.loggers.debug.DebugLogger;
055
056 import org.opends.server.tools.makeldif.TemplateFile;
057 import org.opends.server.types.AttributeType;
058 import org.opends.server.types.DirectoryException;
059 import org.opends.server.types.DN;
060 import org.opends.server.types.ExistingFileBehavior;
061 import org.opends.server.types.InitializationException;
062 import org.opends.server.types.LDIFImportConfig;
063 import org.opends.server.types.LDIFImportResult;
064 import org.opends.server.types.NullOutputStream;
065 import org.opends.server.types.SearchFilter;
066 import org.opends.server.types.RawAttribute;
067 import org.opends.server.util.args.ArgumentException;
068 import org.opends.server.util.args.BooleanArgument;
069 import org.opends.server.util.args.IntegerArgument;
070 import org.opends.server.util.args.StringArgument;
071 import org.opends.server.util.args.LDAPConnectionArgumentParser;
072
073 import static org.opends.server.loggers.ErrorLogger.*;
074 import static org.opends.messages.ToolMessages.*;
075 import org.opends.messages.Message;
076 import static org.opends.server.util.ServerConstants.*;
077 import static org.opends.server.util.StaticUtils.*;
078 import static org.opends.server.tools.ToolConstants.*;
079 import org.opends.server.tools.tasks.TaskTool;
080 import org.opends.server.tasks.ImportTask;
081 import org.opends.server.protocols.asn1.ASN1OctetString;
082 import org.opends.server.protocols.ldap.LDAPAttribute;
083
084
085 /**
086 * This program provides a utility that may be used to import the contents of an
087 * LDIF file into a Directory Server backend. This will be a process that is
088 * intended to run separate from Directory Server and not internally within the
089 * server process (e.g., via the tasks interface).
090 */
091 public class ImportLDIF extends TaskTool {
092 /**
093 * The buffer size that should be used when reading data from LDIF.
094 */
095 public static final int LDIF_BUFFER_SIZE = 1048576;
096
097
098 /**
099 * The main method for ImportLDIF tool.
100 *
101 * @param args The command-line arguments provided to this program.
102 */
103 public static void main(String[] args)
104 {
105 int retCode = mainImportLDIF(args, true, System.out, System.err);
106
107 if(retCode != 0)
108 {
109 System.exit(filterExitCode(retCode));
110 }
111 }
112
113 /**
114 * Processes the command-line arguments and invokes the import process.
115 *
116 * @param args The command-line arguments provided to thisprogram.
117 *
118 * @return The error code.
119 */
120 public static int mainImportLDIF(String[] args)
121 {
122 return mainImportLDIF(args, true, System.out, System.err);
123 }
124
125 /**
126 * Processes the command-line arguments and invokes the import process.
127 *
128 * @param args The command-line arguments provided to this
129 * program.
130 * @param initializeServer Indicates whether to initialize the server.
131 * @param outStream The output stream to use for standard output, or
132 * {@code null} if standard output is not needed.
133 * @param errStream The output stream to use for standard error, or
134 * {@code null} if standard error is not needed.
135 *
136 * @return The error code.
137 */
138 public static int mainImportLDIF(String[] args, boolean initializeServer,
139 OutputStream outStream,
140 OutputStream errStream)
141 {
142 ImportLDIF tool = new ImportLDIF();
143 return tool.process(args, initializeServer, outStream, errStream);
144 }
145
146 // Define the command-line arguments that may be used with this program.
147 private BooleanArgument append = null;
148 private BooleanArgument countRejects = null;
149 private BooleanArgument displayUsage = null;
150 private BooleanArgument isCompressed = null;
151 private BooleanArgument isEncrypted = null;
152 private BooleanArgument overwrite = null;
153 private BooleanArgument quietMode = null;
154 private BooleanArgument replaceExisting = null;
155 private BooleanArgument skipSchemaValidation = null;
156 private BooleanArgument clearBackend = null;
157 private IntegerArgument randomSeed = null;
158 private StringArgument backendID = null;
159 private StringArgument configClass = null;
160 private StringArgument configFile = null;
161 private StringArgument excludeAttributeStrings = null;
162 private StringArgument excludeBranchStrings = null;
163 private StringArgument excludeFilterStrings = null;
164 private StringArgument includeAttributeStrings = null;
165 private StringArgument includeBranchStrings = null;
166 private StringArgument includeFilterStrings = null;
167 private StringArgument ldifFiles = null;
168 private StringArgument rejectFile = null;
169 private StringArgument skipFile = null;
170 private StringArgument templateFile = null;
171
172 private int process(String[] args, boolean initializeServer,
173 OutputStream outStream, OutputStream errStream) {
174
175 PrintStream out;
176 if (outStream == null)
177 {
178 out = NullOutputStream.printStream();
179 }
180 else
181 {
182 out = new PrintStream(outStream);
183 }
184
185 PrintStream err;
186 if (errStream == null)
187 {
188 err = NullOutputStream.printStream();
189 }
190 else
191 {
192 err = new PrintStream(errStream);
193 }
194
195 // FIXME -- Need to add a mechanism for verifying the file signature.
196
197
198 // Create the command-line argument parser for use with this program.
199 LDAPConnectionArgumentParser argParser =
200 createArgParser("org.opends.server.tools.ImportLDIF",
201 INFO_LDIFIMPORT_TOOL_DESCRIPTION.get());
202
203 // Initialize all the command-line argument types and register them with the
204 // parser.
205 try
206 {
207 configClass =
208 new StringArgument("configclass", OPTION_SHORT_CONFIG_CLASS,
209 OPTION_LONG_CONFIG_CLASS, true, false,
210 true, INFO_CONFIGCLASS_PLACEHOLDER.get(),
211 ConfigFileHandler.class.getName(), null,
212 INFO_DESCRIPTION_CONFIG_CLASS.get());
213 configClass.setHidden(true);
214 argParser.addArgument(configClass);
215
216
217 configFile =
218 new StringArgument("configfile", 'f', "configFile", true, false,
219 true, INFO_CONFIGFILE_PLACEHOLDER.get(), null,
220 null,
221 INFO_DESCRIPTION_CONFIG_FILE.get());
222 configFile.setHidden(true);
223 argParser.addArgument(configFile);
224
225
226 ldifFiles =
227 new StringArgument("ldiffile", OPTION_SHORT_LDIF_FILE,
228 OPTION_LONG_LDIF_FILE, false, true, true,
229 INFO_LDIFFILE_PLACEHOLDER.get(), null, null,
230 INFO_LDIFIMPORT_DESCRIPTION_LDIF_FILE.get());
231 argParser.addArgument(ldifFiles);
232
233
234 templateFile =
235 new StringArgument("templatefile", 'A', "templateFile", false, false,
236 true, INFO_TEMPLATE_FILE_PLACEHOLDER.get(), null,
237 null,
238 INFO_LDIFIMPORT_DESCRIPTION_TEMPLATE_FILE.get());
239 argParser.addArgument(templateFile);
240
241
242 append =
243 new BooleanArgument("append", 'a', "append",
244 INFO_LDIFIMPORT_DESCRIPTION_APPEND.get());
245 argParser.addArgument(append);
246
247
248 replaceExisting =
249 new BooleanArgument(
250 "replaceexisting", 'r', "replaceExisting",
251 INFO_LDIFIMPORT_DESCRIPTION_REPLACE_EXISTING.get());
252 argParser.addArgument(replaceExisting);
253
254
255 backendID =
256 new StringArgument("backendid", 'n', "backendID", false, false, true,
257 INFO_BACKENDNAME_PLACEHOLDER.get(), null, null,
258 INFO_LDIFIMPORT_DESCRIPTION_BACKEND_ID.get());
259 argParser.addArgument(backendID);
260
261 clearBackend =
262 new BooleanArgument("clearbackend", 'F', "clearBackend",
263 INFO_LDIFIMPORT_DESCRIPTION_CLEAR_BACKEND.get());
264 argParser.addArgument(clearBackend);
265
266
267 includeBranchStrings =
268 new StringArgument("includebranch", 'b', "includeBranch", false,
269 true, true, INFO_BRANCH_DN_PLACEHOLDER.get(),
270 null, null,
271 INFO_LDIFIMPORT_DESCRIPTION_INCLUDE_BRANCH.get());
272 argParser.addArgument(includeBranchStrings);
273
274
275 excludeBranchStrings =
276 new StringArgument("excludebranch", 'B', "excludeBranch", false,
277 true, true, INFO_BRANCH_DN_PLACEHOLDER.get(),
278 null, null,
279 INFO_LDIFIMPORT_DESCRIPTION_EXCLUDE_BRANCH.get());
280 argParser.addArgument(excludeBranchStrings);
281
282
283 includeAttributeStrings =
284 new StringArgument(
285 "includeattribute", 'i', "includeAttribute",
286 false, true, true, INFO_ATTRIBUTE_PLACEHOLDER.get(), null,
287 null,
288 INFO_LDIFIMPORT_DESCRIPTION_INCLUDE_ATTRIBUTE.get());
289 argParser.addArgument(includeAttributeStrings);
290
291
292 excludeAttributeStrings =
293 new StringArgument(
294 "excludeattribute", 'e', "excludeAttribute",
295 false, true, true, INFO_ATTRIBUTE_PLACEHOLDER.get(), null,
296 null,
297 INFO_LDIFIMPORT_DESCRIPTION_EXCLUDE_ATTRIBUTE.get());
298 argParser.addArgument(excludeAttributeStrings);
299
300
301 includeFilterStrings =
302 new StringArgument(
303 "includefilter", 'I', "includeFilter",
304 false, true, true, INFO_FILTER_PLACEHOLDER.get(), null, null,
305 INFO_LDIFIMPORT_DESCRIPTION_INCLUDE_FILTER.get());
306 argParser.addArgument(includeFilterStrings);
307
308
309 excludeFilterStrings =
310 new StringArgument("excludefilter", 'E', "excludeFilter",
311 false, true, true, INFO_FILTER_PLACEHOLDER.get(),
312 null, null,
313 INFO_LDIFIMPORT_DESCRIPTION_EXCLUDE_FILTER.get());
314 argParser.addArgument(excludeFilterStrings);
315
316
317 rejectFile =
318 new StringArgument("rejectfile", 'R', "rejectFile", false, false,
319 true, INFO_REJECT_FILE_PLACEHOLDER.get(), null,
320 null,
321 INFO_LDIFIMPORT_DESCRIPTION_REJECT_FILE.get());
322 argParser.addArgument(rejectFile);
323
324
325 skipFile =
326 new StringArgument("skipfile", null, "skipFile", false, false,
327 true, INFO_SKIP_FILE_PLACEHOLDER.get(), null,
328 null,
329 INFO_LDIFIMPORT_DESCRIPTION_SKIP_FILE.get());
330 argParser.addArgument(skipFile);
331
332
333 overwrite =
334 new BooleanArgument("overwrite", 'O', "overwrite",
335 INFO_LDIFIMPORT_DESCRIPTION_OVERWRITE.get());
336 argParser.addArgument(overwrite);
337
338
339 randomSeed =
340 new IntegerArgument("randomseed", OPTION_SHORT_RANDOM_SEED,
341 OPTION_LONG_RANDOM_SEED, false, false,
342 true, INFO_SEED_PLACEHOLDER.get(),
343 0, null, false, 0, false, 0,
344 INFO_LDIFIMPORT_DESCRIPTION_RANDOM_SEED.get());
345 argParser.addArgument(randomSeed);
346
347
348 skipSchemaValidation =
349 new BooleanArgument("skipschema", 'S', "skipSchemaValidation",
350 INFO_LDIFIMPORT_DESCRIPTION_SKIP_SCHEMA_VALIDATION.get());
351 argParser.addArgument(skipSchemaValidation);
352
353
354 countRejects =
355 new BooleanArgument("countrejects", null, "countRejects",
356 INFO_LDIFIMPORT_DESCRIPTION_COUNT_REJECTS.get());
357 argParser.addArgument(countRejects);
358
359
360 isCompressed =
361 new BooleanArgument("iscompressed", 'c', "isCompressed",
362 INFO_LDIFIMPORT_DESCRIPTION_IS_COMPRESSED.get());
363 argParser.addArgument(isCompressed);
364
365
366 isEncrypted =
367 new BooleanArgument("isencrypted", 'y', "isEncrypted",
368 INFO_LDIFIMPORT_DESCRIPTION_IS_ENCRYPTED.get());
369 isEncrypted.setHidden(true); //See issue #27
370 argParser.addArgument(isEncrypted);
371
372
373 quietMode = new BooleanArgument("quietmode", OPTION_SHORT_QUIET,
374 OPTION_LONG_QUIET,
375 INFO_LDIFIMPORT_DESCRIPTION_QUIET.get());
376 argParser.addArgument(quietMode);
377
378
379 displayUsage =
380 new BooleanArgument("help", OPTION_SHORT_HELP, OPTION_LONG_HELP,
381 INFO_DESCRIPTION_USAGE.get());
382 argParser.addArgument(displayUsage);
383 argParser.setUsageArgument(displayUsage);
384 }
385 catch (ArgumentException ae)
386 {
387 Message message = ERR_CANNOT_INITIALIZE_ARGS.get(ae.getMessage());
388
389 err.println(wrapText(message, MAX_LINE_WIDTH));
390 return 1;
391 }
392
393
394 // Parse the command-line arguments provided to this program.
395 try
396 {
397 argParser.parseArguments(args);
398 validateTaskArgs();
399 }
400 catch (ArgumentException ae)
401 {
402 Message message = ERR_ERROR_PARSING_ARGS.get(ae.getMessage());
403
404 err.println(wrapText(message, MAX_LINE_WIDTH));
405 err.println(argParser.getUsage());
406 return 1;
407 }
408
409
410 // If we should just display usage or version information,
411 // then print it and exit.
412 if (argParser.usageOrVersionDisplayed())
413 {
414 return 0;
415 }
416
417
418 // Make sure that either the "ldifFile" argument or the "templateFile"
419 // argument was provided, but not both.
420 if (ldifFiles.isPresent())
421 {
422 if (templateFile.isPresent())
423 {
424 Message message = ERR_LDIFIMPORT_CONFLICTING_OPTIONS.get(
425 ldifFiles.getLongIdentifier(),
426 templateFile.getLongIdentifier());
427 err.println(wrapText(message, MAX_LINE_WIDTH));
428 return 1;
429 }
430 }
431 else if (! templateFile.isPresent())
432 {
433 Message message = ERR_LDIFIMPORT_MISSING_REQUIRED_ARGUMENT.get(
434 ldifFiles.getLongIdentifier(),
435 templateFile.getLongIdentifier());
436 err.println(wrapText(message, MAX_LINE_WIDTH));
437 return 1;
438 }
439
440 // Make sure that either the "includeBranchStrings" argument or the
441 // "backendID" argument was provided.
442 if(!includeBranchStrings.isPresent() && !backendID.isPresent())
443 {
444 Message message = ERR_LDIFIMPORT_MISSING_BACKEND_ARGUMENT.get(
445 includeBranchStrings.getLongIdentifier(),
446 backendID.getLongIdentifier());
447 err.println(wrapText(message, MAX_LINE_WIDTH));
448 return 1;
449 }
450
451 // Don't write non-error messages to console if quite
452 if (quietMode.isPresent()) {
453 out = new PrintStream(NullOutputStream.instance());
454 }
455
456 return process(argParser, initializeServer, out, err);
457 }
458
459 /**
460 * {@inheritDoc}
461 */
462 public void addTaskAttributes(List<RawAttribute> attributes)
463 {
464 //
465 // Required attributes
466 //
467 ArrayList<ASN1OctetString> values;
468 List<String> fileList = ldifFiles.getValues();
469 if (fileList != null && fileList.size() > 0) {
470 values = new ArrayList<ASN1OctetString>(fileList.size());
471 for (String file : fileList) {
472 values.add(new ASN1OctetString(file));
473 }
474 attributes.add(new LDAPAttribute(ATTR_IMPORT_LDIF_FILE, values));
475 }
476
477 //
478 // Optional attributes
479 //
480 if (append.getValue() != null &&
481 !append.getValue().equals(append.getDefaultValue())) {
482 values = new ArrayList<ASN1OctetString>(1);
483 values.add(new ASN1OctetString(append.getValue()));
484 attributes.add(new LDAPAttribute(ATTR_IMPORT_APPEND, values));
485 }
486
487 if (replaceExisting.getValue() != null &&
488 !replaceExisting.getValue().equals(
489 replaceExisting.getDefaultValue())) {
490 values = new ArrayList<ASN1OctetString>(1);
491 values.add(new ASN1OctetString(replaceExisting.getValue()));
492 attributes.add(new LDAPAttribute(ATTR_IMPORT_REPLACE_EXISTING, values));
493 }
494
495 if (backendID.getValue() != null &&
496 !backendID.getValue().equals(
497 backendID.getDefaultValue())) {
498 values = new ArrayList<ASN1OctetString>(1);
499 values.add(new ASN1OctetString(backendID.getValue()));
500 attributes.add(new LDAPAttribute(ATTR_IMPORT_BACKEND_ID, values));
501 }
502
503 List<String> includeAttributes = includeAttributeStrings.getValues();
504 if (includeAttributes != null && includeAttributes.size() > 0) {
505 values = new ArrayList<ASN1OctetString>(includeAttributes.size());
506 for (String includeAttribute : includeAttributes) {
507 values.add(new ASN1OctetString(includeAttribute));
508 }
509 attributes.add(new LDAPAttribute(ATTR_IMPORT_INCLUDE_ATTRIBUTE, values));
510 }
511
512 List<String> excludeAttributes = excludeAttributeStrings.getValues();
513 if (excludeAttributes != null && excludeAttributes.size() > 0) {
514 values = new ArrayList<ASN1OctetString>(excludeAttributes.size());
515 for (String excludeAttribute : excludeAttributes) {
516 values.add(new ASN1OctetString(excludeAttribute));
517 }
518 attributes.add(new LDAPAttribute(ATTR_IMPORT_EXCLUDE_ATTRIBUTE, values));
519 }
520
521 List<String> includeFilters = includeFilterStrings.getValues();
522 if (includeFilters != null && includeFilters.size() > 0) {
523 values = new ArrayList<ASN1OctetString>(includeFilters.size());
524 for (String includeFilter : includeFilters) {
525 values.add(new ASN1OctetString(includeFilter));
526 }
527 attributes.add(new LDAPAttribute(ATTR_IMPORT_INCLUDE_FILTER, values));
528 }
529
530 List<String> excludeFilters = excludeFilterStrings.getValues();
531 if (excludeFilters != null && excludeFilters.size() > 0) {
532 values = new ArrayList<ASN1OctetString>(excludeFilters.size());
533 for (String excludeFilter : excludeFilters) {
534 values.add(new ASN1OctetString(excludeFilter));
535 }
536 attributes.add(new LDAPAttribute(ATTR_IMPORT_EXCLUDE_FILTER, values));
537 }
538
539 List<String> includeBranches = includeBranchStrings.getValues();
540 if (includeBranches != null && includeBranches.size() > 0) {
541 values = new ArrayList<ASN1OctetString>(includeBranches.size());
542 for (String includeBranche : includeBranches) {
543 values.add(new ASN1OctetString(includeBranche));
544 }
545 attributes.add(new LDAPAttribute(ATTR_IMPORT_INCLUDE_BRANCH, values));
546 }
547
548 List<String> excludeBranches = excludeBranchStrings.getValues();
549 if (excludeBranches != null && excludeBranches.size() > 0) {
550 values = new ArrayList<ASN1OctetString>(excludeBranches.size());
551 for (String excludeBranch : excludeBranches) {
552 values.add(new ASN1OctetString(excludeBranch));
553 }
554 attributes.add(new LDAPAttribute(ATTR_IMPORT_EXCLUDE_BRANCH, values));
555 }
556
557 if (rejectFile.getValue() != null &&
558 !rejectFile.getValue().equals(
559 rejectFile.getDefaultValue())) {
560 values = new ArrayList<ASN1OctetString>(1);
561 values.add(new ASN1OctetString(rejectFile.getValue()));
562 attributes.add(new LDAPAttribute(ATTR_IMPORT_REJECT_FILE, values));
563 }
564
565 if (skipFile.getValue() != null &&
566 !skipFile.getValue().equals(
567 skipFile.getDefaultValue())) {
568 values = new ArrayList<ASN1OctetString>(1);
569 values.add(new ASN1OctetString(skipFile.getValue()));
570 attributes.add(new LDAPAttribute(ATTR_IMPORT_SKIP_FILE, values));
571 }
572
573 if (overwrite.getValue() != null &&
574 !overwrite.getValue().equals(
575 overwrite.getDefaultValue())) {
576 values = new ArrayList<ASN1OctetString>(1);
577 values.add(new ASN1OctetString(overwrite.getValue()));
578 attributes.add(new LDAPAttribute(ATTR_IMPORT_OVERWRITE, values));
579 }
580
581 if (skipSchemaValidation.getValue() != null &&
582 !skipSchemaValidation.getValue().equals(
583 skipSchemaValidation.getDefaultValue())) {
584 values = new ArrayList<ASN1OctetString>(1);
585 values.add(new ASN1OctetString(skipSchemaValidation.getValue()));
586 attributes.add(
587 new LDAPAttribute(ATTR_IMPORT_SKIP_SCHEMA_VALIDATION, values));
588 }
589
590 if (isCompressed.getValue() != null &&
591 !isCompressed.getValue().equals(
592 isCompressed.getDefaultValue())) {
593 values = new ArrayList<ASN1OctetString>(1);
594 values.add(new ASN1OctetString(isCompressed.getValue()));
595 attributes.add(
596 new LDAPAttribute(ATTR_IMPORT_IS_COMPRESSED, values));
597 }
598
599 if (isEncrypted.getValue() != null &&
600 !isEncrypted.getValue().equals(
601 isEncrypted.getDefaultValue())) {
602 values = new ArrayList<ASN1OctetString>(1);
603 values.add(new ASN1OctetString(isEncrypted.getValue()));
604 attributes.add(
605 new LDAPAttribute(ATTR_IMPORT_IS_ENCRYPTED, values));
606 }
607
608 if (clearBackend.getValue() != null &&
609 !clearBackend.getValue().equals(
610 clearBackend.getDefaultValue())) {
611 values = new ArrayList<ASN1OctetString>(1);
612 values.add(new ASN1OctetString(clearBackend.getValue()));
613 attributes.add(
614 new LDAPAttribute(ATTR_IMPORT_CLEAR_BACKEND, values));
615 }
616
617 }
618
619 /**
620 * {@inheritDoc}
621 */
622 public String getTaskObjectclass() {
623 return "ds-task-import";
624 }
625
626 /**
627 * {@inheritDoc}
628 */
629 public Class getTaskClass() {
630 return ImportTask.class;
631 }
632
633 /**
634 * {@inheritDoc}
635 */
636 protected int processLocal(boolean initializeServer,
637 PrintStream out,
638 PrintStream err) {
639
640
641 // Perform the initial bootstrap of the Directory Server and process the
642 // configuration.
643 DirectoryServer directoryServer = DirectoryServer.getInstance();
644 if (initializeServer)
645 {
646 try
647 {
648 DirectoryServer.bootstrapClient();
649 DirectoryServer.initializeJMX();
650 }
651 catch (Exception e)
652 {
653 Message message = ERR_SERVER_BOOTSTRAP_ERROR.get(
654 getExceptionMessage(e));
655 err.println(wrapText(message, MAX_LINE_WIDTH));
656 return 1;
657 }
658
659 try
660 {
661 directoryServer.initializeConfiguration(configClass.getValue(),
662 configFile.getValue());
663 }
664 catch (InitializationException ie)
665 {
666 Message message = ERR_CANNOT_LOAD_CONFIG.get(ie.getMessage());
667 err.println(wrapText(message, MAX_LINE_WIDTH));
668 return 1;
669 }
670 catch (Exception e)
671 {
672 Message message = ERR_CANNOT_LOAD_CONFIG.get(getExceptionMessage(e));
673 err.println(wrapText(message, MAX_LINE_WIDTH));
674 return 1;
675 }
676
677
678
679 // Initialize the Directory Server schema elements.
680 try
681 {
682 directoryServer.initializeSchema();
683 }
684 catch (ConfigException ce)
685 {
686 Message message = ERR_CANNOT_LOAD_SCHEMA.get(ce.getMessage());
687 err.println(wrapText(message, MAX_LINE_WIDTH));
688 return 1;
689 }
690 catch (InitializationException ie)
691 {
692 Message message = ERR_CANNOT_LOAD_SCHEMA.get(ie.getMessage());
693 err.println(wrapText(message, MAX_LINE_WIDTH));
694 return 1;
695 }
696 catch (Exception e)
697 {
698 Message message = ERR_CANNOT_LOAD_SCHEMA.get(getExceptionMessage(e));
699 err.println(wrapText(message, MAX_LINE_WIDTH));
700 return 1;
701 }
702
703
704 // Initialize the Directory Server core configuration.
705 try
706 {
707 CoreConfigManager coreConfigManager = new CoreConfigManager();
708 coreConfigManager.initializeCoreConfig();
709 }
710 catch (ConfigException ce)
711 {
712 Message message = ERR_CANNOT_INITIALIZE_CORE_CONFIG.get(
713 ce.getMessage());
714 err.println(wrapText(message, MAX_LINE_WIDTH));
715 return 1;
716 }
717 catch (InitializationException ie)
718 {
719 Message message = ERR_CANNOT_INITIALIZE_CORE_CONFIG.get(
720 ie.getMessage());
721 err.println(wrapText(message, MAX_LINE_WIDTH));
722 return 1;
723 }
724 catch (Exception e)
725 {
726 Message message = ERR_CANNOT_INITIALIZE_CORE_CONFIG.get(
727 getExceptionMessage(e));
728 err.println(wrapText(message, MAX_LINE_WIDTH));
729 return 1;
730 }
731
732
733 // Initialize the Directory Server crypto manager.
734 try
735 {
736 directoryServer.initializeCryptoManager();
737 }
738 catch (ConfigException ce)
739 {
740 Message message = ERR_CANNOT_INITIALIZE_CRYPTO_MANAGER.get(
741 ce.getMessage());
742 err.println(wrapText(message, MAX_LINE_WIDTH));
743 return 1;
744 }
745 catch (InitializationException ie)
746 {
747 Message message = ERR_CANNOT_INITIALIZE_CRYPTO_MANAGER.get(
748 ie.getMessage());
749 err.println(wrapText(message, MAX_LINE_WIDTH));
750 return 1;
751 }
752 catch (Exception e)
753 {
754 Message message = ERR_CANNOT_INITIALIZE_CRYPTO_MANAGER.get(
755 getExceptionMessage(e));
756 err.println(wrapText(message, MAX_LINE_WIDTH));
757 return 1;
758 }
759
760
761 if (! quietMode.isPresent())
762 {
763 try
764 {
765 ErrorLogPublisher errorLogPublisher =
766 TextErrorLogPublisher.getStartupTextErrorPublisher(
767 new TextWriter.STREAM(out));
768 DebugLogPublisher debugLogPublisher =
769 TextDebugLogPublisher.getStartupTextDebugPublisher(
770 new TextWriter.STREAM(out));
771 ErrorLogger.addErrorLogPublisher(errorLogPublisher);
772 DebugLogger.addDebugLogPublisher(debugLogPublisher);
773 }
774 catch(Exception e)
775 {
776 err.println("Error installing the custom error logger: " +
777 stackTraceToSingleLineString(e));
778 }
779 }
780
781
782 // Initialize all the password policy information.
783 try
784 {
785 directoryServer.initializePasswordPolicyComponents();
786 }
787 catch (ConfigException ce)
788 {
789 Message message = ERR_LDIFIMPORT_CANNOT_INITIALIZE_PWPOLICY.get(
790 ce.getMessage());
791 err.println(wrapText(message, MAX_LINE_WIDTH));
792 return 1;
793 }
794 catch (InitializationException ie)
795 {
796 Message message = ERR_LDIFIMPORT_CANNOT_INITIALIZE_PWPOLICY.get(
797 ie.getMessage());
798 err.println(wrapText(message, MAX_LINE_WIDTH));
799 return 1;
800 }
801 catch (Exception e)
802 {
803 Message message = ERR_LDIFIMPORT_CANNOT_INITIALIZE_PWPOLICY.get(
804 getExceptionMessage(e));
805 err.println(wrapText(message, MAX_LINE_WIDTH));
806 return 1;
807 }
808
809
810 // Make sure that the Directory Server plugin initialization is performed.
811 try
812 {
813 HashSet<PluginType> pluginTypes = new HashSet<PluginType>(1);
814 pluginTypes.add(PluginType.LDIF_IMPORT);
815 directoryServer.initializePlugins(pluginTypes);
816 }
817 catch (ConfigException ce)
818 {
819 Message message = ERR_LDIFIMPORT_CANNOT_INITIALIZE_PLUGINS.get(
820 ce.getMessage());
821 err.println(wrapText(message, MAX_LINE_WIDTH));
822 return 1;
823 }
824 catch (InitializationException ie)
825 {
826 Message message = ERR_LDIFIMPORT_CANNOT_INITIALIZE_PLUGINS.get(
827 ie.getMessage());
828 err.println(wrapText(message, MAX_LINE_WIDTH));
829 return 1;
830 }
831 catch (Exception e)
832 {
833 Message message = ERR_LDIFIMPORT_CANNOT_INITIALIZE_PLUGINS.get(
834 getExceptionMessage(e));
835 err.println(wrapText(message, MAX_LINE_WIDTH));
836 return 1;
837 }
838 }
839
840
841 // See if there were any user-defined sets of include/exclude attributes or
842 // filters. If so, then process them.
843 HashSet<AttributeType> excludeAttributes;
844 boolean excludeAllUserAttributes = false;
845 boolean excludeAllOperationalAttributes = false;
846 if (excludeAttributeStrings == null)
847 {
848 excludeAttributes = null;
849 }
850 else
851 {
852 excludeAttributes = new HashSet<AttributeType>();
853 for (String attrName : excludeAttributeStrings.getValues())
854 {
855 String lowerName = attrName.toLowerCase();
856 if(lowerName.equals("*"))
857 {
858 excludeAllUserAttributes = true;
859 }
860 else if(lowerName.equals("+"))
861 {
862 excludeAllOperationalAttributes = true;
863 }
864 else
865 {
866 AttributeType attrType = DirectoryServer.getAttributeType(lowerName);
867 if (attrType == null)
868 {
869 attrType = DirectoryServer.getDefaultAttributeType(attrName);
870 }
871
872 excludeAttributes.add(attrType);
873 }
874 }
875 }
876
877 HashSet<AttributeType> includeAttributes;
878 boolean includeAllUserAttributes = false;
879 boolean includeAllOperationalAttributes = false;
880 if (includeAttributeStrings == null)
881 {
882 includeAttributes = null;
883 }
884 else
885 {
886 includeAttributes = new HashSet<AttributeType>();
887 for (String attrName : includeAttributeStrings.getValues())
888 {
889 String lowerName = attrName.toLowerCase();
890 if(lowerName.equals("*"))
891 {
892 includeAllUserAttributes = true;
893 }
894 else if(lowerName.equals("+"))
895 {
896 includeAllOperationalAttributes = true;
897 }
898 else
899 {
900 AttributeType attrType = DirectoryServer.getAttributeType(lowerName);
901 if (attrType == null)
902 {
903 attrType = DirectoryServer.getDefaultAttributeType(attrName);
904 }
905
906 includeAttributes.add(attrType);
907 }
908 }
909 }
910
911 ArrayList<SearchFilter> excludeFilters;
912 if (excludeFilterStrings == null)
913 {
914 excludeFilters = null;
915 }
916 else
917 {
918 excludeFilters = new ArrayList<SearchFilter>();
919 for (String filterString : excludeFilterStrings.getValues())
920 {
921 try
922 {
923 excludeFilters.add(SearchFilter.createFilterFromString(filterString));
924 }
925 catch (DirectoryException de)
926 {
927 Message message = ERR_LDIFIMPORT_CANNOT_PARSE_EXCLUDE_FILTER.get(
928 filterString, de.getMessageObject());
929 logError(message);
930 return 1;
931 }
932 catch (Exception e)
933 {
934 Message message = ERR_LDIFIMPORT_CANNOT_PARSE_EXCLUDE_FILTER.get(
935 filterString, getExceptionMessage(e));
936 logError(message);
937 return 1;
938 }
939 }
940 }
941
942 ArrayList<SearchFilter> includeFilters;
943 if (includeFilterStrings == null)
944 {
945 includeFilters = null;
946 }
947 else
948 {
949 includeFilters = new ArrayList<SearchFilter>();
950 for (String filterString : includeFilterStrings.getValues())
951 {
952 try
953 {
954 includeFilters.add(SearchFilter.createFilterFromString(filterString));
955 }
956 catch (DirectoryException de)
957 {
958 Message message = ERR_LDIFIMPORT_CANNOT_PARSE_INCLUDE_FILTER.get(
959 filterString, de.getMessageObject());
960 logError(message);
961 return 1;
962 }
963 catch (Exception e)
964 {
965 Message message = ERR_LDIFIMPORT_CANNOT_PARSE_INCLUDE_FILTER.get(
966 filterString, getExceptionMessage(e));
967 logError(message);
968 return 1;
969 }
970 }
971 }
972
973
974 // Get information about the backends defined in the server. Iterate
975 // through them, finding the one backend into which the LDIF should be
976 // imported and finding backends with subordinate base DNs that should be
977 // excluded from the import.
978 Backend backend = null;
979 List<DN> defaultIncludeBranches = null;
980 List<DN> excludeBranches = new ArrayList<DN>();
981 List<DN> includeBranches = new ArrayList<DN>();
982
983 if (includeBranchStrings.isPresent())
984 {
985 includeBranches = new ArrayList<DN>();
986 for (String s : includeBranchStrings.getValues())
987 {
988 DN includeBranch;
989 try
990 {
991 includeBranch = DN.decode(s);
992 }
993 catch (DirectoryException de)
994 {
995 Message message = ERR_LDIFIMPORT_CANNOT_DECODE_INCLUDE_BASE.get(
996 s, de.getMessageObject());
997 logError(message);
998 return 1;
999 }
1000 catch (Exception e)
1001 {
1002 Message message = ERR_LDIFIMPORT_CANNOT_DECODE_INCLUDE_BASE.get(
1003 s, getExceptionMessage(e));
1004 logError(message);
1005 return 1;
1006 }
1007
1008 includeBranches.add(includeBranch);
1009 }
1010 }
1011
1012 ArrayList<Backend> backendList = new ArrayList<Backend>();
1013 ArrayList<BackendCfg> entryList = new ArrayList<BackendCfg>();
1014 ArrayList<List<DN>> dnList = new ArrayList<List<DN>>();
1015 int code = BackendToolUtils.getBackends(backendList, entryList, dnList);
1016 if (code != 0)
1017 {
1018 return code;
1019 }
1020
1021 int numBackends = backendList.size();
1022 for (int i=0; i < numBackends; i++)
1023 {
1024 Backend b = backendList.get(i);
1025
1026 if(backendID.isPresent())
1027 {
1028 if (! backendID.getValue().equals(b.getBackendID()))
1029 {
1030 continue;
1031 }
1032 }
1033 else
1034 {
1035 boolean useBackend = false;
1036 for(DN baseDN : dnList.get(i))
1037 {
1038 for(DN includeDN : includeBranches)
1039 {
1040 if(baseDN.isAncestorOf(includeDN))
1041 {
1042 useBackend = true;
1043 break;
1044 }
1045 }
1046 if(useBackend)
1047 {
1048 break;
1049 }
1050 }
1051 if(!useBackend)
1052 {
1053 continue;
1054 }
1055 }
1056
1057 if (backend == null)
1058 {
1059 backend = b;
1060 defaultIncludeBranches = dnList.get(i);
1061 }
1062 else
1063 {
1064 Message message = ERR_LDIFIMPORT_MULTIPLE_BACKENDS_FOR_ID.get();
1065 logError(message);
1066 return 1;
1067 }
1068 }
1069
1070 if (backend == null)
1071 {
1072 Message message =
1073 ERR_LDIFIMPORT_NO_BACKENDS_FOR_ID.get();
1074 logError(message);
1075 return 1;
1076 }
1077 else if (! backend.supportsLDIFImport())
1078 {
1079 Message message = ERR_LDIFIMPORT_CANNOT_IMPORT.get(backendID.getValue());
1080 logError(message);
1081 return 1;
1082 }
1083
1084 for (List<DN> baseList : dnList)
1085 {
1086 for (DN baseDN : baseList)
1087 {
1088 for (DN importBase : defaultIncludeBranches)
1089 {
1090 if (baseDN.isDescendantOf(importBase) &&
1091 (! baseDN.equals(importBase)))
1092 {
1093 if (! excludeBranches.contains(baseDN))
1094 {
1095 excludeBranches.add(baseDN);
1096 }
1097
1098 break;
1099 }
1100 }
1101 }
1102 }
1103
1104 // Make sure that if the "backendID" argument was provided, no include base
1105 // was included, and the "append" option was not provided, the
1106 // "clearBackend" argument was also provided if there are more then one
1107 // baseDNs for the backend being imported.
1108 if(backendID.isPresent() && !includeBranchStrings.isPresent() &&
1109 !append.isPresent() && defaultIncludeBranches.size() > 1 &&
1110 !clearBackend.isPresent())
1111 {
1112 StringBuilder builder = new StringBuilder();
1113 builder.append(backend.getBaseDNs()[0].toNormalizedString());
1114 for(int i = 1; i < backend.getBaseDNs().length; i++)
1115 {
1116 builder.append(" / ");
1117 builder.append(backend.getBaseDNs()[i].toNormalizedString());
1118 }
1119 Message message = ERR_LDIFIMPORT_MISSING_CLEAR_BACKEND.get(
1120 builder.toString(), clearBackend.getLongIdentifier());
1121 err.println(wrapText(message, MAX_LINE_WIDTH));
1122 return 1;
1123 }
1124
1125 for (String s : excludeBranchStrings.getValues())
1126 {
1127 DN excludeBranch;
1128 try
1129 {
1130 excludeBranch = DN.decode(s);
1131 }
1132 catch (DirectoryException de)
1133 {
1134 Message message = ERR_LDIFIMPORT_CANNOT_DECODE_EXCLUDE_BASE.get(
1135 s, de.getMessageObject());
1136 logError(message);
1137 return 1;
1138 }
1139 catch (Exception e)
1140 {
1141 Message message = ERR_LDIFIMPORT_CANNOT_DECODE_EXCLUDE_BASE.get(
1142 s, getExceptionMessage(e));
1143 logError(message);
1144 return 1;
1145 }
1146
1147 if (! excludeBranches.contains(excludeBranch))
1148 {
1149 excludeBranches.add(excludeBranch);
1150 }
1151 }
1152
1153 if (! includeBranchStrings.isPresent())
1154 {
1155 includeBranches = defaultIncludeBranches;
1156 }
1157 else
1158 {
1159 // Make sure the selected backend will handle all the include branches
1160 for(DN includeBranch : includeBranches)
1161 {
1162 if (! Backend.handlesEntry(includeBranch, defaultIncludeBranches,
1163 excludeBranches))
1164 {
1165 Message message = ERR_LDIFIMPORT_INVALID_INCLUDE_BASE.get(
1166 includeBranch.toNormalizedString(), backendID.getValue());
1167 logError(message);
1168 return 1;
1169 }
1170 }
1171 }
1172
1173
1174 // See if the data should be read from LDIF files or generated via MakeLDIF.
1175 LDIFImportConfig importConfig;
1176 if (ldifFiles.isPresent())
1177 {
1178 ArrayList<String> fileList = new ArrayList<String>(ldifFiles.getValues());
1179 int badFileCount = 0;
1180 for (String pathname : fileList)
1181 {
1182 File f = new File(pathname);
1183 if (!f.canRead())
1184 {
1185 Message message = ERR_LDIFIMPORT_CANNOT_READ_FILE.get(pathname);
1186 logError(message);
1187 badFileCount++;
1188 }
1189 }
1190 if (badFileCount > 0) return 1;
1191 importConfig = new LDIFImportConfig(fileList);
1192 }
1193 else
1194 {
1195 Random random;
1196 if (randomSeed.isPresent())
1197 {
1198 try
1199 {
1200 random = new Random(randomSeed.getIntValue());
1201 }
1202 catch (Exception e)
1203 {
1204 random = new Random();
1205 }
1206 }
1207 else
1208 {
1209 random = new Random();
1210 }
1211
1212 String resourcePath = DirectoryServer.getServerRoot() + File.separator +
1213 PATH_MAKELDIF_RESOURCE_DIR;
1214 TemplateFile tf = new TemplateFile(resourcePath, random);
1215
1216 ArrayList<Message> warnings = new ArrayList<Message>();
1217 try
1218 {
1219 tf.parse(templateFile.getValue(), warnings);
1220 }
1221 catch (Exception e)
1222 {
1223 Message message = ERR_LDIFIMPORT_CANNOT_PARSE_TEMPLATE_FILE.get(
1224 templateFile.getValue(), e.getMessage());
1225 logError(message);
1226 return 1;
1227 }
1228
1229 importConfig = new LDIFImportConfig(tf);
1230 }
1231
1232
1233
1234 // Create the LDIF import configuration to use when reading the LDIF.
1235 importConfig.setAppendToExistingData(append.isPresent());
1236 importConfig.setReplaceExistingEntries(replaceExisting.isPresent());
1237 importConfig.setCompressed(isCompressed.isPresent());
1238 importConfig.setClearBackend(clearBackend.isPresent());
1239 importConfig.setEncrypted(isEncrypted.isPresent());
1240 importConfig.setExcludeAttributes(excludeAttributes);
1241 importConfig.setExcludeBranches(excludeBranches);
1242 importConfig.setExcludeFilters(excludeFilters);
1243 importConfig.setIncludeAttributes(includeAttributes);
1244 importConfig.setIncludeBranches(includeBranches);
1245 importConfig.setIncludeFilters(includeFilters);
1246 importConfig.setValidateSchema(!skipSchemaValidation.isPresent());
1247 importConfig.setBufferSize(LDIF_BUFFER_SIZE);
1248 importConfig.setExcludeAllUserAttributes(
1249 excludeAllUserAttributes);
1250 importConfig.setExcludeAllOperationalAttributes(
1251 excludeAllOperationalAttributes);
1252 importConfig.setIncludeAllOpAttributes(
1253 includeAllOperationalAttributes);
1254 importConfig.setIncludeAllUserAttributes(includeAllUserAttributes);
1255
1256 // FIXME -- Should this be conditional?
1257 importConfig.setInvokeImportPlugins(true);
1258
1259 if (rejectFile != null)
1260 {
1261 try
1262 {
1263 ExistingFileBehavior existingBehavior;
1264 if (overwrite.isPresent())
1265 {
1266 existingBehavior = ExistingFileBehavior.OVERWRITE;
1267 }
1268 else
1269 {
1270 existingBehavior = ExistingFileBehavior.APPEND;
1271 }
1272
1273 importConfig.writeRejectedEntries(rejectFile.getValue(),
1274 existingBehavior);
1275 }
1276 catch (Exception e)
1277 {
1278 Message message = ERR_LDIFIMPORT_CANNOT_OPEN_REJECTS_FILE.get(
1279 rejectFile.getValue(), getExceptionMessage(e));
1280 logError(message);
1281 return 1;
1282 }
1283 }
1284
1285 if (skipFile != null)
1286 {
1287 try
1288 {
1289 ExistingFileBehavior existingBehavior;
1290 if (overwrite.isPresent())
1291 {
1292 existingBehavior = ExistingFileBehavior.OVERWRITE;
1293 }
1294 else
1295 {
1296 existingBehavior = ExistingFileBehavior.APPEND;
1297 }
1298
1299 importConfig.writeSkippedEntries(skipFile.getValue(),
1300 existingBehavior);
1301 }
1302 catch (Exception e)
1303 {
1304 Message message = ERR_LDIFIMPORT_CANNOT_OPEN_SKIP_FILE.get(
1305 skipFile.getValue(), getExceptionMessage(e));
1306 logError(message);
1307 return 1;
1308 }
1309 }
1310
1311 // Get the set of base DNs for the backend as an array.
1312 DN[] baseDNs = new DN[defaultIncludeBranches.size()];
1313 defaultIncludeBranches.toArray(baseDNs);
1314
1315
1316 // Acquire an exclusive lock for the backend.
1317 try
1318 {
1319 String lockFile = LockFileManager.getBackendLockFileName(backend);
1320 StringBuilder failureReason = new StringBuilder();
1321 if (! LockFileManager.acquireExclusiveLock(lockFile, failureReason))
1322 {
1323 Message message = ERR_LDIFIMPORT_CANNOT_LOCK_BACKEND.get(
1324 backend.getBackendID(), String.valueOf(failureReason));
1325 logError(message);
1326 return 1;
1327 }
1328 }
1329 catch (Exception e)
1330 {
1331 Message message = ERR_LDIFIMPORT_CANNOT_LOCK_BACKEND.get(
1332 backend.getBackendID(), getExceptionMessage(e));
1333 logError(message);
1334 return 1;
1335 }
1336
1337
1338 // Launch the import.
1339 int retCode = 0;
1340 try
1341 {
1342 LDIFImportResult importResult = backend.importLDIF(importConfig);
1343 if (countRejects.isPresent())
1344 {
1345 if (importResult.getEntriesRejected() > Integer.MAX_VALUE)
1346 {
1347 retCode = Integer.MAX_VALUE;
1348 }
1349 else
1350 {
1351 retCode = (int) importResult.getEntriesRejected();
1352 }
1353 }
1354 }
1355 catch (DirectoryException de)
1356 {
1357 Message message =
1358 ERR_LDIFIMPORT_ERROR_DURING_IMPORT.get(de.getMessageObject());
1359 logError(message);
1360 retCode = 1;
1361 }
1362 catch (Exception e)
1363 {
1364 Message message =
1365 ERR_LDIFIMPORT_ERROR_DURING_IMPORT.get(getExceptionMessage(e));
1366 logError(message);
1367 retCode = 1;
1368 }
1369
1370
1371 // Release the exclusive lock on the backend.
1372 try
1373 {
1374 String lockFile = LockFileManager.getBackendLockFileName(backend);
1375 StringBuilder failureReason = new StringBuilder();
1376 if (! LockFileManager.releaseLock(lockFile, failureReason))
1377 {
1378 Message message = WARN_LDIFIMPORT_CANNOT_UNLOCK_BACKEND.get(
1379 backend.getBackendID(), String.valueOf(failureReason));
1380 logError(message);
1381 retCode = 1;
1382 }
1383 }
1384 catch (Exception e)
1385 {
1386 Message message = WARN_LDIFIMPORT_CANNOT_UNLOCK_BACKEND.get(
1387 backend.getBackendID(), getExceptionMessage(e));
1388 logError(message);
1389 retCode = 1;
1390 }
1391
1392
1393 // Clean up after the import by closing the import config.
1394 importConfig.close();
1395 return retCode;
1396 }
1397 }
1398