001    /*
002     * CDDL HEADER START
003     *
004     * The contents of this file are subject to the terms of the
005     * Common Development and Distribution License, Version 1.0 only
006     * (the "License").  You may not use this file except in compliance
007     * with the License.
008     *
009     * You can obtain a copy of the license at
010     * trunk/opends/resource/legal-notices/OpenDS.LICENSE
011     * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
012     * See the License for the specific language governing permissions
013     * and limitations under the License.
014     *
015     * When distributing Covered Code, include this CDDL HEADER in each
016     * file and include the License file at
017     * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
018     * add the following below this CDDL HEADER, with the fields enclosed
019     * by brackets "[]" replaced with your own identifying information:
020     *      Portions Copyright [yyyy] [name of copyright owner]
021     *
022     * CDDL HEADER END
023     *
024     *
025     *      Copyright 2006-2008 Sun Microsystems, Inc.
026     */
027    package org.opends.server.tools;
028    
029    import java.io.OutputStream;
030    import java.io.PrintStream;
031    import java.util.ArrayList;
032    import java.util.HashSet;
033    import java.util.List;
034    
035    import org.opends.server.api.Backend;
036    import org.opends.server.api.ErrorLogPublisher;
037    import org.opends.server.api.DebugLogPublisher;
038    import org.opends.server.api.plugin.PluginType;
039    import org.opends.server.config.ConfigException;
040    import static org.opends.server.config.ConfigConstants.*;
041    import org.opends.server.core.CoreConfigManager;
042    import org.opends.server.core.DirectoryServer;
043    import org.opends.server.core.LockFileManager;
044    import org.opends.server.extensions.ConfigFileHandler;
045    import org.opends.server.loggers.TextWriter;
046    import org.opends.server.loggers.TextErrorLogPublisher;
047    import org.opends.server.loggers.ErrorLogger;
048    import org.opends.server.loggers.debug.TextDebugLogPublisher;
049    import org.opends.server.loggers.debug.DebugLogger;
050    import org.opends.server.types.AttributeType;
051    import org.opends.server.types.DirectoryException;
052    import org.opends.server.types.DN;
053    import org.opends.server.types.ExistingFileBehavior;
054    import org.opends.server.types.InitializationException;
055    import org.opends.server.types.LDIFExportConfig;
056    import org.opends.server.types.NullOutputStream;
057    import org.opends.server.types.SearchFilter;
058    import org.opends.server.types.RawAttribute;
059    import org.opends.server.util.args.ArgumentException;
060    import org.opends.server.util.args.BooleanArgument;
061    import org.opends.server.util.args.IntegerArgument;
062    import org.opends.server.util.args.StringArgument;
063    import org.opends.server.util.args.LDAPConnectionArgumentParser;
064    
065    import org.opends.messages.Message;
066    import static org.opends.messages.ToolMessages.*;
067    import static org.opends.server.loggers.ErrorLogger.*;
068    import static org.opends.server.util.ServerConstants.*;
069    import static org.opends.server.util.StaticUtils.*;
070    import static org.opends.server.tools.ToolConstants.*;
071    import org.opends.server.tools.tasks.TaskTool;
072    import org.opends.server.admin.std.server.BackendCfg;
073    import org.opends.server.protocols.ldap.LDAPAttribute;
074    import org.opends.server.protocols.asn1.ASN1OctetString;
075    import org.opends.server.tasks.ExportTask;
076    
077    
078    /**
079     * This program provides a utility that may be used to export the contents of a
080     * Directory Server backend to an LDIF file.  Depending on the arguments given,
081     * this program will either perform the export directly as a process that
082     * runs separate from Directory Server; or by scheduling a task to perform the
083     * action within the Directory Server via the tasks interface.
084     */
085    public class ExportLDIF extends TaskTool {
086    
087      /**
088       * The main method for ExportLDIF tool.
089       *
090       * @param  args  The command-line arguments provided to this program.
091       */
092      public static void main(String[] args)
093      {
094        int retCode = mainExportLDIF(args, true, System.out, System.err);
095    
096        if(retCode != 0)
097        {
098          System.exit(filterExitCode(retCode));
099        }
100      }
101    
102      /**
103       * Processes the command-line arguments and invokes the export process.
104       *
105       * @param  args  The command-line arguments provided to this program.
106       *
107       * @return The error code.
108       */
109      public static int mainExportLDIF(String[] args)
110      {
111        return mainExportLDIF(args, true, System.out, System.err);
112      }
113    
114      /**
115       * Processes the command-line arguments and invokes the export process.
116       *
117       * @param  args              The command-line arguments provided to this
118       *                           program.
119       * @param  initializeServer  Indicates whether to initialize the server.
120       * @param  outStream         The output stream to use for standard output, or
121       *                           {@code null} if standard output is not needed.
122       * @param  errStream         The output stream to use for standard error, or
123       *                           {@code null} if standard error is not needed.
124       *
125       * @return The error code.
126       */
127      public static int mainExportLDIF(String[] args, boolean initializeServer,
128                                       OutputStream outStream,
129                                       OutputStream errStream)
130      {
131        ExportLDIF tool = new ExportLDIF();
132        return tool.process(args, initializeServer, outStream, errStream);
133      }
134    
135      // Define the command-line arguments that may be used with this program.
136      private BooleanArgument appendToLDIF            = null;
137      private BooleanArgument compressLDIF            = null;
138      private BooleanArgument displayUsage            = null;
139      private BooleanArgument encryptLDIF             = null;
140      private BooleanArgument excludeOperationalAttrs = null;
141      private BooleanArgument signHash                = null;
142      private IntegerArgument wrapColumn              = null;
143      private StringArgument  backendID               = null;
144      private StringArgument  configClass             = null;
145      private StringArgument  configFile              = null;
146      private StringArgument  excludeAttributeStrings = null;
147      private StringArgument  excludeBranchStrings    = null;
148      private StringArgument  excludeFilterStrings    = null;
149      private StringArgument  includeAttributeStrings = null;
150      private StringArgument  includeBranchStrings    = null;
151      private StringArgument  includeFilterStrings    = null;
152      private StringArgument  ldifFile                = null;
153    
154      private int process(String[] args, boolean initializeServer,
155                          OutputStream outStream, OutputStream errStream) {
156    
157        PrintStream out;
158        if (outStream == null)
159        {
160          out = NullOutputStream.printStream();
161        }
162        else
163        {
164          out = new PrintStream(outStream);
165        }
166    
167        PrintStream err;
168        if (errStream == null)
169        {
170          err = NullOutputStream.printStream();
171        }
172        else
173        {
174          err = new PrintStream(errStream);
175        }
176    
177        // Create the command-line argument parser for use with this program.
178        LDAPConnectionArgumentParser argParser =
179                createArgParser("org.opends.server.tools.ExportLDIF",
180                                INFO_LDIFEXPORT_TOOL_DESCRIPTION.get());
181    
182    
183        // Initialize all the command-line argument types and register them with the
184        // parser.
185        try
186        {
187          configClass =
188               new StringArgument("configclass", OPTION_SHORT_CONFIG_CLASS,
189                                  OPTION_LONG_CONFIG_CLASS, true, false,
190                                  true, INFO_CONFIGCLASS_PLACEHOLDER.get(),
191                                  ConfigFileHandler.class.getName(), null,
192                                  INFO_DESCRIPTION_CONFIG_CLASS.get());
193          configClass.setHidden(true);
194          argParser.addArgument(configClass);
195    
196    
197          configFile =
198               new StringArgument("configfile", 'f', "configFile", true, false,
199                                  true, INFO_CONFIGFILE_PLACEHOLDER.get(), null,
200                                  null,
201                                  INFO_DESCRIPTION_CONFIG_FILE.get());
202          configFile.setHidden(true);
203          argParser.addArgument(configFile);
204    
205    
206          ldifFile =
207               new StringArgument("ldiffile", OPTION_SHORT_LDIF_FILE,
208                                  OPTION_LONG_LDIF_FILE,true, false, true,
209                                  INFO_LDIFFILE_PLACEHOLDER.get(), null, null,
210                                  INFO_LDIFEXPORT_DESCRIPTION_LDIF_FILE.get());
211          argParser.addArgument(ldifFile);
212    
213    
214          appendToLDIF = new BooleanArgument(
215                       "appendldif", 'a', "appendToLDIF",
216                       INFO_LDIFEXPORT_DESCRIPTION_APPEND_TO_LDIF.get());
217          argParser.addArgument(appendToLDIF);
218    
219    
220          backendID =
221               new StringArgument("backendid", 'n', "backendID", true, false, true,
222                                  INFO_BACKENDNAME_PLACEHOLDER.get(), null, null,
223                                  INFO_LDIFEXPORT_DESCRIPTION_BACKEND_ID.get());
224          argParser.addArgument(backendID);
225    
226    
227          includeBranchStrings =
228               new StringArgument("includebranch", 'b', "includeBranch", false,
229                                  true, true, INFO_BRANCH_DN_PLACEHOLDER.get(),
230                                  null, null,
231                                  INFO_LDIFEXPORT_DESCRIPTION_INCLUDE_BRANCH.get());
232          argParser.addArgument(includeBranchStrings);
233    
234    
235          excludeBranchStrings =
236               new StringArgument("excludebranch", 'B', "excludeBranch", false,
237                                  true, true, INFO_BRANCH_DN_PLACEHOLDER.get(),
238                                  null, null,
239                                  INFO_LDIFEXPORT_DESCRIPTION_EXCLUDE_BRANCH.get());
240          argParser.addArgument(excludeBranchStrings);
241    
242    
243          includeAttributeStrings =
244               new StringArgument(
245                       "includeattribute", 'i', "includeAttribute",
246                       false, true, true, INFO_ATTRIBUTE_PLACEHOLDER.get(), null,
247                       null,
248                       INFO_LDIFEXPORT_DESCRIPTION_INCLUDE_ATTRIBUTE.get());
249          argParser.addArgument(includeAttributeStrings);
250    
251    
252          excludeAttributeStrings =
253               new StringArgument(
254                       "excludeattribute", 'e', "excludeAttribute",
255                       false, true, true, INFO_ATTRIBUTE_PLACEHOLDER.get(), null,
256                       null,
257                       INFO_LDIFEXPORT_DESCRIPTION_EXCLUDE_ATTRIBUTE.get());
258          argParser.addArgument(excludeAttributeStrings);
259    
260    
261          includeFilterStrings =
262               new StringArgument("includefilter", 'I', "includeFilter",
263                                  false, true, true, INFO_FILTER_PLACEHOLDER.get(),
264                                  null, null,
265                                  INFO_LDIFEXPORT_DESCRIPTION_INCLUDE_FILTER.get());
266          argParser.addArgument(includeFilterStrings);
267    
268    
269          excludeFilterStrings =
270               new StringArgument("excludefilter", 'E', "excludeFilter",
271                                  false, true, true, INFO_FILTER_PLACEHOLDER.get(),
272                                  null, null,
273                                  INFO_LDIFEXPORT_DESCRIPTION_EXCLUDE_FILTER.get());
274          argParser.addArgument(excludeFilterStrings);
275    
276    
277          excludeOperationalAttrs =
278               new BooleanArgument("excludeoperational", 'O', "excludeOperational",
279                        INFO_LDIFEXPORT_DESCRIPTION_EXCLUDE_OPERATIONAL.get());
280          argParser.addArgument(excludeOperationalAttrs);
281    
282    
283          wrapColumn =
284               new IntegerArgument("wrapcolumn", null, "wrapColumn", false, false,
285                                   true, INFO_WRAP_COLUMN_PLACEHOLDER.get(), 0,
286                                   null, true, 0, false, 0,
287                                   INFO_LDIFEXPORT_DESCRIPTION_WRAP_COLUMN.get());
288          argParser.addArgument(wrapColumn);
289    
290    
291          compressLDIF =
292               new BooleanArgument("compressldif", OPTION_SHORT_COMPRESS,
293                                   OPTION_LONG_COMPRESS,
294                                   INFO_LDIFEXPORT_DESCRIPTION_COMPRESS_LDIF.get());
295          argParser.addArgument(compressLDIF);
296    
297    
298          encryptLDIF =
299               new BooleanArgument("encryptldif", 'y', "encryptLDIF",
300                                   INFO_LDIFEXPORT_DESCRIPTION_ENCRYPT_LDIF.get());
301          encryptLDIF.setHidden(true); // See issue #27
302          argParser.addArgument(encryptLDIF);
303    
304    
305          signHash =
306               new BooleanArgument("signhash", 's', "signHash",
307                                   INFO_LDIFEXPORT_DESCRIPTION_SIGN_HASH.get());
308          signHash.setHidden(true); // See issue #28
309          argParser.addArgument(signHash);
310    
311    
312          displayUsage =
313               new BooleanArgument("help", OPTION_SHORT_HELP,
314                                   OPTION_LONG_HELP,
315                                   INFO_DESCRIPTION_USAGE.get());
316          argParser.addArgument(displayUsage);
317          argParser.setUsageArgument(displayUsage);
318        }
319        catch (ArgumentException ae)
320        {
321          Message message = ERR_CANNOT_INITIALIZE_ARGS.get(ae.getMessage());
322    
323          err.println(wrapText(message, MAX_LINE_WIDTH));
324          return 1;
325        }
326    
327    
328        // Parse the command-line arguments provided to this program.
329        try
330        {
331          argParser.parseArguments(args);
332          validateTaskArgs();
333        }
334        catch (ArgumentException ae)
335        {
336          Message message = ERR_ERROR_PARSING_ARGS.get(ae.getMessage());
337    
338          err.println(wrapText(message, MAX_LINE_WIDTH));
339          err.println(argParser.getUsage());
340          return 1;
341        }
342    
343    
344        // If we should just display usage or version information,
345        // then print it and exit.
346        if (argParser.usageOrVersionDisplayed())
347        {
348          return 0;
349        }
350    
351        return process(argParser, initializeServer, out, err);
352      }
353    
354      /**
355       * {@inheritDoc}
356       */
357      public void addTaskAttributes(List<RawAttribute> attributes)
358      {
359        //
360        // Required attributes
361        //
362        ArrayList<ASN1OctetString> values = new ArrayList<ASN1OctetString>(1);
363        values.add(new ASN1OctetString(ldifFile.getValue()));
364        attributes.add(new LDAPAttribute(ATTR_TASK_EXPORT_LDIF_FILE, values));
365    
366        values = new ArrayList<ASN1OctetString>(1);
367        values.add(new ASN1OctetString(backendID.getValue()));
368        attributes.add(new LDAPAttribute(ATTR_TASK_EXPORT_BACKEND_ID, values));
369    
370        //
371        // Optional attributes
372        //
373        if (appendToLDIF.getValue() != null &&
374                !appendToLDIF.getValue().equals(appendToLDIF.getDefaultValue())) {
375          values = new ArrayList<ASN1OctetString>(1);
376          values.add(new ASN1OctetString(appendToLDIF.getValue()));
377          attributes.add(
378                  new LDAPAttribute(ATTR_TASK_EXPORT_APPEND_TO_LDIF, values));
379        }
380    
381        if (compressLDIF.getValue() != null &&
382                !compressLDIF.getValue().equals(compressLDIF.getDefaultValue())) {
383          values = new ArrayList<ASN1OctetString>(1);
384          values.add(new ASN1OctetString(compressLDIF.getValue()));
385          attributes.add(new LDAPAttribute(ATTR_TASK_EXPORT_COMPRESS_LDIF, values));
386        }
387    
388        if (encryptLDIF.getValue() != null &&
389                !encryptLDIF.getValue().equals(encryptLDIF.getDefaultValue())) {
390          values = new ArrayList<ASN1OctetString>(1);
391          values.add(new ASN1OctetString(encryptLDIF.getValue()));
392          attributes.add(new LDAPAttribute(ATTR_TASK_EXPORT_ENCRYPT_LDIF, values));
393        }
394    
395        if (signHash.getValue() != null &&
396                !signHash.getValue().equals(signHash.getDefaultValue())) {
397          values = new ArrayList<ASN1OctetString>(1);
398          values.add(new ASN1OctetString(signHash.getValue()));
399          attributes.add(
400                  new LDAPAttribute(ATTR_TASK_EXPORT_SIGN_HASH, values));
401        }
402    
403        List<String> includeAttributes = includeAttributeStrings.getValues();
404        if (includeAttributes != null && includeAttributes.size() > 0) {
405          values = new ArrayList<ASN1OctetString>(includeAttributes.size());
406          for (String includeAttribute : includeAttributes) {
407            values.add(new ASN1OctetString(includeAttribute));
408          }
409          attributes.add(
410                  new LDAPAttribute(ATTR_TASK_EXPORT_INCLUDE_ATTRIBUTE, values));
411        }
412    
413        List<String> excludeAttributes = excludeAttributeStrings.getValues();
414        if (excludeAttributes != null && excludeAttributes.size() > 0) {
415          values = new ArrayList<ASN1OctetString>(excludeAttributes.size());
416          for (String excludeAttribute : excludeAttributes) {
417            values.add(new ASN1OctetString(excludeAttribute));
418          }
419          attributes.add(
420                  new LDAPAttribute(ATTR_TASK_EXPORT_EXCLUDE_ATTRIBUTE, values));
421        }
422    
423        List<String> includeFilters = includeFilterStrings.getValues();
424        if (includeFilters != null && includeFilters.size() > 0) {
425          values = new ArrayList<ASN1OctetString>(includeFilters.size());
426          for (String includeFilter : includeFilters) {
427            values.add(new ASN1OctetString(includeFilter));
428          }
429          attributes.add(
430                  new LDAPAttribute(ATTR_TASK_EXPORT_INCLUDE_FILTER, values));
431        }
432    
433        List<String> excludeFilters = excludeFilterStrings.getValues();
434        if (excludeFilters != null && excludeFilters.size() > 0) {
435          values = new ArrayList<ASN1OctetString>(excludeFilters.size());
436          for (String excludeFilter : excludeFilters) {
437            values.add(new ASN1OctetString(excludeFilter));
438          }
439          attributes.add(
440                  new LDAPAttribute(ATTR_TASK_EXPORT_EXCLUDE_FILTER, values));
441        }
442    
443        List<String> includeBranches = includeBranchStrings.getValues();
444        if (includeBranches != null && includeBranches.size() > 0) {
445          values = new ArrayList<ASN1OctetString>(includeBranches.size());
446          for (String includeBranche : includeBranches) {
447            values.add(new ASN1OctetString(includeBranche));
448          }
449          attributes.add(
450                  new LDAPAttribute(ATTR_TASK_EXPORT_INCLUDE_BRANCH, values));
451        }
452    
453        List<String> excludeBranches = excludeBranchStrings.getValues();
454        if (excludeBranches != null && excludeBranches.size() > 0) {
455          values = new ArrayList<ASN1OctetString>(excludeBranches.size());
456          for (String excludeBranche : excludeBranches) {
457            values.add(new ASN1OctetString(excludeBranche));
458          }
459          attributes.add(
460                  new LDAPAttribute(ATTR_TASK_EXPORT_EXCLUDE_BRANCH, values));
461        }
462    
463        if (wrapColumn.getValue() != null &&
464                !wrapColumn.getValue().equals(wrapColumn.getDefaultValue())) {
465          values = new ArrayList<ASN1OctetString>(1);
466          values.add(new ASN1OctetString(wrapColumn.getValue()));
467          attributes.add(
468                  new LDAPAttribute(ATTR_TASK_EXPORT_WRAP_COLUMN, values));
469        }
470    
471        if (excludeOperationalAttrs.isPresent())
472        {
473          values = new ArrayList<ASN1OctetString>(1);
474          values.add(new ASN1OctetString("false"));
475          attributes.add(
476              new LDAPAttribute(ATTR_TASK_EXPORT_INCLUDE_OPERATIONAL_ATTRIBUTES,
477                  values));
478        }
479      }
480    
481      /**
482       * {@inheritDoc}
483       */
484      public String getTaskObjectclass() {
485        return "ds-task-export";
486      }
487    
488      /**
489       * {@inheritDoc}
490       */
491      public Class getTaskClass() {
492        return ExportTask.class;
493      }
494    
495      /**
496       * {@inheritDoc}
497       */
498      protected int processLocal(boolean initializeServer,
499                               PrintStream out,
500                               PrintStream err) {
501    
502        // Perform the initial bootstrap of the Directory Server and process the
503        // configuration.
504        DirectoryServer directoryServer = DirectoryServer.getInstance();
505        if (initializeServer)
506        {
507          try
508          {
509            DirectoryServer.bootstrapClient();
510            DirectoryServer.initializeJMX();
511          }
512          catch (Exception e)
513          {
514            Message message =
515                    ERR_SERVER_BOOTSTRAP_ERROR.get(getExceptionMessage(e));
516            err.println(wrapText(message, MAX_LINE_WIDTH));
517            return 1;
518          }
519    
520          try
521          {
522            directoryServer.initializeConfiguration(configClass.getValue(),
523                                                    configFile.getValue());
524          }
525          catch (InitializationException ie)
526          {
527            Message message = ERR_CANNOT_LOAD_CONFIG.get(ie.getMessage());
528            err.println(wrapText(message, MAX_LINE_WIDTH));
529            return 1;
530          }
531          catch (Exception e)
532          {
533            Message message = ERR_CANNOT_LOAD_CONFIG.get(getExceptionMessage(e));
534            err.println(wrapText(message, MAX_LINE_WIDTH));
535            return 1;
536          }
537    
538    
539    
540          // Initialize the Directory Server schema elements.
541          try
542          {
543            directoryServer.initializeSchema();
544          }
545          catch (ConfigException ce)
546          {
547            Message message = ERR_CANNOT_LOAD_SCHEMA.get(ce.getMessage());
548            err.println(wrapText(message, MAX_LINE_WIDTH));
549            return 1;
550          }
551          catch (InitializationException ie)
552          {
553            Message message = ERR_CANNOT_LOAD_SCHEMA.get(ie.getMessage());
554            err.println(wrapText(message, MAX_LINE_WIDTH));
555            return 1;
556          }
557          catch (Exception e)
558          {
559            Message message = ERR_CANNOT_LOAD_SCHEMA.get(getExceptionMessage(e));
560            err.println(wrapText(message, MAX_LINE_WIDTH));
561            return 1;
562          }
563    
564    
565          // Initialize the Directory Server core configuration.
566          try
567          {
568            CoreConfigManager coreConfigManager = new CoreConfigManager();
569            coreConfigManager.initializeCoreConfig();
570          }
571          catch (ConfigException ce)
572          {
573            Message message =
574                    ERR_CANNOT_INITIALIZE_CORE_CONFIG.get(ce.getMessage());
575            err.println(wrapText(message, MAX_LINE_WIDTH));
576            return 1;
577          }
578          catch (InitializationException ie)
579          {
580            Message message =
581                    ERR_CANNOT_INITIALIZE_CORE_CONFIG.get(ie.getMessage());
582            err.println(wrapText(message, MAX_LINE_WIDTH));
583            return 1;
584          }
585          catch (Exception e)
586          {
587            Message message =
588                    ERR_CANNOT_INITIALIZE_CORE_CONFIG.get(getExceptionMessage(e));
589            err.println(wrapText(message, MAX_LINE_WIDTH));
590            return 1;
591          }
592    
593    
594          // Initialize the Directory Server crypto manager.
595          try
596          {
597            directoryServer.initializeCryptoManager();
598          }
599          catch (ConfigException ce)
600          {
601            Message message =
602                    ERR_CANNOT_INITIALIZE_CRYPTO_MANAGER.get(ce.getMessage());
603            err.println(wrapText(message, MAX_LINE_WIDTH));
604            return 1;
605          }
606          catch (InitializationException ie)
607          {
608            Message message =
609                    ERR_CANNOT_INITIALIZE_CRYPTO_MANAGER.get(ie.getMessage());
610            err.println(wrapText(message, MAX_LINE_WIDTH));
611            return 1;
612          }
613          catch (Exception e)
614          {
615            Message message =
616                    ERR_CANNOT_INITIALIZE_CRYPTO_MANAGER.get(
617                            getExceptionMessage(e));
618            err.println(wrapText(message, MAX_LINE_WIDTH));
619            return 1;
620          }
621    
622    
623          try
624          {
625            ErrorLogPublisher errorLogPublisher =
626                TextErrorLogPublisher.getStartupTextErrorPublisher(
627                new TextWriter.STREAM(out));
628            DebugLogPublisher debugLogPublisher =
629                TextDebugLogPublisher.getStartupTextDebugPublisher(
630                new TextWriter.STREAM(out));
631            ErrorLogger.addErrorLogPublisher(errorLogPublisher);
632            DebugLogger.addDebugLogPublisher(debugLogPublisher);
633          }
634          catch(Exception e)
635          {
636            err.println("Error installing the custom error logger: " +
637                        stackTraceToSingleLineString(e));
638          }
639    
640    
641    
642          // Make sure that the Directory Server plugin initialization is performed.
643          try
644          {
645            HashSet<PluginType> pluginTypes = new HashSet<PluginType>(1);
646            pluginTypes.add(PluginType.LDIF_EXPORT);
647            directoryServer.initializePlugins(pluginTypes);
648          }
649          catch (ConfigException ce)
650          {
651            Message message =
652                    ERR_LDIFEXPORT_CANNOT_INITIALIZE_PLUGINS.get(ce.getMessage());
653            err.println(wrapText(message, MAX_LINE_WIDTH));
654            return 1;
655          }
656          catch (InitializationException ie)
657          {
658            Message message =
659                    ERR_LDIFEXPORT_CANNOT_INITIALIZE_PLUGINS.get(ie.getMessage());
660            err.println(wrapText(message, MAX_LINE_WIDTH));
661            return 1;
662          }
663          catch (Exception e)
664          {
665            Message message =
666                    ERR_LDIFEXPORT_CANNOT_INITIALIZE_PLUGINS.get(
667                            getExceptionMessage(e));
668            err.println(wrapText(message, MAX_LINE_WIDTH));
669            return 1;
670          }
671        }
672    
673    
674        // See if there were any user-defined sets of include/exclude attributes or
675        // filters.  If so, then process them.
676        HashSet<AttributeType> excludeAttributes;
677        if (excludeAttributeStrings == null)
678        {
679          excludeAttributes = null;
680        }
681        else
682        {
683          excludeAttributes = new HashSet<AttributeType>();
684          for (String attrName : excludeAttributeStrings.getValues())
685          {
686            String        lowerName = attrName.toLowerCase();
687            AttributeType attrType  = DirectoryServer.getAttributeType(lowerName);
688            if (attrType == null)
689            {
690              attrType = DirectoryServer.getDefaultAttributeType(attrName);
691            }
692    
693            excludeAttributes.add(attrType);
694          }
695        }
696    
697        HashSet<AttributeType> includeAttributes;
698        if (includeAttributeStrings == null)
699        {
700          includeAttributes = null;
701        }
702        else
703        {
704          includeAttributes =new HashSet<AttributeType>();
705          for (String attrName : includeAttributeStrings.getValues())
706          {
707            String        lowerName = attrName.toLowerCase();
708            AttributeType attrType  = DirectoryServer.getAttributeType(lowerName);
709            if (attrType == null)
710            {
711              attrType = DirectoryServer.getDefaultAttributeType(attrName);
712            }
713    
714            includeAttributes.add(attrType);
715          }
716        }
717    
718        ArrayList<SearchFilter> excludeFilters;
719        if (excludeFilterStrings == null)
720        {
721          excludeFilters = null;
722        }
723        else
724        {
725          excludeFilters = new ArrayList<SearchFilter>();
726          for (String filterString : excludeFilterStrings.getValues())
727          {
728            try
729            {
730              excludeFilters.add(SearchFilter.createFilterFromString(filterString));
731            }
732            catch (DirectoryException de)
733            {
734              Message message = ERR_LDIFEXPORT_CANNOT_PARSE_EXCLUDE_FILTER.get(
735                  filterString, de.getMessageObject());
736              logError(message);
737              return 1;
738            }
739            catch (Exception e)
740            {
741              Message message = ERR_LDIFEXPORT_CANNOT_PARSE_EXCLUDE_FILTER.get(
742                  filterString, getExceptionMessage(e));
743              logError(message);
744              return 1;
745            }
746          }
747        }
748    
749        ArrayList<SearchFilter> includeFilters;
750        if (includeFilterStrings == null)
751        {
752          includeFilters = null;
753        }
754        else
755        {
756          includeFilters = new ArrayList<SearchFilter>();
757          for (String filterString : includeFilterStrings.getValues())
758          {
759            try
760            {
761              includeFilters.add(SearchFilter.createFilterFromString(filterString));
762            }
763            catch (DirectoryException de)
764            {
765              Message message = ERR_LDIFEXPORT_CANNOT_PARSE_INCLUDE_FILTER.get(
766                  filterString, de.getMessageObject());
767              logError(message);
768              return 1;
769            }
770            catch (Exception e)
771            {
772              Message message = ERR_LDIFEXPORT_CANNOT_PARSE_INCLUDE_FILTER.get(
773                  filterString, getExceptionMessage(e));
774              logError(message);
775              return 1;
776            }
777          }
778        }
779    
780    
781        // Get information about the backends defined in the server.  Iterate
782        // through them, finding the one backend that should be used for the export,
783        // and also finding backends with subordinate base DNs that should be
784        // excluded from the export.
785        Backend       backend                = null;
786        List<DN>      baseDNList             = null;
787        List<DN>      defaultIncludeBranches = null;
788        ArrayList<DN> excludeBranches        = null;
789    
790        ArrayList<Backend>     backendList = new ArrayList<Backend>();
791        ArrayList<BackendCfg>  entryList   = new ArrayList<BackendCfg>();
792        ArrayList<List<DN>>    dnList      = new ArrayList<List<DN>>();
793        BackendToolUtils.getBackends(backendList, entryList, dnList);
794    
795        int numBackends = backendList.size();
796        for (int i=0; i < numBackends; i++)
797        {
798          Backend b = backendList.get(i);
799          if (! backendID.getValue().equals(b.getBackendID()))
800          {
801            continue;
802          }
803    
804          if (backend == null)
805          {
806            backend                = b;
807            baseDNList             = dnList.get(i);
808            defaultIncludeBranches = dnList.get(i);
809          }
810          else
811          {
812            Message message =
813                ERR_LDIFEXPORT_MULTIPLE_BACKENDS_FOR_ID.get(backendID.getValue());
814            logError(message);
815            return 1;
816          }
817        }
818    
819        if (backend == null)
820        {
821          Message message =
822              ERR_LDIFEXPORT_NO_BACKENDS_FOR_ID.get(backendID.getValue());
823          logError(message);
824          return 1;
825        }
826        else if (! backend.supportsLDIFExport())
827        {
828          Message message =
829              ERR_LDIFEXPORT_CANNOT_EXPORT_BACKEND.get(backendID.getValue());
830          logError(message);
831          return 1;
832        }
833    
834        if (excludeBranchStrings.isPresent())
835        {
836          excludeBranches = new ArrayList<DN>();
837          for (String s : excludeBranchStrings.getValues())
838          {
839            DN excludeBranch;
840            try
841            {
842              excludeBranch = DN.decode(s);
843            }
844            catch (DirectoryException de)
845            {
846              Message message = ERR_LDIFEXPORT_CANNOT_DECODE_EXCLUDE_BASE.get(
847                  s, de.getMessageObject());
848              logError(message);
849              return 1;
850            }
851            catch (Exception e)
852            {
853              Message message = ERR_LDIFEXPORT_CANNOT_DECODE_EXCLUDE_BASE.get(
854                  s, getExceptionMessage(e));
855              logError(message);
856              return 1;
857            }
858    
859            if (! excludeBranches.contains(excludeBranch))
860            {
861              excludeBranches.add(excludeBranch);
862            }
863          }
864        }
865    
866    
867        List<DN> includeBranches;
868        if (includeBranchStrings.isPresent())
869        {
870          includeBranches = new ArrayList<DN>();
871          for (String s : includeBranchStrings.getValues())
872          {
873            DN includeBranch;
874            try
875            {
876              includeBranch = DN.decode(s);
877            }
878            catch (DirectoryException de)
879            {
880              Message message = ERR_LDIFIMPORT_CANNOT_DECODE_INCLUDE_BASE.get(
881                  s, de.getMessageObject());
882              logError(message);
883              return 1;
884            }
885            catch (Exception e)
886            {
887              Message message = ERR_LDIFIMPORT_CANNOT_DECODE_INCLUDE_BASE.get(
888                  s, getExceptionMessage(e));
889              logError(message);
890              return 1;
891            }
892    
893            if (! Backend.handlesEntry(includeBranch, defaultIncludeBranches,
894                                       excludeBranches))
895            {
896              Message message =
897                  ERR_LDIFEXPORT_INVALID_INCLUDE_BASE.get(s, backendID.getValue());
898              logError(message);
899              return 1;
900            }
901    
902            includeBranches.add(includeBranch);
903          }
904        }
905        else
906        {
907          includeBranches = defaultIncludeBranches;
908        }
909    
910    
911        // Create the LDIF export configuration to use when reading the LDIF.
912        ExistingFileBehavior existingBehavior;
913        if (appendToLDIF.isPresent())
914        {
915          existingBehavior = ExistingFileBehavior.APPEND;
916        }
917        else
918        {
919          existingBehavior = ExistingFileBehavior.OVERWRITE;
920        }
921    
922        LDIFExportConfig exportConfig = new LDIFExportConfig(ldifFile.getValue(),
923                                                             existingBehavior);
924        exportConfig.setCompressData(compressLDIF.isPresent());
925        exportConfig.setEncryptData(encryptLDIF.isPresent());
926        exportConfig.setExcludeAttributes(excludeAttributes);
927        exportConfig.setExcludeBranches(excludeBranches);
928        exportConfig.setExcludeFilters(excludeFilters);
929        exportConfig.setIncludeAttributes(includeAttributes);
930        exportConfig.setIncludeBranches(includeBranches);
931        exportConfig.setIncludeFilters(includeFilters);
932        exportConfig.setSignHash(signHash.isPresent());
933        exportConfig.setIncludeOperationalAttributes(
934                          (! excludeOperationalAttrs.isPresent()));
935    
936        // FIXME -- Should this be conditional?
937        exportConfig.setInvokeExportPlugins(true);
938    
939        try
940        {
941          exportConfig.setWrapColumn(wrapColumn.getIntValue());
942        }
943        catch (ArgumentException ae)
944        {
945          Message message = ERR_LDIFEXPORT_CANNOT_DECODE_WRAP_COLUMN_AS_INTEGER.get(
946              wrapColumn.getValue());
947          logError(message);
948          return 1;
949        }
950    
951    
952        // Get the set of base DNs for the backend as an array.
953        DN[] baseDNs = new DN[baseDNList.size()];
954        baseDNList.toArray(baseDNs);
955    
956    
957        // Acquire a shared lock for the backend.
958        try
959        {
960          String lockFile = LockFileManager.getBackendLockFileName(backend);
961          StringBuilder failureReason = new StringBuilder();
962          if (! LockFileManager.acquireSharedLock(lockFile, failureReason))
963          {
964            Message message = ERR_LDIFEXPORT_CANNOT_LOCK_BACKEND.get(
965                backend.getBackendID(), String.valueOf(failureReason));
966            logError(message);
967            return 1;
968          }
969        }
970        catch (Exception e)
971        {
972          Message message = ERR_LDIFEXPORT_CANNOT_LOCK_BACKEND.get(
973              backend.getBackendID(), getExceptionMessage(e));
974          logError(message);
975          return 1;
976        }
977    
978        boolean errorOccurred = false;
979    
980        // Launch the export.
981        try
982        {
983          backend.exportLDIF(exportConfig);
984        }
985        catch (DirectoryException de)
986        {
987          Message message =
988              ERR_LDIFEXPORT_ERROR_DURING_EXPORT.get(de.getMessageObject());
989          logError(message);
990          errorOccurred = true;
991        }
992        catch (Exception e)
993        {
994          Message message =
995              ERR_LDIFEXPORT_ERROR_DURING_EXPORT.get(getExceptionMessage(e));
996          logError(message);
997          errorOccurred = true;
998        }
999    
1000    
1001        // Release the shared lock on the backend.
1002        try
1003        {
1004          String lockFile = LockFileManager.getBackendLockFileName(backend);
1005          StringBuilder failureReason = new StringBuilder();
1006          if (! LockFileManager.releaseLock(lockFile, failureReason))
1007          {
1008            Message message = WARN_LDIFEXPORT_CANNOT_UNLOCK_BACKEND.get(
1009                backend.getBackendID(), String.valueOf(failureReason));
1010            logError(message);
1011          }
1012        }
1013        catch (Exception e)
1014        {
1015          Message message = WARN_LDIFEXPORT_CANNOT_UNLOCK_BACKEND.get(
1016              backend.getBackendID(), getExceptionMessage(e));
1017          logError(message);
1018        }
1019    
1020    
1021        // Clean up after the export by closing the export config.
1022        exportConfig.close();
1023        if (!errorOccurred)
1024        {
1025          return 0;
1026        }
1027        else
1028        {
1029          return 1;
1030        }
1031      }
1032    }
1033