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-2016 ForgeRock AS.
016 */
017package org.opends.guitools.controlpanel.ui;
018
019import static org.opends.messages.AdminToolMessages.*;
020
021import java.awt.Component;
022import java.awt.GridBagConstraints;
023import java.awt.GridBagLayout;
024import java.io.File;
025import java.text.SimpleDateFormat;
026import java.util.ArrayList;
027import java.util.Collection;
028import java.util.Date;
029import java.util.HashSet;
030import java.util.LinkedHashSet;
031import java.util.Set;
032import java.util.TreeSet;
033
034import javax.swing.ButtonGroup;
035import javax.swing.DefaultComboBoxModel;
036import javax.swing.JCheckBox;
037import javax.swing.JComboBox;
038import javax.swing.JComponent;
039import javax.swing.JLabel;
040import javax.swing.JPanel;
041import javax.swing.JRadioButton;
042import javax.swing.JTextField;
043import javax.swing.SwingUtilities;
044import javax.swing.event.ChangeEvent;
045import javax.swing.event.ChangeListener;
046
047import org.forgerock.i18n.LocalizableMessage;
048import org.forgerock.i18n.slf4j.LocalizedLogger;
049import org.opends.guitools.controlpanel.datamodel.BackendDescriptor;
050import org.opends.guitools.controlpanel.datamodel.BackupDescriptor;
051import org.opends.guitools.controlpanel.datamodel.ControlPanelInfo;
052import org.opends.guitools.controlpanel.datamodel.ScheduleType;
053import org.opends.guitools.controlpanel.datamodel.ServerDescriptor;
054import org.opends.guitools.controlpanel.event.ConfigurationChangeEvent;
055import org.opends.guitools.controlpanel.task.Task;
056import org.opends.guitools.controlpanel.ui.components.ScheduleSummaryPanel;
057import org.opends.guitools.controlpanel.util.BackgroundTask;
058import org.opends.guitools.controlpanel.util.Utilities;
059import org.opends.server.tools.BackUpDB;
060import org.opends.server.types.BackupDirectory;
061import org.opends.server.types.BackupInfo;
062import org.opends.server.util.ServerConstants;
063
064/** The panel that appears when the user clicks on 'Backup...'. */
065public class BackupPanel extends BackupListPanel
066{
067  private static final long serialVersionUID = -1626301350756394814L;
068  private JComboBox backends;
069  private JCheckBox allBackends;
070  private JTextField backupID;
071  private JTextField parentBackupID;
072  private JRadioButton fullBackup;
073  private JCheckBox incrementalParent;
074  private JRadioButton incrementalBackup;
075  private JCheckBox compressData;
076  private JCheckBox encryptData;
077  private JCheckBox generateMessageDigest;
078  private JCheckBox signMessageDigest;
079
080  private JLabel lBackend;
081  private JLabel lNoBackendsFound;
082  private JLabel lBackupID;
083  private JLabel lParentID;
084  private JLabel lBackupType;
085  private JLabel lBackupOptions;
086
087  private ChangeListener changeListener;
088
089  private boolean backupIDInitialized;
090
091  private ScheduleSummaryPanel schedulePanel;
092
093  private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
094
095  /** Default constructor. */
096  public BackupPanel()
097  {
098    super();
099    createLayout();
100  }
101
102  @Override
103  public LocalizableMessage getTitle()
104  {
105    return INFO_CTRL_PANEL_BACKUP_TITLE.get();
106  }
107
108  @Override
109  public Component getPreferredFocusComponent()
110  {
111    return backupID;
112  }
113
114  @Override
115  protected void verifyBackupClicked()
116  {
117    // Nothing to do: the button is not visible.
118  }
119
120  /** Creates the layout of the panel (but the contents are not populated here). */
121  private void createLayout()
122  {
123    GridBagConstraints gbc = new GridBagConstraints();
124    gbc.anchor = GridBagConstraints.WEST;
125    gbc.gridx = 0;
126    gbc.gridy = 0;
127    gbc.gridwidth = 3;
128    addErrorPane(gbc);
129
130    gbc.weightx = 0.0;
131    gbc.gridy ++;
132    gbc.gridwidth = 1;
133    gbc.fill = GridBagConstraints.NONE;
134    lBackend = Utilities.createPrimaryLabel(
135        INFO_CTRL_PANEL_BACKEND_LABEL.get());
136    add(lBackend, gbc);
137    gbc.insets.left = 10;
138    gbc.gridx = 1;
139    gbc.gridwidth = 2;
140    JPanel auxPanel = new JPanel(new GridBagLayout());
141    add(auxPanel, gbc);
142    auxPanel.setOpaque(false);
143    GridBagConstraints gbc2 = new GridBagConstraints();
144    backends = Utilities.createComboBox();
145    backends.setModel(new DefaultComboBoxModel(new String[]{}));
146    auxPanel.add(backends, gbc2);
147    lNoBackendsFound = Utilities.createDefaultLabel(
148        INFO_CTRL_PANEL_NO_BACKENDS_FOUND_LABEL.get());
149    add(lNoBackendsFound, gbc);
150    lNoBackendsFound.setVisible(false);
151    gbc2.insets.left = 10;
152    allBackends = Utilities.createCheckBox(
153        INFO_CTRL_PANEL_BACKUP_ALL_BACKENDS_LABEL.get());
154    auxPanel.add(allBackends, gbc2);
155
156    gbc.insets.top = 10;
157    gbc.gridx = 0;
158    gbc.gridy ++;
159    gbc.insets.left = 0;
160    gbc.gridwidth = 1;
161    lBackupType = Utilities.createPrimaryLabel(
162        INFO_CTRL_PANEL_BACKUP_TYPE_LABEL.get());
163    add(lBackupType, gbc);
164    gbc.insets.left = 10;
165    gbc.gridx = 1;
166    gbc.gridwidth = 2;
167    fullBackup = Utilities.createRadioButton(
168        INFO_CTRL_PANEL_FULL_BACKUP_LABEL.get());
169    add(fullBackup, gbc);
170
171    gbc.gridy ++;
172    gbc.insets.top = 5;
173    incrementalBackup = Utilities.createRadioButton(
174        INFO_CTRL_PANEL_INCREMENTAL_BACKUP_LABEL.get());
175    add(incrementalBackup, gbc);
176
177    gbc.gridy ++;
178    gbc.insets.left = 25;
179    incrementalParent = Utilities.createCheckBox(
180        INFO_CTRL_PANEL_INCREMENTAL_PARENT_LABEL.get());
181    add(incrementalParent, gbc);
182
183    ButtonGroup group = new ButtonGroup();
184    group.add(fullBackup);
185    group.add(incrementalBackup);
186    fullBackup.setSelected(true);
187
188    gbc.insets.top = 10;
189    gbc.gridx = 0;
190    gbc.gridy ++;
191    gbc.insets.left = 0;
192    gbc.gridwidth = 1;
193    lBackupID = Utilities.createPrimaryLabel(
194        INFO_CTRL_PANEL_BACKUP_ID_LABEL.get());
195    add(lBackupID, gbc);
196    backupID = Utilities.createMediumTextField();
197    gbc.weightx = 0.0;
198    gbc.gridx ++;
199    gbc.insets.left = 10;
200    gbc.fill = GridBagConstraints.NONE;
201    gbc.gridwidth = 2;
202    add(backupID, gbc);
203
204    gbc.insets.top = 10;
205    gbc.gridx = 0;
206    gbc.gridy ++;
207    super.createLayout(gbc);
208
209    verifyBackup.setVisible(false);
210    lAvailableBackups.setText(
211        INFO_CTRL_PANEL_AVAILABLE_PARENT_BACKUPS_LABEL.get().toString());
212    gbc.gridx = 0;
213    gbc.gridy ++;
214    gbc.insets.left = 0;
215    gbc.insets.top = 10;
216    gbc.gridwidth = 1;
217    gbc.anchor = GridBagConstraints.WEST;
218    lParentID = Utilities.createPrimaryLabel(
219        INFO_CTRL_PANEL_PARENT_BACKUP_ID_LABEL.get());
220    add(lParentID, gbc);
221    parentBackupID = Utilities.createMediumTextField();
222    gbc.weightx = 0.0;
223    gbc.gridx ++;
224    gbc.insets.left = 10;
225    gbc.fill = GridBagConstraints.NONE;
226    gbc.gridwidth = 2;
227    add(parentBackupID, gbc);
228
229    gbc.gridy ++;
230    gbc.gridx = 0;
231    gbc.gridwidth = 1;
232    gbc.insets.left = 0;
233    lBackupOptions = Utilities.createPrimaryLabel(
234        INFO_CTRL_PANEL_BACKUP_OPTIONS_LABEL.get());
235    add(lBackupOptions, gbc);
236
237    schedulePanel = new ScheduleSummaryPanel(
238        INFO_CTRL_PANEL_BACKUP_TASK_NAME.get().toString());
239    schedulePanel.setSchedule(ScheduleType.createLaunchNow());
240
241    gbc.insets.left = 10;
242    gbc.gridx = 1;
243    gbc.gridwidth = 2;
244    add(schedulePanel, gbc);
245
246    compressData = Utilities.createCheckBox(
247        INFO_CTRL_PANEL_COMPRESS_DATA_LABEL.get());
248    compressData.setSelected(false);
249
250    gbc.gridy ++;
251    gbc.insets.top = 5;
252    add(compressData, gbc);
253
254    encryptData = Utilities.createCheckBox(
255        INFO_CTRL_PANEL_ENCRYPT_DATA_LABEL.get());
256
257    gbc.gridy ++;
258    add(encryptData, gbc);
259    encryptData.setSelected(false);
260    generateMessageDigest = Utilities.createCheckBox(
261        INFO_CTRL_PANEL_GENERATE_MESSAGE_DIGEST_LABEL.get());
262
263    gbc.gridy ++;
264    add(generateMessageDigest, gbc);
265
266    signMessageDigest = Utilities.createCheckBox(
267        INFO_CTRL_PANEL_SIGN_MESSAGE_DIGEST_HASH_LABEL.get());
268    gbc.insets.left = 30;
269    gbc.gridy ++;
270    add(signMessageDigest, gbc);
271    generateMessageDigest.setSelected(false);
272
273    changeListener = new ChangeListener()
274    {
275      @Override
276      public void stateChanged(ChangeEvent ev)
277      {
278        backends.setEnabled(!allBackends.isSelected());
279        signMessageDigest.setEnabled(generateMessageDigest.isSelected());
280        incrementalParent.setEnabled(incrementalBackup.isSelected());
281        boolean enable = isIncrementalWithParent();
282        refreshList.setEnabled(enable);
283        tableScroll.setEnabled(enable);
284        backupList.setEnabled(enable);
285        lAvailableBackups.setEnabled(enable);
286        lRefreshingList.setEnabled(enable);
287        lParentID.setEnabled(enable);
288        parentBackupID.setEnabled(enable);
289        verifyBackup.setEnabled(enable && getSelectedBackup() != null);
290      }
291    };
292    incrementalBackup.addChangeListener(changeListener);
293    incrementalParent.addChangeListener(changeListener);
294    generateMessageDigest.addChangeListener(changeListener);
295    allBackends.addChangeListener(changeListener);
296    changeListener.stateChanged(null);
297
298    addBottomGlue(gbc);
299  }
300
301  /**
302   * Check status of incremental backup radio/checkbox.
303   *
304   * @return boolean true if both incremental and parent base ID
305   *                  are selected
306   */
307  private boolean isIncrementalWithParent()
308  {
309    return incrementalParent.isSelected() &&
310            incrementalBackup.isSelected();
311  }
312
313  @Override
314  public void configurationChanged(ConfigurationChangeEvent ev)
315  {
316    final ServerDescriptor desc = ev.getNewDescriptor();
317    updateSimpleBackendComboBoxModel(backends, lNoBackendsFound, desc);
318    SwingUtilities.invokeLater(new Runnable()
319    {
320      @Override
321      public void run()
322      {
323        allBackends.setVisible(backends.getModel().getSize() > 0);
324        lParentID.setVisible(!desc.isLocal());
325        parentBackupID.setVisible(!desc.isLocal());
326        if (desc.isLocal())
327        {
328          lPath.setText(INFO_CTRL_PANEL_BACKUP_PATH_LABEL.get().toString());
329        }
330        else
331        {
332          lPath.setText(
333              INFO_CTRL_PANEL_PARENT_BACKUP_PATH_LABEL.get().toString());
334        }
335      }
336    });
337    super.configurationChanged(ev);
338    updateErrorPaneAndOKButtonIfAuthRequired(desc,
339        isLocal() ? INFO_CTRL_PANEL_AUTHENTICATION_REQUIRED_FOR_BACKUP.get() :
340      INFO_CTRL_PANEL_CANNOT_CONNECT_TO_REMOTE_DETAILS.get(desc.getHostname()));
341  }
342
343  @Override
344  public void okClicked()
345  {
346    setPrimaryValid(lBackend);
347    setPrimaryValid(lPath);
348    setPrimaryValid(lAvailableBackups);
349    setPrimaryValid(lParentID);
350    setPrimaryValid(lBackupOptions);
351    backupIDInitialized = false;
352
353    final LinkedHashSet<LocalizableMessage> errors = new LinkedHashSet<>();
354
355    if (!allBackends.isSelected())
356    {
357      String backendName = (String)backends.getSelectedItem();
358      if (backendName == null)
359      {
360        errors.add(ERR_CTRL_PANEL_NO_BACKENDS_SELECTED.get());
361        setPrimaryInvalid(lBackend);
362      }
363    }
364    else
365    {
366      if (backends.getModel().getSize() == 0)
367      {
368        errors.add(ERR_CTRL_PANEL_NO_BACKENDS_AVAILABLE.get());
369        setPrimaryInvalid(lBackend);
370      }
371    }
372
373    String parentPath = parentDirectory.getText();
374    if (parentPath == null || parentPath.trim().equals(""))
375    {
376      errors.add(ERR_CTRL_PANEL_NO_BACKUP_PATH_PROVIDED.get());
377      setPrimaryInvalid(lPath);
378    }
379    else if (isLocal())
380    {
381      File f = new File(parentPath);
382      if (f.isFile())
383      {
384        errors.add(ERR_CTRL_PANEL_BACKUP_PATH_IS_A_FILE.get(parentPath));
385        setPrimaryInvalid(lPath);
386      }
387      else if (!f.exists())
388      {
389        errors.add(ERR_CTRL_PANEL_BACKUP_PATH_DOES_NOT_EXIST.get(parentPath));
390        setPrimaryInvalid(lPath);
391      }
392    }
393    String dir = backupID.getText();
394    if (dir == null || dir.trim().equals(""))
395    {
396      errors.add(ERR_CTRL_PANEL_NO_BACKUP_ID_PROVIDED.get());
397      setPrimaryInvalid(lBackupID);
398    }
399
400    if (errors.isEmpty() && isLocal())
401    {
402      File f = new File(parentPath, dir);
403      if (f.isFile())
404      {
405        errors.add(ERR_CTRL_PANEL_BACKUP_PATH_EXISTS.get(
406            f.getAbsolutePath()));
407        setPrimaryInvalid(lPath);
408      }
409    }
410
411    if (isIncrementalWithParent())
412    {
413      if (isLocal())
414      {
415        boolean selected = backupList.isVisible() && getSelectedBackup() != null;
416        if (!selected)
417        {
418          errors.add(ERR_CTRL_PANEL_NO_PARENT_BACKUP_SELECTED.get());
419          setPrimaryInvalid(lAvailableBackups);
420        }
421      }
422      else
423      {
424        String parentID = parentBackupID.getText();
425        if (parentID == null || parentID.trim().equals(""))
426        {
427          errors.add(ERR_CTRL_PANEL_NO_PARENT_BACKUP_ID_PROVIDED.get());
428          setPrimaryInvalid(lParentID);
429        }
430      }
431    }
432
433    addScheduleErrors(getSchedule(), errors, lBackupOptions);
434
435    // Check that there is not a backup with the provided ID
436    final JComponent[] components =
437    {
438        backends, allBackends, fullBackup, incrementalBackup, parentDirectory,
439        browse, backupList, refreshList, compressData, encryptData,
440        generateMessageDigest, signMessageDigest, incrementalParent
441    };
442    setEnabledOK(false);
443    setEnabledCancel(false);
444    for (JComponent component : components)
445    {
446      component.setEnabled(false);
447    }
448    final String id = backupID.getText();
449    final String path = parentDirectory.getText();
450    BackgroundTask<Void> worker = new BackgroundTask<Void>()
451    {
452      @Override
453      public Void processBackgroundTask() throws Throwable
454      {
455        // Open the backup directory and make sure it is valid.
456        LinkedHashSet<BackupInfo> backups = new LinkedHashSet<>();
457        try
458        {
459          BackupDirectory backupDir =
460            BackupDirectory.readBackupDirectoryDescriptor(path);
461          backups.addAll(backupDir.getBackups().values());
462        }
463        catch (Throwable t)
464        {
465          // Check the subdirectories
466          File f = new File(path);
467
468          if (f.isDirectory())
469          {
470            File[] children = f.listFiles();
471            for (int i=0; i<children.length; i++)
472            {
473              if (children[i].isDirectory())
474              {
475                try
476                {
477                  BackupDirectory backupDir =
478                    BackupDirectory.readBackupDirectoryDescriptor(
479                        children[i].getAbsolutePath());
480
481                  backups.addAll(backupDir.getBackups().values());
482                }
483                catch (Throwable t2)
484                {
485                  if (!children[i].getName().equals("tasks"))
486                  {
487                    logger.warn(LocalizableMessage.raw("Error searching backup: "+t2, t2));
488                  }
489                }
490              }
491            }
492          }
493        }
494        for (BackupInfo backup : backups)
495        {
496          if (backup.getBackupID().equalsIgnoreCase(id))
497          {
498            errors.add(ERR_CTRL_PANEL_BACKUP_ID_ALREADY_EXIST.get(id, path));
499            SwingUtilities.invokeLater(new Runnable()
500            {
501              @Override
502              public void run()
503              {
504                setPrimaryInvalid(lBackupID);
505              }
506            });
507            break;
508          }
509        }
510        return null;
511      }
512      @Override
513      public void backgroundTaskCompleted(Void returnValue, Throwable t)
514      {
515        for (JComponent component : components)
516        {
517          component.setEnabled(true);
518        }
519        setEnabledOK(true);
520        setEnabledCancel(true);
521        changeListener.stateChanged(null);
522        if (errors.isEmpty())
523        {
524          ProgressDialog progressDialog = new ProgressDialog(
525              Utilities.createFrame(),
526              Utilities.getParentDialog(BackupPanel.this),
527              getTitle(), getInfo());
528          BackupTask newTask = new BackupTask(getInfo(), progressDialog);
529          for (Task task : getInfo().getTasks())
530          {
531            task.canLaunch(newTask, errors);
532          }
533          if (errors.isEmpty())
534          {
535            LocalizableMessage initMsg;
536            if (allBackends.isSelected())
537            {
538              initMsg = INFO_CTRL_PANEL_RUN_BACKUP_ALL_BACKENDS.get();
539            }
540            else
541            {
542              initMsg = INFO_CTRL_PANEL_RUN_BACKUP_SUMMARY.get(
543                  backends.getSelectedItem());
544            }
545            launchOperation(newTask,
546                initMsg,
547                INFO_CTRL_PANEL_RUN_BACKUP_SUCCESSFUL_SUMMARY.get(),
548                INFO_CTRL_PANEL_RUN_BACKUP_SUCCESSFUL_DETAILS.get(),
549                ERR_CTRL_PANEL_RUN_BACKUP_ERROR_SUMMARY.get(),
550                null,
551                ERR_CTRL_PANEL_RUN_BACKUP_ERROR_DETAILS,
552                progressDialog);
553            progressDialog.setVisible(true);
554            Utilities.getParentDialog(BackupPanel.this).setVisible(false);
555          }
556        }
557        if (!errors.isEmpty())
558        {
559          displayErrorDialog(errors);
560        }
561      }
562    };
563    if (errors.isEmpty())
564    {
565      worker.startBackgroundTask();
566    }
567    else
568    {
569      worker.backgroundTaskCompleted(null, null);
570    }
571  }
572
573  private ScheduleType getSchedule()
574  {
575    return schedulePanel.getSchedule();
576  }
577
578  @Override
579  public void cancelClicked()
580  {
581    setPrimaryValid(lBackend);
582    setPrimaryValid(lPath);
583    setPrimaryValid(lAvailableBackups);
584    setPrimaryValid(lBackupOptions);
585
586    super.cancelClicked();
587  }
588
589  @Override
590  public void toBeDisplayed(boolean visible)
591  {
592    super.toBeDisplayed(visible);
593    if (visible && !backupIDInitialized)
594    {
595      initializeBackupID();
596    }
597    if (!visible)
598    {
599      backupIDInitialized = false;
600    }
601  }
602
603  /** Initialize the backup ID field with a value. */
604  private void initializeBackupID()
605  {
606    SimpleDateFormat dateFormat = new SimpleDateFormat(
607        ServerConstants.DATE_FORMAT_COMPACT_LOCAL_TIME);
608    final String id = dateFormat.format(new Date());
609    backupID.setText(id);
610  }
611
612  /** Class that launches the backup. */
613  private class BackupTask extends Task
614  {
615    private Set<String> backendSet;
616    private String dir;
617    /**
618     * The constructor of the task.
619     * @param info the control panel info.
620     * @param dlg the progress dialog that shows the progress of the task.
621     */
622    private BackupTask(ControlPanelInfo info, ProgressDialog dlg)
623    {
624      super(info, dlg);
625      backendSet = new HashSet<>();
626      if (!allBackends.isSelected())
627      {
628        backendSet.add((String)backends.getSelectedItem());
629      }
630      else
631      {
632        for (BackendDescriptor backend :
633          info.getServerDescriptor().getBackends())
634        {
635          if (!backend.isConfigBackend())
636          {
637            backendSet.add(backend.getBackendID());
638          }
639        }
640      }
641      if (isIncrementalWithParent())
642      {
643        if (isLocal())
644        {
645          BackupDescriptor backup = getSelectedBackup();
646          dir = backup.getPath().getAbsolutePath();
647        }
648        else
649        {
650          dir = parentDirectory.getText();
651        }
652      }
653      else
654      {
655        dir = parentDirectory.getText();
656      }
657    }
658
659    @Override
660    public Type getType()
661    {
662      return Type.BACKUP;
663    }
664
665    @Override
666    public LocalizableMessage getTaskDescription()
667    {
668      return INFO_CTRL_PANEL_BACKUP_TASK_DESCRIPTION.get(
669      Utilities.getStringFromCollection(backendSet, ", "), dir);
670    }
671
672    @Override
673    public boolean canLaunch(Task taskToBeLaunched,
674        Collection<LocalizableMessage> incompatibilityReasons)
675    {
676      boolean canLaunch = true;
677      if (state == State.RUNNING && runningOnSameServer(taskToBeLaunched))
678      {
679        // All the operations are incompatible if they apply to this backend.
680        Set<String> backends = new TreeSet<>(taskToBeLaunched.getBackends());
681        backends.retainAll(getBackends());
682        if (!backends.isEmpty())
683        {
684          incompatibilityReasons.add(getIncompatibilityMessage(this, taskToBeLaunched));
685          canLaunch = false;
686        }
687      }
688      return canLaunch;
689    }
690
691    @Override
692    public void runTask()
693    {
694      state = State.RUNNING;
695      lastException = null;
696      try
697      {
698        ArrayList<String> arguments = getCommandLineArguments();
699
700        String[] args = new String[arguments.size()];
701
702        arguments.toArray(args);
703        if (isServerRunning())
704        {
705          returnCode = BackUpDB.mainBackUpDB(args, false, outPrintStream,
706              errorPrintStream);
707        }
708        else
709        {
710          returnCode = executeCommandLine(getCommandLinePath(), args);
711        }
712        if (returnCode != 0)
713        {
714          state = State.FINISHED_WITH_ERROR;
715        }
716        else
717        {
718          getInfo().backupCreated(
719              new BackupDescriptor(
720                  new File(parentDirectory.getText()),
721                  new Date(),
722                  fullBackup.isSelected() ? BackupDescriptor.Type.FULL :
723                    BackupDescriptor.Type.INCREMENTAL,
724                  backupID.getText()));
725          state = State.FINISHED_SUCCESSFULLY;
726        }
727      }
728      catch (Throwable t)
729      {
730        lastException = t;
731        state = State.FINISHED_WITH_ERROR;
732      }
733    }
734
735    @Override
736    public Set<String> getBackends()
737    {
738      return backendSet;
739    }
740
741    @Override
742    protected ArrayList<String> getCommandLineArguments()
743    {
744      ArrayList<String> args = new ArrayList<>();
745
746      args.add("--backupDirectory");
747      args.add(dir);
748
749      args.add("--backupID");
750      args.add(backupID.getText());
751
752      if (allBackends.isSelected())
753      {
754        args.add("--backUpAll");
755      }
756      else
757      {
758        args.add("--backendID");
759        args.add((String)backends.getSelectedItem());
760      }
761
762      if (incrementalBackup.isSelected())
763      {
764        args.add("--incremental");
765        if(incrementalParent.isSelected())
766        {
767          if (isLocal())
768          {
769            BackupDescriptor backup = getSelectedBackup();
770            args.add("--incrementalBaseID");
771            args.add(backup.getID());
772          }
773          else
774          {
775            args.add("--incrementalBaseID");
776            args.add(parentBackupID.getText());
777          }
778        }
779      }
780
781
782      if (compressData.isSelected())
783      {
784        args.add("--compress");
785      }
786
787      if (encryptData.isSelected())
788      {
789        args.add("--encrypt");
790      }
791
792      if (generateMessageDigest.isSelected())
793      {
794        args.add("--hash");
795        if (signMessageDigest.isSelected())
796        {
797          args.add("--signHash");
798        }
799      }
800
801      args.addAll(getConnectionCommandLineArguments());
802
803      args.addAll(getScheduleArgs(getSchedule()));
804
805      if (isServerRunning())
806      {
807        args.addAll(getConfigCommandLineArguments());
808      }
809
810      args.add(getNoPropertiesFileArgument());
811
812      return args;
813    }
814
815    @Override
816    protected String getCommandLinePath()
817    {
818      return getCommandLinePath("backup");
819    }
820  }
821}