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 legal-notices/CDDLv1_0.txt
010 * or http://forgerock.org/license/CDDLv1.0.html.
011 * See the License for the specific language governing permissions
012 * and limitations under the License.
013 *
014 * When distributing Covered Code, include this CDDL HEADER in each
015 * file and include the License file at legal-notices/CDDLv1_0.txt.
016 * If applicable, add the following below this CDDL HEADER, with the
017 * fields enclosed by brackets "[]" replaced with your own identifying
018 * information:
019 *      Portions Copyright [yyyy] [name of copyright owner]
020 *
021 * CDDL HEADER END
022 *
023 *
024 *      Copyright 2008-2009 Sun Microsystems, Inc.
025 *      Portions Copyright 2012-2015 ForgeRock AS
026 */
027package org.opends.guitools.controlpanel.task;
028
029import static org.opends.messages.AdminToolMessages.*;
030
031import java.util.ArrayList;
032import java.util.Collection;
033import java.util.HashSet;
034import java.util.List;
035import java.util.Set;
036import java.util.SortedSet;
037import java.util.TreeSet;
038
039import javax.swing.SwingUtilities;
040
041import org.forgerock.i18n.LocalizableMessage;
042import org.opends.guitools.controlpanel.datamodel.AbstractIndexDescriptor;
043import org.opends.guitools.controlpanel.datamodel.BackendDescriptor;
044import org.opends.guitools.controlpanel.datamodel.ControlPanelInfo;
045import org.opends.guitools.controlpanel.datamodel.IndexDescriptor;
046import org.opends.guitools.controlpanel.datamodel.VLVIndexDescriptor;
047import org.opends.guitools.controlpanel.ui.ProgressDialog;
048import org.opends.guitools.controlpanel.util.Utilities;
049import org.opends.server.backends.pluggable.SuffixContainer;
050import org.opends.server.tools.RebuildIndex;
051
052/**
053 * The class that is used when a set of indexes must be rebuilt.
054 */
055public class RebuildIndexTask extends IndexTask
056{
057  private SortedSet<AbstractIndexDescriptor> indexes = new TreeSet<>();
058
059  /**
060   * The indexes that must not be specified in the command-line.
061   */
062  public static final String[] INDEXES_NOT_TO_SPECIFY = { SuffixContainer.ID2CHILDREN_INDEX_NAME,
063    SuffixContainer.ID2SUBTREE_INDEX_NAME, SuffixContainer.ID2CHILDREN_COUNT_NAME };
064
065  /**
066   * Constructor of the task.
067   *
068   * @param info
069   *          the control panel information.
070   * @param dlg
071   *          the progress dialog where the task progress will be displayed.
072   * @param baseDNs
073   *          the baseDNs corresponding to the indexes.
074   * @param indexes
075   *          the indexes.
076   */
077  public RebuildIndexTask(ControlPanelInfo info, ProgressDialog dlg, Collection<String> baseDNs,
078      SortedSet<AbstractIndexDescriptor> indexes)
079  {
080    super(info, dlg, baseDNs);
081    this.indexes.addAll(indexes);
082  }
083
084  @Override
085  public Type getType()
086  {
087    return Type.REBUILD_INDEXES;
088  }
089
090  @Override
091  public LocalizableMessage getTaskDescription()
092  {
093    if (baseDNs.size() == 1)
094    {
095      return INFO_CTRL_PANEL_REBUILD_INDEX_TASK_DESCRIPTION.get(baseDNs.iterator().next());
096    }
097    else
098    {
099      // Assume is in a backend
100      return INFO_CTRL_PANEL_REBUILD_INDEX_TASK_DESCRIPTION.get(backendSet.iterator().next());
101    }
102  }
103
104  @Override
105  public boolean canLaunch(Task taskToBeLaunched, Collection<LocalizableMessage> incompatibilityReasons)
106  {
107    boolean canLaunch = true;
108    if (state == State.RUNNING && runningOnSameServer(taskToBeLaunched))
109    {
110      // All the operations are incompatible if they apply to this backend.
111      Set<String> backends = new TreeSet<>(taskToBeLaunched.getBackends());
112      backends.retainAll(getBackends());
113      if (!backends.isEmpty())
114      {
115        incompatibilityReasons.add(getIncompatibilityMessage(this, taskToBeLaunched));
116        canLaunch = false;
117      }
118    }
119    return canLaunch;
120  }
121
122  @Override
123  public void runTask()
124  {
125    state = State.RUNNING;
126    lastException = null;
127    try
128    {
129      boolean isLocal = getInfo().getServerDescriptor().isLocal();
130
131      for (final String baseDN : baseDNs)
132      {
133        List<String> arguments = getCommandLineArguments(baseDN);
134        String[] args = arguments.toArray(new String[arguments.size()]);
135
136        final List<String> displayArgs = getObfuscatedCommandLineArguments(getCommandLineArguments(baseDN));
137        displayArgs.removeAll(getConfigCommandLineArguments());
138
139        SwingUtilities.invokeLater(new Runnable()
140        {
141          @Override
142          public void run()
143          {
144            printEquivalentCommandLine(getCommandLinePath("rebuild-index"), displayArgs,
145                INFO_CTRL_PANEL_EQUIVALENT_CMD_TO_REBUILD_INDEX.get(baseDN));
146          }
147        });
148
149        if (isLocal && !isServerRunning())
150        {
151          returnCode = executeCommandLine(getCommandLinePath("rebuild-index"), args);
152        }
153        else
154        {
155          returnCode = RebuildIndex.mainRebuildIndex(args, false, outPrintStream, errorPrintStream);
156        }
157
158        if (returnCode != 0)
159        {
160          break;
161        }
162      }
163
164      if (returnCode != 0)
165      {
166        state = State.FINISHED_WITH_ERROR;
167      }
168      else
169      {
170        for (AbstractIndexDescriptor index : indexes)
171        {
172          getInfo().unregisterModifiedIndex(index);
173        }
174
175        state = State.FINISHED_SUCCESSFULLY;
176      }
177    }
178    catch (Throwable t)
179    {
180      lastException = t;
181      state = State.FINISHED_WITH_ERROR;
182    }
183  }
184
185  @Override
186  protected List<String> getCommandLineArguments()
187  {
188    return new ArrayList<>();
189  }
190
191  /**
192   * Returns the command line arguments required to rebuild the indexes in the
193   * specified base DN.
194   *
195   * @param baseDN
196   *          the base DN.
197   * @return the command line arguments required to rebuild the indexes in the
198   *         specified base DN.
199   */
200  protected List<String> getCommandLineArguments(String baseDN)
201  {
202    List<String> args = new ArrayList<>();
203
204    args.add("--baseDN");
205    args.add(baseDN);
206
207    if (rebuildAll())
208    {
209      args.add("--rebuildAll");
210    }
211    else
212    {
213      for (AbstractIndexDescriptor index : indexes)
214      {
215        args.add("--index");
216        if (index instanceof VLVIndexDescriptor)
217        {
218          args.add(Utilities.getVLVNameInCommandLine((VLVIndexDescriptor) index));
219        }
220        else
221        {
222          args.add(index.getName());
223        }
224      }
225    }
226
227    boolean isLocal = getInfo().getServerDescriptor().isLocal();
228    if (isLocal && isServerRunning())
229    {
230      args.addAll(getConnectionCommandLineArguments());
231      args.addAll(getConfigCommandLineArguments());
232    }
233
234    return args;
235  }
236
237  @Override
238  protected String getCommandLinePath()
239  {
240    return null;
241  }
242
243  private boolean rebuildAll()
244  {
245    Set<BackendDescriptor> backends = new HashSet<>();
246    for (AbstractIndexDescriptor index : indexes)
247    {
248      backends.add(index.getBackend());
249    }
250    for (BackendDescriptor backend : backends)
251    {
252      Set<AbstractIndexDescriptor> allIndexes = new HashSet<>();
253      allIndexes.addAll(backend.getIndexes());
254      allIndexes.addAll(backend.getVLVIndexes());
255      for (AbstractIndexDescriptor index : allIndexes)
256      {
257        if (!ignoreIndex(index) && !indexes.contains(index))
258        {
259          return false;
260        }
261      }
262    }
263    return true;
264  }
265
266  private boolean ignoreIndex(AbstractIndexDescriptor index)
267  {
268    if (index instanceof IndexDescriptor)
269    {
270      for (String name : INDEXES_NOT_TO_SPECIFY)
271      {
272        if (name.equalsIgnoreCase(index.getName()))
273        {
274          return true;
275        }
276      }
277    }
278    return false;
279  }
280}