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 2011-2016 ForgeRock AS.
016 */
017package org.opends.guitools.controlpanel.ui;
018
019import static org.opends.guitools.controlpanel.util.Utilities.*;
020import static org.opends.messages.AdminToolMessages.*;
021
022import java.awt.Component;
023import java.awt.GridBagConstraints;
024import java.awt.GridBagLayout;
025import java.awt.Insets;
026import java.awt.event.ActionEvent;
027import java.awt.event.ActionListener;
028import java.util.ArrayList;
029import java.util.Collection;
030import java.util.HashSet;
031import java.util.List;
032import java.util.Set;
033import java.util.TreeSet;
034
035import javax.swing.Box;
036import javax.swing.DefaultComboBoxModel;
037import javax.swing.JButton;
038import javax.swing.JLabel;
039import javax.swing.JPanel;
040import javax.swing.JScrollPane;
041import javax.swing.SwingConstants;
042import javax.swing.SwingUtilities;
043import javax.swing.border.EmptyBorder;
044import javax.swing.event.DocumentEvent;
045import javax.swing.event.DocumentListener;
046import javax.swing.event.ListDataEvent;
047import javax.swing.event.ListDataListener;
048
049import org.forgerock.i18n.LocalizableMessage;
050import org.forgerock.i18n.LocalizedIllegalArgumentException;
051import org.forgerock.opendj.ldap.DN;
052import org.forgerock.opendj.ldap.SearchScope;
053import org.forgerock.opendj.server.config.client.BackendVLVIndexCfgClient;
054import org.forgerock.opendj.server.config.client.PluggableBackendCfgClient;
055import org.forgerock.opendj.server.config.client.RootCfgClient;
056import org.opends.admin.ads.util.ConnectionWrapper;
057import org.opends.guitools.controlpanel.datamodel.AbstractIndexDescriptor;
058import org.opends.guitools.controlpanel.datamodel.CategorizedComboBoxElement;
059import org.opends.guitools.controlpanel.datamodel.ControlPanelInfo;
060import org.opends.guitools.controlpanel.datamodel.ServerDescriptor;
061import org.opends.guitools.controlpanel.datamodel.VLVIndexDescriptor;
062import org.opends.guitools.controlpanel.datamodel.VLVSortOrder;
063import org.opends.guitools.controlpanel.event.ConfigurationChangeEvent;
064import org.opends.guitools.controlpanel.event.ScrollPaneBorderListener;
065import org.opends.guitools.controlpanel.task.DeleteIndexTask;
066import org.opends.guitools.controlpanel.task.Task;
067import org.opends.guitools.controlpanel.util.Utilities;
068
069/**
070 * The panel that displays an existing VLV index (it appears on the right of the
071 * 'Manage Indexes' dialog).
072 */
073public class VLVIndexPanel extends AbstractVLVIndexPanel
074{
075  private static final long serialVersionUID = 6333337497315464283L;
076  private static final LocalizableMessage INDEX_MODIFIED = INFO_CTRL_PANEL_INDEX_MODIFIED_MESSAGE.get();
077
078  private final JButton deleteIndex = Utilities.createButton(INFO_CTRL_PANEL_DELETE_INDEX_LABEL.get());
079  private final JButton saveChanges = Utilities.createButton(INFO_CTRL_PANEL_SAVE_CHANGES_LABEL.get());
080  private final JLabel warning = Utilities.createDefaultLabel();
081
082  private ScrollPaneBorderListener scrollListener;
083
084  private ModifyVLVIndexTask newModifyTask;
085
086  private boolean ignoreCheckSave;
087
088  private VLVIndexDescriptor index;
089
090  /** Default constructor. */
091  public VLVIndexPanel()
092  {
093    super(null, null);
094    createLayout();
095  }
096
097  @Override
098  public LocalizableMessage getTitle()
099  {
100    return INFO_CTRL_PANEL_VLV_INDEX_PANEL_TITLE.get();
101  }
102
103  @Override
104  public Component getPreferredFocusComponent()
105  {
106    return baseDN;
107  }
108
109  @Override
110  public void configurationChanged(ConfigurationChangeEvent ev)
111  {
112    final ServerDescriptor desc = ev.getNewDescriptor();
113    if (updateLayout(desc))
114    {
115      LocalizableMessage msg = isLocal() ? INFO_CTRL_PANEL_AUTHENTICATION_REQUIRED_FOR_VLV_INDEX_EDITING.get()
116                                         : INFO_CTRL_PANEL_CANNOT_CONNECT_TO_REMOTE_DETAILS.get(desc.getHostname());
117      updateErrorPaneIfAuthRequired(desc, msg);
118      SwingUtilities.invokeLater(new Runnable()
119      {
120        @Override
121        public void run()
122        {
123          checkSaveButton();
124          deleteIndex.setEnabled(!authenticationRequired(desc));
125        }
126      });
127    }
128  }
129
130  @Override
131  public void okClicked()
132  {
133    // no-op
134  }
135
136  /**
137   * Method used to know if there are unsaved changes or not. It is used by the
138   * index selection listener when the user changes the selection.
139   *
140   * @return <CODE>true</CODE> if there are unsaved changes (and so the
141   *         selection of the index should be canceled) and <CODE>false</CODE>
142   *         otherwise.
143   */
144  public boolean mustCheckUnsavedChanges()
145  {
146    return index != null && saveChanges.isVisible() && saveChanges.isEnabled();
147  }
148
149  /**
150   * Tells whether the user chose to save the changes in the panel, to not save
151   * them or simply cancelled the selection in the tree.
152   *
153   * @return the value telling whether the user chose to save the changes in the
154   *         panel, to not save them or simply cancelled the selection change in
155   *         the tree.
156   */
157  public UnsavedChangesDialog.Result checkUnsavedChanges()
158  {
159    UnsavedChangesDialog.Result result;
160    final UnsavedChangesDialog unsavedChangesDlg = new UnsavedChangesDialog(getParentDialog(this), getInfo());
161    unsavedChangesDlg.setMessage(INFO_CTRL_PANEL_UNSAVED_CHANGES_SUMMARY.get(),
162                                 INFO_CTRL_PANEL_UNSAVED_INDEX_CHANGES_DETAILS.get(index.getName()));
163    centerGoldenMean(unsavedChangesDlg, getParentDialog(this));
164    unsavedChangesDlg.setVisible(true);
165    result = unsavedChangesDlg.getResult();
166    if (result == UnsavedChangesDialog.Result.SAVE)
167    {
168      saveIndex(false);
169      if (newModifyTask == null
170       || newModifyTask.getState() != Task.State.FINISHED_SUCCESSFULLY) // The user data is not valid
171      {
172        result = UnsavedChangesDialog.Result.CANCEL;
173      }
174    }
175
176    return result;
177  }
178
179  private void checkSaveButton()
180  {
181    if (!ignoreCheckSave && index != null)
182    {
183      saveChanges.setEnabled(!authenticationRequired(getInfo().getServerDescriptor()) && isModified());
184    }
185  }
186
187  @Override
188  public GenericDialog.ButtonType getButtonType()
189  {
190    return GenericDialog.ButtonType.NO_BUTTON;
191  }
192
193  /** Creates the layout of the panel (but the contents are not populated here). */
194  private void createLayout()
195  {
196    GridBagConstraints gbc = new GridBagConstraints();
197    final JPanel p = new JPanel(new GridBagLayout());
198    p.setOpaque(false);
199    super.createBasicLayout(p, gbc, true);
200    p.setBorder(new EmptyBorder(10, 10, 10, 10));
201    gbc = new GridBagConstraints();
202    gbc.weightx = 1.0;
203    gbc.weighty = 1.0;
204    gbc.fill = GridBagConstraints.BOTH;
205    gbc.gridx = 0;
206    gbc.gridy = 0;
207    final JScrollPane scroll = Utilities.createBorderLessScrollBar(p);
208    scrollListener = ScrollPaneBorderListener.createBottomBorderListener(scroll);
209    add(scroll, gbc);
210
211    gbc.gridy++;
212    gbc.gridx = 0;
213    gbc.weightx = 1.0;
214    gbc.weighty = 0.0;
215    gbc.insets.left = 0;
216    gbc.gridwidth = 2;
217    gbc.weighty = 0.0;
218    gbc.fill = GridBagConstraints.HORIZONTAL;
219    gbc.insets.top = 10;
220
221    gbc.gridwidth = 3;
222    gbc.insets = new Insets(10, 10, 0, 10);
223    add(warning, gbc);
224    Utilities.setWarningLabel(warning, INDEX_MODIFIED);
225
226    gbc.gridy++;
227    final JPanel buttonPanel = new JPanel(new GridBagLayout());
228    buttonPanel.setOpaque(false);
229    gbc.insets = new Insets(10, 10, 10, 10);
230    add(buttonPanel, gbc);
231
232    gbc.insets = new Insets(0, 0, 0, 0);
233    gbc.gridy = 0;
234    gbc.gridx = 0;
235    gbc.weightx = 0.0;
236    gbc.gridwidth = 1;
237    deleteIndex.setOpaque(false);
238    gbc.insets.left = 0;
239    buttonPanel.add(deleteIndex, gbc);
240    deleteIndex.addActionListener(new ActionListener()
241    {
242      @Override
243      public void actionPerformed(ActionEvent ev)
244      {
245        deleteIndex();
246      }
247    });
248    gbc.gridx = 2;
249    gbc.weightx = 1.0;
250    buttonPanel.add(Box.createHorizontalGlue(), gbc);
251    gbc.weightx = 0.0;
252    gbc.insets.left = 10;
253    saveChanges.setOpaque(false);
254    gbc.gridx = 3;
255    buttonPanel.add(saveChanges, gbc);
256    saveChanges.addActionListener(new ActionListener()
257    {
258      @Override
259      public void actionPerformed(ActionEvent ev)
260      {
261        saveIndex(false);
262      }
263    });
264
265    final DocumentListener documentListener = new DocumentListener()
266    {
267      @Override
268      public void insertUpdate(DocumentEvent ev)
269      {
270        checkSaveButton();
271      }
272
273      @Override
274      public void changedUpdate(DocumentEvent ev)
275      {
276        checkSaveButton();
277      }
278
279      @Override
280      public void removeUpdate(DocumentEvent ev)
281      {
282        checkSaveButton();
283      }
284    };
285
286    final ActionListener actionListener = new ActionListener()
287    {
288      @Override
289      public void actionPerformed(ActionEvent ev)
290      {
291        checkSaveButton();
292      }
293    };
294
295    baseDNs.addActionListener(actionListener);
296    baseObject.addActionListener(actionListener);
297    singleLevel.addActionListener(actionListener);
298    subordinateSubtree.addActionListener(actionListener);
299    wholeSubtree.addActionListener(actionListener);
300    attributes.addActionListener(actionListener);
301    sortOrder.getModel().addListDataListener(new ListDataListener()
302    {
303      @Override
304      public void contentsChanged(ListDataEvent e)
305      {
306        checkSaveButton();
307      }
308
309      @Override
310      public void intervalAdded(ListDataEvent e)
311      {
312        checkSaveButton();
313      }
314
315      @Override
316      public void intervalRemoved(ListDataEvent e)
317      {
318        checkSaveButton();
319      }
320    });
321
322    baseDN.getDocument().addDocumentListener(documentListener);
323    filter.getDocument().addDocumentListener(documentListener);
324    baseDN.getDocument().addDocumentListener(documentListener);
325  }
326
327  private void deleteIndex()
328  {
329    final List<LocalizableMessage> errors = new ArrayList<>();
330    final ProgressDialog dlg = new ProgressDialog(
331        createFrame(), getParentDialog(this), INFO_CTRL_PANEL_DELETE_VLV_INDEX_TITLE.get(), getInfo());
332    final List<AbstractIndexDescriptor> indexesToDelete = new ArrayList<>();
333    indexesToDelete.add(index);
334    final DeleteIndexTask newTask = new DeleteIndexTask(getInfo(), dlg, indexesToDelete);
335    for (final Task task : getInfo().getTasks())
336    {
337      task.canLaunch(newTask, errors);
338    }
339
340    if (errors.isEmpty())
341    {
342      final String indexName = index.getName();
343      final String backendName = index.getBackend().getBackendID();
344      if (displayConfirmationDialog(INFO_CTRL_PANEL_CONFIRMATION_REQUIRED_SUMMARY.get(),
345                                    INFO_CTRL_PANEL_CONFIRMATION_VLV_INDEX_DELETE_DETAILS.get(indexName, backendName)))
346      {
347        launchOperation(newTask,
348                        INFO_CTRL_PANEL_DELETING_VLV_INDEX_SUMMARY.get(),
349                        INFO_CTRL_PANEL_DELETING_VLV_INDEX_COMPLETE.get(),
350                        INFO_CTRL_PANEL_DELETING_VLV_INDEX_SUCCESSFUL.get(indexName, backendName),
351                        ERR_CTRL_PANEL_DELETING_VLV_INDEX_ERROR_SUMMARY.get(),
352                        ERR_CTRL_PANEL_DELETING_VLV_INDEX_ERROR_DETAILS.get(indexName),
353                        null, dlg);
354        dlg.setVisible(true);
355      }
356    }
357    else
358    {
359      displayErrorDialog(errors);
360    }
361  }
362
363  private void saveIndex(boolean modal)
364  {
365    newModifyTask = null;
366    if (!isModified())
367    {
368      return;
369    }
370    final List<LocalizableMessage> errors = checkErrors(false);
371
372    if (errors.isEmpty())
373    {
374      final ProgressDialog dlg =
375          new ProgressDialog(getFrame(this), getFrame(this), INFO_CTRL_PANEL_MODIFYING_INDEX_TITLE.get(), getInfo());
376      dlg.setModal(modal);
377      newModifyTask = new ModifyVLVIndexTask(getInfo(), dlg);
378      for (final Task task : getInfo().getTasks())
379      {
380        task.canLaunch(newModifyTask, errors);
381      }
382      if (errors.isEmpty() && checkIndexRequired())
383      {
384        final String indexName = index.getName();
385        final String backendName = index.getBackend().getBackendID();
386        launchOperation(newModifyTask,
387                        INFO_CTRL_PANEL_MODIFYING_VLV_INDEX_SUMMARY.get(indexName),
388                        INFO_CTRL_PANEL_MODIFYING_VLV_INDEX_COMPLETE.get(),
389                        INFO_CTRL_PANEL_MODIFYING_VLV_INDEX_SUCCESSFUL.get(indexName, backendName),
390                        ERR_CTRL_PANEL_MODIFYING_VLV_INDEX_ERROR_SUMMARY.get(),
391                        ERR_CTRL_PANEL_MODIFYING_VLV_INDEX_ERROR_DETAILS.get(indexName),
392                        null, dlg);
393        saveChanges.setEnabled(false);
394        dlg.setVisible(true);
395      }
396    }
397
398    if (!errors.isEmpty())
399    {
400      displayErrorDialog(errors);
401    }
402  }
403
404  /**
405   * Updates the contents of the panel with the provided VLV index.
406   *
407   * @param index
408   *          the VLV index descriptor to be used to update the panel.
409   */
410  public void update(VLVIndexDescriptor index)
411  {
412    ignoreCheckSave = true;
413    readOnlyName.setText(index.getName());
414    titlePanel.setDetails(LocalizableMessage.raw(index.getName()));
415    if (index.getBackend() != null)
416    {
417      updateBaseDNCombo(index.getBackend());
418      backendName.setText(index.getBackend().getBackendID());
419    }
420    final String dn = Utilities.unescapeUtf8(index.getBaseDN().toString());
421    if (((DefaultComboBoxModel) baseDNs.getModel()).getIndexOf(dn) != -1)
422    {
423      baseDN.setText("");
424      baseDNs.setSelectedItem(dn);
425    }
426    else
427    {
428      baseDN.setText(dn);
429      baseDNs.setSelectedItem(OTHER_BASE_DN);
430    }
431
432    selectScopeRadioButton(index.getScope());
433    filter.setText(index.getFilter());
434
435    // Simulate a remove to update the attribute combo box and add them again.
436    final int indexes[] = new int[sortOrderModel.getSize()];
437    for (int i = 0; i < indexes.length; i++)
438    {
439      indexes[i] = i;
440    }
441    sortOrder.setSelectedIndices(indexes);
442    remove.doClick();
443
444    // The list is now empty and the attribute combo properly updated.
445    final DefaultComboBoxModel model = (DefaultComboBoxModel) attributes.getModel();
446    for (final VLVSortOrder s : index.getSortOrder())
447    {
448      sortOrderModel.addElement(s);
449      for (int i = 0; i < model.getSize(); i++)
450      {
451        final CategorizedComboBoxElement o = (CategorizedComboBoxElement) model.getElementAt(i);
452        if (o.getType() == CategorizedComboBoxElement.Type.REGULAR && o.getValue().equals(s.getAttributeName()))
453        {
454          model.removeElementAt(i);
455          break;
456        }
457      }
458    }
459    if (model.getSize() > 1)
460    {
461      attributes.setSelectedIndex(1);
462    }
463
464    if (getInfo() != null)
465    {
466      if (getInfo().mustReindex(index))
467      {
468        setWarningLabel(warning, INDEX_MODIFIED);
469        warning.setVisible(true);
470        warning.setVerticalTextPosition(SwingConstants.TOP);
471      }
472      else
473      {
474        warning.setVisible(false);
475      }
476    }
477    this.index = index;
478
479    ignoreCheckSave = false;
480    checkSaveButton();
481
482    scrollListener.updateBorder();
483  }
484
485  private void selectScopeRadioButton(final SearchScope indexScope)
486  {
487    switch (indexScope.asEnum())
488    {
489    case BASE_OBJECT:
490      baseObject.setSelected(true);
491      break;
492    case SINGLE_LEVEL:
493      singleLevel.setSelected(true);
494      break;
495    case SUBORDINATES:
496      subordinateSubtree.setSelected(true);
497      break;
498    case WHOLE_SUBTREE:
499      wholeSubtree.setSelected(true);
500      break;
501    default:
502      break;
503    }
504  }
505
506  private boolean isModified()
507  {
508    try
509    {
510      return !index.getBaseDN().equals(DN.valueOf(getBaseDN())) || !index.getScope().equals(getScope())
511          || !index.getFilter().equals(filter.getText().trim()) || !index.getSortOrder().equals(getSortOrder());
512    }
513    catch (final LocalizedIllegalArgumentException unused)
514    {
515      // The base DN is not valid.  This means that the index has been modified.
516      return true;
517    }
518  }
519
520  /** The task in charge of modifying the VLV index. */
521  private class ModifyVLVIndexTask extends Task
522  {
523    private final Set<String> backendSet;
524    private final String indexName;
525    private final String baseDN;
526    private final String filterValue;
527    private final SearchScope searchScope;
528    private final List<VLVSortOrder> sortOrder;
529    private final String backendID;
530    private final String sortOrderStringValue;
531    private final VLVIndexDescriptor indexToModify;
532    private VLVIndexDescriptor modifiedIndex;
533
534    /**
535     * The constructor of the task.
536     *
537     * @param info
538     *          the control panel info.
539     * @param dlg
540     *          the progress dialog that shows the progress of the task.
541     */
542    private ModifyVLVIndexTask(ControlPanelInfo info, ProgressDialog dlg)
543    {
544      super(info, dlg);
545      backendID = index.getBackend().getBackendID();
546      backendSet = new HashSet<>();
547      backendSet.add(backendID);
548      indexName = index.getName();
549      sortOrder = getSortOrder();
550      baseDN = getBaseDN();
551      filterValue = filter.getText().trim();
552      searchScope = getScope();
553      sortOrderStringValue = getSortOrderStringValue(sortOrder);
554      indexToModify = index;
555    }
556
557    @Override
558    public Type getType()
559    {
560      return Type.MODIFY_INDEX;
561    }
562
563    @Override
564    public Set<String> getBackends()
565    {
566      return backendSet;
567    }
568
569    @Override
570    public LocalizableMessage getTaskDescription()
571    {
572      return INFO_CTRL_PANEL_MODIFY_VLV_INDEX_TASK_DESCRIPTION.get(indexName, backendID);
573    }
574
575    @Override
576    public boolean canLaunch(Task taskToBeLaunched, Collection<LocalizableMessage> incompatibilityReasons)
577    {
578      boolean canLaunch = true;
579      if (state == State.RUNNING && runningOnSameServer(taskToBeLaunched))
580      {
581        // All the operations are incompatible if they apply to this
582        // backend for safety.  This is a short operation so the limitation
583        // has not a lot of impact.
584        final Set<String> backends = new TreeSet<>(taskToBeLaunched.getBackends());
585        backends.retainAll(getBackends());
586        if (!backends.isEmpty())
587        {
588          incompatibilityReasons.add(getIncompatibilityMessage(this, taskToBeLaunched));
589          canLaunch = false;
590        }
591      }
592      return canLaunch;
593    }
594
595    private void updateConfiguration() throws Exception
596    {
597      boolean configHandlerUpdated = false;
598      try
599      {
600        if (!isServerRunning())
601        {
602          configHandlerUpdated = true;
603          stopPoolingAndInitializeConfiguration();
604        }
605        else
606        {
607          SwingUtilities.invokeLater(new Runnable()
608          {
609            @Override
610            public void run()
611            {
612              final List<String> args = getObfuscatedCommandLineArguments(getDSConfigCommandLineArguments());
613              args.removeAll(getConfigCommandLineArguments());
614              printEquivalentCommandLine(getConfigCommandLineName(), args,
615                  INFO_CTRL_PANEL_EQUIVALENT_CMD_TO_MODIFY_VLV_INDEX.get());
616            }
617          });
618        }
619        SwingUtilities.invokeLater(new Runnable()
620        {
621          @Override
622          public void run()
623          {
624            getProgressDialog().appendProgressHtml(
625                Utilities.getProgressWithPoints(INFO_CTRL_PANEL_MODIFYING_VLV_INDEX_PROGRESS.get(indexName),
626                    ColorAndFontConstants.progressFont));
627          }
628        });
629
630        if (isServerRunning())
631        {
632          modifyVLVIndexOnline(getInfo().getConnection());
633        }
634        else
635        {
636          modifyVLVIndexOffline(backendID, indexName, indexToModify, DN.valueOf(baseDN), filterValue,
637              searchScope, sortOrder);
638        }
639        SwingUtilities.invokeLater(new Runnable()
640        {
641          @Override
642          public void run()
643          {
644            getProgressDialog().appendProgressHtml(Utilities.getProgressDone(ColorAndFontConstants.progressFont));
645          }
646        });
647      }
648      finally
649      {
650        if (configHandlerUpdated)
651        {
652          startPoolingAndInitializeConfiguration();
653        }
654      }
655    }
656
657    /**
658     * Modifies index using the provided connection.
659     *
660     * @param ctx
661     *          the connection to be used to update the index configuration.
662     * @throws Exception
663     *           if there is an error updating the server.
664     */
665    private void modifyVLVIndexOnline(ConnectionWrapper connWrapper) throws Exception
666    {
667      final RootCfgClient root = connWrapper.getRootConfiguration();
668      modifyBackendVLVIndexOnline((PluggableBackendCfgClient) root.getBackend(backendID));
669    }
670
671    private void modifyBackendVLVIndexOnline(final PluggableBackendCfgClient backend) throws Exception
672    {
673      final BackendVLVIndexCfgClient index = backend.getBackendVLVIndex(indexName);
674      final DN b = DN.valueOf(baseDN);
675      if (!indexToModify.getBaseDN().equals(b))
676      {
677        index.setBaseDN(b);
678      }
679
680      if (!indexToModify.getFilter().equals(filterValue))
681      {
682        index.setFilter(filterValue);
683      }
684
685      if (indexToModify.getScope() != searchScope)
686      {
687        index.setScope(VLVIndexDescriptor.getBackendVLVIndexScope(searchScope));
688      }
689
690      if (!indexToModify.getSortOrder().equals(sortOrder))
691      {
692        index.setSortOrder(sortOrderStringValue);
693      }
694      index.commit();
695    }
696
697    @Override
698    protected String getCommandLinePath()
699    {
700      return null;
701    }
702
703    @Override
704    protected ArrayList<String> getCommandLineArguments()
705    {
706      return new ArrayList<>();
707    }
708
709    private String getConfigCommandLineName()
710    {
711      if (isServerRunning() && isModified())
712      {
713        return getCommandLinePath("dsconfig");
714      }
715      return null;
716    }
717
718    @Override
719    public void runTask()
720    {
721      state = State.RUNNING;
722      lastException = null;
723
724      try
725      {
726        updateConfiguration();
727        modifiedIndex = new VLVIndexDescriptor(
728            indexName, indexToModify.getBackend(), DN.valueOf(baseDN), searchScope, filterValue, sortOrder);
729        getInfo().registerModifiedIndex(modifiedIndex);
730        state = State.FINISHED_SUCCESSFULLY;
731      }
732      catch (final Throwable t)
733      {
734        lastException = t;
735        state = State.FINISHED_WITH_ERROR;
736      }
737    }
738
739    @Override
740    public void postOperation()
741    {
742      if (lastException == null && state == State.FINISHED_SUCCESSFULLY)
743      {
744        rebuildIndexIfNecessary(modifiedIndex, getProgressDialog());
745      }
746    }
747
748    private List<String> getDSConfigCommandLineArguments()
749    {
750      final List<String> args = new ArrayList<>();
751      args.add("set-backend-vlv-index-prop");
752      args.add("--backend-name");
753      args.add(backendID);
754
755      args.add("--index-name");
756      args.add(indexName);
757
758      if (!indexToModify.getBaseDN().equals(DN.valueOf(baseDN)))
759      {
760        args.add("--set");
761        args.add("base-dn:" + baseDN);
762      }
763
764      if (indexToModify.getScope() != searchScope)
765      {
766        args.add("--set");
767        args.add("scope:" + VLVIndexDescriptor.getBackendVLVIndexScope(searchScope));
768      }
769      if (!indexToModify.getFilter().equals(filterValue))
770      {
771        args.add("--set");
772        args.add("filter:" + filterValue);
773      }
774
775      if (!indexToModify.getSortOrder().equals(sortOrder))
776      {
777        args.add("--set");
778        args.add("sort-order:" + sortOrderStringValue);
779      }
780
781      args.addAll(getConnectionCommandLineArguments());
782      args.add(getNoPropertiesFileArgument());
783      args.add("--no-prompt");
784
785      return args;
786    }
787  }
788}