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