001/*
002 * The contents of this file are subject to the terms of the Common Development and
003 * Distribution License (the License). You may not use this file except in compliance with the
004 * License.
005 *
006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
007 * specific language governing permission and limitations under the License.
008 *
009 * When distributing Covered Software, include this CDDL Header Notice in each file and include
010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
011 * Header, with the fields enclosed by brackets [] replaced by your own identifying
012 * information: "Portions Copyright [year] [name of copyright owner]".
013 *
014 * Copyright 2008-2009 Sun Microsystems, Inc.
015 * Portions Copyright 2014-2015 ForgeRock AS.
016 */
017
018package org.opends.guitools.controlpanel.ui;
019
020import static org.opends.messages.AdminToolMessages.*;
021
022import static org.opends.messages.QuickSetupMessages.INFO_NO_LDIF_PATH;
023
024import java.awt.Component;
025import java.awt.GridBagConstraints;
026import java.io.File;
027import java.util.ArrayList;
028import java.util.Collection;
029import java.util.HashSet;
030import java.util.LinkedHashSet;
031import java.util.Set;
032import java.util.TreeSet;
033
034import javax.swing.DefaultComboBoxModel;
035import javax.swing.JButton;
036import javax.swing.JCheckBox;
037import javax.swing.JComboBox;
038import javax.swing.JLabel;
039import javax.swing.JTextField;
040import javax.swing.SwingUtilities;
041import javax.swing.event.ChangeEvent;
042import javax.swing.event.ChangeListener;
043import javax.swing.event.DocumentEvent;
044import javax.swing.event.DocumentListener;
045
046import org.opends.guitools.controlpanel.datamodel.ControlPanelInfo;
047import org.opends.guitools.controlpanel.datamodel.ScheduleType;
048import org.opends.guitools.controlpanel.datamodel.ServerDescriptor;
049import org.opends.guitools.controlpanel.event.BrowseActionListener;
050import org.opends.guitools.controlpanel.event.ConfigurationChangeEvent;
051import org.opends.guitools.controlpanel.task.Task;
052import org.opends.guitools.controlpanel.ui.components.ScheduleSummaryPanel;
053import org.opends.guitools.controlpanel.util.Utilities;
054import org.forgerock.i18n.LocalizableMessage;
055import org.opends.server.tools.ExportLDIF;
056
057/**
058 * The panel where the user can export the contents of the server to an LDIF
059 * file.
060 *
061 */
062public class ExportLDIFPanel extends InclusionExclusionPanel
063{
064 private static final long serialVersionUID = 2256902594454214644L;
065  private JComboBox backends;
066  private JTextField file;
067  private JCheckBox overwrite;
068  private JCheckBox compressData;
069  private JCheckBox encryptData;
070  private JCheckBox generateSignedHash;
071  private JCheckBox wrapText;
072  private JTextField wrapColumn;
073  private JButton bBrowse;
074
075  private JLabel lBackend;
076  private JLabel lNoBackendsFound;
077  private JLabel lFile;
078  private JLabel lExportOptions;
079  private JLabel lRemoteFileHelp;
080  private JCheckBox excludeOperationalAttrs;
081
082  private DocumentListener documentListener;
083
084  private ScheduleSummaryPanel schedulePanel;
085
086  /**
087   * Default constructor.
088   *
089   */
090  public ExportLDIFPanel()
091  {
092    super();
093    createLayout();
094  }
095
096  /** {@inheritDoc} */
097  public LocalizableMessage getTitle()
098  {
099    return INFO_CTRL_PANEL_EXPORT_LDIF_TITLE.get();
100  }
101
102  /** {@inheritDoc} */
103  public Component getPreferredFocusComponent()
104  {
105    return file;
106  }
107
108  /** {@inheritDoc} */
109  public void toBeDisplayed(boolean visible)
110  {
111    if (visible)
112    {
113      documentListener.changedUpdate(null);
114    }
115  }
116
117  /**
118   * Creates the layout of the panel (but the contents are not populated here).
119   */
120  private void createLayout()
121  {
122    GridBagConstraints gbc = new GridBagConstraints();
123    gbc.gridx = 0;
124    gbc.gridy = 0;
125    gbc.gridwidth = 4;
126    addErrorPane(gbc);
127
128    gbc.anchor = GridBagConstraints.WEST;
129    gbc.weightx = 0.0;
130    gbc.gridy ++;
131    gbc.gridwidth = 1;
132    gbc.fill = GridBagConstraints.NONE;
133    lBackend = Utilities.createPrimaryLabel(
134        INFO_CTRL_PANEL_BACKEND_LABEL.get());
135    add(lBackend, gbc);
136    gbc.insets.left = 10;
137    gbc.gridx = 1;
138    backends = Utilities.createComboBox();
139    backends.setModel(new DefaultComboBoxModel(new String[]{}));
140    gbc.gridwidth = 3;
141    add(backends, gbc);
142    lNoBackendsFound = Utilities.createDefaultLabel(
143        INFO_CTRL_PANEL_NO_BACKENDS_FOUND_LABEL.get());
144    add(lNoBackendsFound, gbc);
145    lNoBackendsFound.setVisible(false);
146    gbc.insets.top = 10;
147
148    gbc.gridx = 0;
149    gbc.gridy ++;
150    gbc.insets.left = 0;
151    gbc.gridwidth = 1;
152    lFile = Utilities.createPrimaryLabel(
153        INFO_CTRL_PANEL_EXPORT_TO_FILE_LABEL.get());
154    add(lFile, gbc);
155
156    gbc.gridx = 1;
157    gbc.insets.left = 10;
158    gbc.gridwidth = 2;
159    file = Utilities.createTextField();
160    documentListener = new DocumentListener()
161    {
162      /** {@inheritDoc} */
163      public void changedUpdate(DocumentEvent ev)
164      {
165        String text = file.getText().trim();
166        setEnabledOK(text != null && text.length() > 0 && !errorPane.isVisible());
167      }
168      /** {@inheritDoc} */
169      public void removeUpdate(DocumentEvent ev)
170      {
171        changedUpdate(ev);
172      }
173      /** {@inheritDoc} */
174      public void insertUpdate(DocumentEvent ev)
175      {
176        changedUpdate(ev);
177      }
178    };
179    file.getDocument().addDocumentListener(documentListener);
180    gbc.weightx = 1.0;
181    gbc.fill = GridBagConstraints.HORIZONTAL;
182    add(file, gbc);
183    bBrowse = Utilities.createButton(
184        INFO_CTRL_PANEL_BROWSE_BUTTON_LABEL.get());
185    bBrowse.addActionListener(
186        new BrowseActionListener(file,
187            BrowseActionListener.BrowseType.CREATE_LDIF_FILE,  this));
188    gbc.gridx = 3;
189    gbc.gridwidth = 1;
190    gbc.weightx = 0.0;
191    bBrowse.setOpaque(false);
192    add(bBrowse, gbc);
193
194    lRemoteFileHelp = Utilities.createInlineHelpLabel(
195        INFO_CTRL_PANEL_REMOTE_SERVER_PATH.get());
196    gbc.gridx = 1;
197    gbc.insets.top = 3;
198    gbc.insets.left = 10;
199    gbc.gridy ++;
200    gbc.gridwidth = 3;
201    add(lRemoteFileHelp, gbc);
202
203    gbc.gridx = 1;
204    gbc.gridy ++;
205    gbc.insets.left = 30;
206    gbc.insets.top = 5;
207    gbc.gridwidth = 3;
208    overwrite =
209      Utilities.createCheckBox(INFO_CTRL_PANEL_EXPORT_OVERWRITE_LABEL.get());
210    overwrite.setOpaque(false);
211    add(overwrite, gbc);
212
213    gbc.gridx = 0;
214    gbc.gridy ++;
215    gbc.insets.left = 0;
216    gbc.insets.top = 10;
217    gbc.gridwidth = 1;
218    lExportOptions =
219      Utilities.createPrimaryLabel(INFO_CTRL_PANEL_EXPORT_OPTIONS.get());
220    add(lExportOptions, gbc);
221
222    schedulePanel = new ScheduleSummaryPanel(
223        INFO_CTRL_PANEL_EXPORT_LDIF_TITLE.get().toString());
224    schedulePanel.setSchedule(ScheduleType.createLaunchNow());
225
226    gbc.insets.left = 10;
227    gbc.gridx = 1;
228    gbc.gridwidth = 3;
229    add(schedulePanel, gbc);
230
231    compressData = Utilities.createCheckBox(
232        INFO_CTRL_PANEL_COMPRESS_DATA_LABEL.get());
233    compressData.setSelected(false);
234
235    gbc.gridy ++;
236    gbc.insets.top = 5;
237    add(compressData, gbc);
238
239    encryptData = Utilities.createCheckBox(
240        INFO_CTRL_PANEL_ENCRYPT_DATA_LABEL.get());
241
242    /*
243    gbc.gridy ++;
244    gbc.insets.top = 5;
245    add(encryptData, gbc);
246*/
247    generateSignedHash = Utilities.createCheckBox(
248        INFO_CTRL_PANEL_EXPORT_GENERATE_SIGNED_HASH.get());
249
250    encryptData.addChangeListener(new ChangeListener()
251    {
252      /** {@inheritDoc} */
253      public void stateChanged(ChangeEvent ev)
254      {
255        generateSignedHash.setEnabled(encryptData.isSelected());
256      }
257    });
258    encryptData.setSelected(false);
259    generateSignedHash.setEnabled(false);
260
261    /*
262    gbc.gridy ++;
263    gbc.insets.left = 30;
264    add(generateSignedHash, gbc);
265*/
266    wrapText = Utilities.createCheckBox(INFO_CTRL_PANEL_EXPORT_WRAP_TEXT.get());
267    wrapText.setOpaque(false);
268    gbc.insets.left = 10;
269    gbc.insets.top = 10;
270    gbc.gridy ++;
271    gbc.gridwidth = 1;
272    add(wrapText, gbc);
273
274    gbc.insets.left = 5;
275    gbc.gridx = 2;
276    wrapColumn = Utilities.createTextField("80", 4);
277    gbc.fill = GridBagConstraints.NONE;
278    add(wrapColumn, gbc);
279    gbc.fill = GridBagConstraints.HORIZONTAL;
280
281    wrapText.addChangeListener(new ChangeListener()
282    {
283      /** {@inheritDoc} */
284      public void stateChanged(ChangeEvent ev)
285      {
286        wrapColumn.setEnabled(wrapText.isSelected());
287      }
288    });
289    wrapColumn.setEnabled(false);
290    wrapText.setSelected(false);
291
292    gbc.insets.top = 10;
293    gbc.insets.left = 0;
294    gbc.gridy ++;
295    gbc.gridx = 0;
296    gbc.gridwidth = 4;
297    gbc.fill = GridBagConstraints.HORIZONTAL;
298    excludeOperationalAttrs = Utilities.createCheckBox(
299        INFO_CTRL_PANEL_EXCLUDE_OPERATIONAL_ATTRIBUTES.get());
300    excludeOperationalAttrs.setOpaque(false);
301    add(createDataExclusionOptions(new JLabel[]{null},
302        new Component[]{excludeOperationalAttrs}), gbc);
303    gbc.gridy ++;
304    gbc.insets.top = 15;
305    add(createDataInclusionOptions(new JLabel[]{}, new Component[]{}), gbc);
306    addBottomGlue(gbc);
307  }
308
309  /** {@inheritDoc} */
310  public void configurationChanged(ConfigurationChangeEvent ev)
311  {
312    ServerDescriptor desc = ev.getNewDescriptor();
313    updateSimpleBackendComboBoxModel(backends, lNoBackendsFound,
314        ev.getNewDescriptor());
315
316    updateErrorPaneAndOKButtonIfAuthRequired(desc,
317       isLocal() ? INFO_CTRL_PANEL_AUTHENTICATION_REQUIRED_FOR_EXPORT.get() :
318      INFO_CTRL_PANEL_CANNOT_CONNECT_TO_REMOTE_DETAILS.get(desc.getHostname()));
319
320    SwingUtilities.invokeLater(new Runnable()
321    {
322      public void run()
323      {
324        lRemoteFileHelp.setVisible(!isLocal());
325        bBrowse.setVisible(isLocal());
326      }
327    });
328  }
329
330  /** {@inheritDoc} */
331  protected void checkOKButtonEnable()
332  {
333    documentListener.changedUpdate(null);
334  }
335
336  /** {@inheritDoc} */
337  public void okClicked()
338  {
339    setPrimaryValid(lBackend);
340    setPrimaryValid(lFile);
341    setPrimaryValid(lExportOptions);
342    final LinkedHashSet<LocalizableMessage> errors = new LinkedHashSet<>();
343
344    String backendName = (String)backends.getSelectedItem();
345    if (backendName == null)
346    {
347      errors.add(ERR_CTRL_PANEL_NO_BACKEND_SELECTED.get());
348      setPrimaryInvalid(lBackend);
349    }
350
351    String ldifPath = file.getText();
352    if (ldifPath == null || ldifPath.trim().equals(""))
353    {
354      errors.add(INFO_NO_LDIF_PATH.get());
355      setPrimaryInvalid(lFile);
356    }
357    else if (isLocal())
358    {
359      File f = new File(ldifPath);
360      if (f.isDirectory())
361      {
362        errors.add(ERR_CTRL_PANEL_EXPORT_DIRECTORY_PROVIDED.get(ldifPath));
363      }
364    }
365
366    addScheduleErrors(getSchedule(), errors, lExportOptions);
367    if (wrapText.isSelected())
368    {
369      final String cols = wrapColumn.getText();
370      final int minValue = 1;
371      final int maxValue = 1000;
372      final LocalizableMessage errMsg = ERR_CTRL_PANEL_INVALID_WRAP_COLUMN.get(minValue, maxValue);
373      if (!checkIntValue(errors, cols, minValue, maxValue, errMsg))
374      {
375        setPrimaryInvalid(lExportOptions);
376      }
377    }
378
379    updateIncludeExclude(errors, backendName);
380
381    if (errors.isEmpty())
382    {
383      ProgressDialog progressDialog = new ProgressDialog(
384          Utilities.createFrame(),
385          Utilities.getParentDialog(this), getTitle(), getInfo());
386      ExportTask newTask = new ExportTask(getInfo(), progressDialog);
387      for (Task task : getInfo().getTasks())
388      {
389        task.canLaunch(newTask, errors);
390      }
391      boolean confirmed = true;
392      if (errors.isEmpty())
393      {
394        File f = new File(ldifPath);
395        if (overwrite.isSelected() && f.exists())
396        {
397          confirmed = displayConfirmationDialog(
398              INFO_CTRL_PANEL_CONFIRMATION_REQUIRED_SUMMARY.get(),
399              INFO_CTRL_PANEL_CONFIRMATION_EXPORT_LDIF_DETAILS.get(ldifPath));
400        }
401      }
402      if (errors.isEmpty() && confirmed)
403      {
404        launchOperation(newTask,
405            INFO_CTRL_PANEL_EXPORTING_LDIF_SUMMARY.get(backends.getSelectedItem()),
406            INFO_CTRL_PANEL_EXPORTING_LDIF_SUCCESSFUL_SUMMARY.get(),
407            INFO_CTRL_PANEL_EXPORTING_LDIF_SUCCESSFUL_DETAILS.get(),
408            ERR_CTRL_PANEL_EXPORTING_LDIF_ERROR_SUMMARY.get(),
409            null,
410            ERR_CTRL_PANEL_EXPORTING_LDIF_ERROR_DETAILS,
411            progressDialog);
412        progressDialog.setVisible(true);
413        Utilities.getParentDialog(this).setVisible(false);
414      }
415    }
416    if (!errors.isEmpty())
417    {
418      displayErrorDialog(errors);
419    }
420  }
421
422  /** {@inheritDoc} */
423  public void cancelClicked()
424  {
425    setPrimaryValid(lBackend);
426    setPrimaryValid(lFile);
427    setPrimaryValid(lExportOptions);
428    super.cancelClicked();
429  }
430
431  private ScheduleType getSchedule()
432  {
433    return schedulePanel.getSchedule();
434  }
435
436  /**
437   * The class that performs the export.
438   *
439   */
440  protected class ExportTask extends InclusionExclusionTask
441  {
442    private Set<String> backendSet;
443    private String fileName;
444    /**
445     * The constructor of the task.
446     * @param info the control panel info.
447     * @param dlg the progress dialog that shows the progress of the task.
448     */
449    public ExportTask(ControlPanelInfo info, ProgressDialog dlg)
450    {
451      super(info, dlg);
452      backendSet = new HashSet<>();
453      backendSet.add((String)backends.getSelectedItem());
454      fileName = file.getText();
455    }
456
457    /** {@inheritDoc} */
458    public Type getType()
459    {
460      return Type.EXPORT_LDIF;
461    }
462
463    /** {@inheritDoc} */
464    public LocalizableMessage getTaskDescription()
465    {
466      return INFO_CTRL_PANEL_EXPORT_TASK_DESCRIPTION.get(
467          backendSet.iterator().next(), fileName);
468    }
469
470    /** {@inheritDoc} */
471    public boolean canLaunch(Task taskToBeLaunched,
472        Collection<LocalizableMessage> incompatibilityReasons)
473    {
474      boolean canLaunch = true;
475      if (state == State.RUNNING && runningOnSameServer(taskToBeLaunched))
476      {
477        // All the operations are incompatible if they apply to this backend.
478        Set<String> backends = new TreeSet<>(taskToBeLaunched.getBackends());
479        backends.retainAll(getBackends());
480        if (!backends.isEmpty())
481        {
482          incompatibilityReasons.add(getIncompatibilityMessage(this, taskToBeLaunched));
483          canLaunch = false;
484        }
485      }
486      return canLaunch;
487    }
488
489    /** {@inheritDoc} */
490    public void runTask()
491    {
492      state = State.RUNNING;
493      lastException = null;
494      try
495      {
496        ArrayList<String> arguments = getCommandLineArguments();
497
498        String[] args = new String[arguments.size()];
499
500        arguments.toArray(args);
501        if (isServerRunning())
502        {
503          returnCode = ExportLDIF.mainExportLDIF(args, false, outPrintStream,
504              errorPrintStream);
505        }
506        else
507        {
508          returnCode = executeCommandLine(getCommandLinePath(), args);
509        }
510        if (returnCode != 0)
511        {
512          state = State.FINISHED_WITH_ERROR;
513        }
514        else
515        {
516          state = State.FINISHED_SUCCESSFULLY;
517        }
518      }
519      catch (Throwable t)
520      {
521        lastException = t;
522        state = State.FINISHED_WITH_ERROR;
523      }
524    }
525
526    /** {@inheritDoc} */
527    public Set<String> getBackends()
528    {
529      return backendSet;
530    }
531
532    /** {@inheritDoc} */
533    protected ArrayList<String> getCommandLineArguments()
534    {
535      ArrayList<String> args = new ArrayList<>();
536      args.add("--ldifFile");
537      args.add(fileName);
538      args.add("--backendID");
539      args.add(backendSet.iterator().next());
540
541      if (!overwrite.isSelected())
542      {
543        args.add("--appendToLDIF");
544      }
545
546      if (compressData.isSelected())
547      {
548        args.add("--compress");
549      }
550      if (wrapText.isSelected())
551      {
552        args.add("--wrapColumn");
553        args.add(wrapColumn.getText().trim());
554      }
555      if (excludeOperationalAttrs.isSelected())
556      {
557        args.add("--excludeOperational");
558      }
559
560      args.addAll(super.getCommandLineArguments());
561
562      args.addAll(getScheduleArgs(getSchedule()));
563
564      if (isServerRunning())
565      {
566        args.addAll(getConfigCommandLineArguments());
567      }
568      args.add(getNoPropertiesFileArgument());
569
570      return args;
571    }
572
573    /** {@inheritDoc} */
574    protected String getCommandLinePath()
575    {
576      return getCommandLinePath("export-ldif");
577    }
578  }
579}