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 2014-2015 ForgeRock AS
026 */
027package org.opends.guitools.controlpanel.ui;
028
029import static org.opends.messages.AdminToolMessages.*;
030
031import java.awt.Component;
032import java.awt.GridBagConstraints;
033import java.awt.event.ItemEvent;
034import java.awt.event.ItemListener;
035import java.util.HashMap;
036import java.util.HashSet;
037import java.util.Iterator;
038import java.util.LinkedHashSet;
039import java.util.Map;
040import java.util.Set;
041import java.util.SortedSet;
042
043import javax.swing.DefaultComboBoxModel;
044import javax.swing.JComboBox;
045import javax.swing.JLabel;
046import javax.swing.JScrollPane;
047import javax.swing.ListCellRenderer;
048import javax.swing.SwingUtilities;
049
050import org.forgerock.i18n.LocalizableMessage;
051import org.opends.guitools.controlpanel.datamodel.AbstractIndexDescriptor;
052import org.opends.guitools.controlpanel.datamodel.BackendDescriptor;
053import org.opends.guitools.controlpanel.datamodel.CategorizedComboBoxElement;
054import org.opends.guitools.controlpanel.datamodel.ControlPanelInfo;
055import org.opends.guitools.controlpanel.datamodel.IndexDescriptor;
056import org.opends.guitools.controlpanel.datamodel.ServerDescriptor;
057import org.opends.guitools.controlpanel.datamodel.SortableListModel;
058import org.opends.guitools.controlpanel.event.ConfigurationChangeEvent;
059import org.opends.guitools.controlpanel.event.IndexModifiedEvent;
060import org.opends.guitools.controlpanel.event.IndexModifiedListener;
061import org.opends.guitools.controlpanel.task.RebuildIndexTask;
062import org.opends.guitools.controlpanel.task.Task;
063import org.opends.guitools.controlpanel.ui.components.AddRemovePanel;
064import org.opends.guitools.controlpanel.ui.renderer.CustomListCellRenderer;
065import org.opends.guitools.controlpanel.ui.renderer.IndexCellRenderer;
066import org.opends.guitools.controlpanel.util.Utilities;
067import org.opends.guitools.controlpanel.util.ViewPositions;
068
069/**
070 * The panel that appears when the user wants to rebuild indexes.
071 */
072public class RebuildIndexPanel extends StatusGenericPanel implements IndexModifiedListener
073{
074  private static final long serialVersionUID = -4805445967165643375L;
075  private JComboBox baseDNs;
076  private AddRemovePanel<AbstractIndexDescriptor> addRemove;
077
078  private JLabel lBaseDN;
079  private JLabel lIndexes;
080  private JLabel lNoBaseDNsFound;
081
082  private final Map<String, SortedSet<AbstractIndexDescriptor>> hmIndexes = new HashMap<>();
083
084  /** Constructor of the panel. */
085  public RebuildIndexPanel()
086  {
087    createLayout();
088  }
089
090  @Override
091  public void indexModified(final IndexModifiedEvent ev)
092  {
093    refreshContents(getInfo().getServerDescriptor());
094  }
095
096  @Override
097  public void backendIndexesModified(final IndexModifiedEvent ev)
098  {
099    refreshContents(getInfo().getServerDescriptor());
100  }
101
102  /** Creates the layout of the panel (but the contents are not populated here). */
103  private void createLayout()
104  {
105    GridBagConstraints gbc = new GridBagConstraints();
106    gbc.anchor = GridBagConstraints.WEST;
107    gbc.weightx = 0.0;
108    gbc.gridx = 0;
109    gbc.gridy = 0;
110    gbc.gridwidth = 3;
111    addErrorPane(gbc);
112    gbc.gridwidth = 1;
113    gbc.fill = GridBagConstraints.NONE;
114    lBaseDN = Utilities.createPrimaryLabel(INFO_CTRL_PANEL_BASE_DN_LABEL.get());
115    add(lBaseDN, gbc);
116    gbc.insets.left = 10;
117    gbc.gridx = 1;
118    gbc.gridy = 0;
119    baseDNs = Utilities.createComboBox();
120    DefaultComboBoxModel model = new DefaultComboBoxModel();
121    baseDNs.setModel(model);
122    baseDNs.setRenderer(new CustomListCellRenderer(baseDNs));
123    ItemListener listener = new IgnoreItemListener(baseDNs);
124    baseDNs.addItemListener(listener);
125    baseDNs.addItemListener(new ItemListener()
126    {
127      @Override
128      public void itemStateChanged(final ItemEvent ev)
129      {
130        comboBoxSelected(hmIndexes, (CategorizedComboBoxElement) baseDNs.getSelectedItem(), addRemove);
131      }
132    });
133    listener.itemStateChanged(null);
134    add(baseDNs, gbc);
135    lNoBaseDNsFound = Utilities.createDefaultLabel(INFO_CTRL_PANEL_NO_BASE_DNS_FOUND_LABEL.get());
136    add(lNoBaseDNsFound, gbc);
137    lNoBaseDNsFound.setVisible(false);
138
139    lIndexes = Utilities.createPrimaryLabel(INFO_CTRL_PANEL_INDEXES_LABEL.get());
140    gbc.insets.top = 10;
141    gbc.insets.left = 0;
142    gbc.gridy++;
143    gbc.gridx = 0;
144    gbc.gridwidth = 1;
145    gbc.anchor = GridBagConstraints.NORTHWEST;
146    add(lIndexes, gbc);
147
148    addRemove = new AddRemovePanel<>(AbstractIndexDescriptor.class);
149    addRemove.getAvailableLabel().setText(INFO_CTRL_PANEL_AVAILABLE_INDEXES_LABEL.get().toString());
150    addRemove.getSelectedLabel().setText(INFO_CTRL_PANEL_SELECTED_INDEXES_LABEL.get().toString());
151
152    gbc.gridx = 1;
153    gbc.weightx = 1.0;
154    gbc.weighty = 0.0;
155    gbc.gridwidth = 1;
156    gbc.insets.top = 10;
157    gbc.insets.left = 10;
158    gbc.fill = GridBagConstraints.BOTH;
159    add(addRemove, gbc);
160
161    gbc.gridy++;
162    gbc.insets.top = 3;
163    JLabel explanation = Utilities.createInlineHelpLabel(INFO_CTRL_PANEL_REQUIRES_REBUILD_LEGEND.get());
164    add(explanation, gbc);
165
166    addBottomGlue(gbc);
167  }
168
169  @Override
170  public void setInfo(final ControlPanelInfo info)
171  {
172    super.setInfo(info);
173    ListCellRenderer indexCellRenderer = new IndexCellRenderer(addRemove.getAvailableList(), info);
174    addRemove.getAvailableList().setCellRenderer(indexCellRenderer);
175    addRemove.getSelectedList().setCellRenderer(indexCellRenderer);
176    info.addIndexModifiedListener(this);
177  }
178
179  @Override
180  public LocalizableMessage getTitle()
181  {
182    return INFO_CTRL_PANEL_REBUILD_INDEXES_TITLE.get();
183  }
184
185  @Override
186  public Component getPreferredFocusComponent()
187  {
188    return baseDNs;
189  }
190
191  @Override
192  public void configurationChanged(final ConfigurationChangeEvent ev)
193  {
194    refreshContents(ev.getNewDescriptor());
195  }
196
197  /**
198   * Refresh the contents of the panel with the provided server descriptor.
199   *
200   * @param desc
201   *          the server descriptor.
202   */
203  private void refreshContents(final ServerDescriptor desc)
204  {
205    super.updateIndexMap(desc, hmIndexes);
206    filterIndexes(hmIndexes);
207
208    updateBaseDNComboBoxModel((DefaultComboBoxModel) baseDNs.getModel(), desc);
209
210    if (!allDisabled(desc.getBackends()))
211    {
212      updateErrorPaneAndOKButtonIfAuthRequired(desc,
213              isLocal() ? INFO_CTRL_PANEL_AUTHENTICATION_REQUIRED_FOR_DISABLE_BACKEND.get()
214                        : INFO_CTRL_PANEL_CANNOT_CONNECT_TO_REMOTE_DETAILS.get(desc.getHostname()));
215    }
216    SwingUtilities.invokeLater(new Runnable()
217    {
218      @Override
219      public void run()
220      {
221        ViewPositions pos;
222        JScrollPane scroll = Utilities.getContainingScroll(RebuildIndexPanel.this);
223        if (scroll != null)
224        {
225          pos = Utilities.getViewPositions(scroll);
226        }
227        else
228        {
229          pos = Utilities.getViewPositions(RebuildIndexPanel.this);
230        }
231
232        boolean comboVisible = baseDNs.getModel().getSize() > 0;
233        baseDNs.setVisible(comboVisible);
234        lNoBaseDNsFound.setVisible(!comboVisible);
235        addRemove.getAvailableList().repaint();
236        addRemove.getSelectedList().repaint();
237
238        Utilities.updateViewPositions(pos);
239        if (!desc.isLocal())
240        {
241          displayErrorMessage(INFO_CTRL_PANEL_SERVER_REMOTE_SUMMARY.get(),
242              INFO_CTRL_PANEL_SERVER_MUST_BE_LOCAL_REBUILD_INDEX_SUMMARY.get());
243          setEnabledOK(false);
244        }
245        else
246        {
247          displayMainPanel();
248          setEnabledOK(true);
249        }
250      }
251    });
252  }
253
254  private boolean allDisabled(Set<BackendDescriptor> backends)
255  {
256    for (BackendDescriptor backend : backends)
257    {
258      if (displayBackend(backend) && backend.isEnabled())
259      {
260        return false;
261      }
262    }
263    return true;
264  }
265
266  @Override
267  public void cancelClicked()
268  {
269    setPrimaryValid(lBaseDN);
270    setSecondaryValid(addRemove.getSelectedLabel());
271    super.cancelClicked();
272  }
273
274  @Override
275  public void okClicked()
276  {
277    setPrimaryValid(lBaseDN);
278    setSecondaryValid(addRemove.getSelectedLabel());
279
280    final Set<LocalizableMessage> errors = new LinkedHashSet<>();
281    String baseDN = getSelectedBaseDN();
282
283    if (baseDN == null)
284    {
285      setPrimaryInvalid(lBaseDN);
286      if (baseDNs.getItemCount() == 0)
287      {
288        errors.add(ERR_CTRL_PANEL_NO_BASE_DNS_DEFINED_LABEL.get());
289      }
290      else
291      {
292        errors.add(ERR_CTRL_PANEL_MUST_SELECT_BASE_DN.get());
293      }
294    }
295
296    SortableListModel<AbstractIndexDescriptor> model = addRemove.getSelectedListModel();
297    if (model.getSize() == 0)
298    {
299      setSecondaryInvalid(addRemove.getSelectedLabel());
300      errors.add(ERR_CTRL_PANEL_MUST_SELECT_INDEX_TO_REBUILD.get());
301    }
302
303    if (errors.isEmpty())
304    {
305      ProgressDialog progressDialog =
306          new ProgressDialog(Utilities.createFrame(), Utilities.getParentDialog(this), getTitle(), getInfo());
307      Set<String> baseDNs = new HashSet<>();
308      baseDNs.add(getSelectedBaseDN());
309      RebuildIndexTask newTask =
310          new RebuildIndexTask(getInfo(), progressDialog, baseDNs, addRemove.getSelectedListModel().getData());
311      for (Task task : getInfo().getTasks())
312      {
313        task.canLaunch(newTask, errors);
314      }
315      boolean confirmed = true;
316
317      if (errors.isEmpty() && isServerRunning())
318      {
319        String backendName = newTask.getBackends().iterator().next();
320        confirmed =
321            displayConfirmationDialog(INFO_CTRL_PANEL_CONFIRMATION_REQUIRED_SUMMARY.get(),
322                INFO_CTRL_PANEL_CONFIRM_REBUILD_INDEX_DETAILS.get(backendName));
323      }
324      if (errors.isEmpty() && confirmed)
325      {
326        launchOperation(newTask, INFO_CTRL_PANEL_REBUILDING_INDEXES_SUMMARY.get(baseDN),
327            INFO_CTRL_PANEL_REBUILDING_INDEXES_SUCCESSFUL_SUMMARY.get(),
328            INFO_CTRL_PANEL_REBUILDING_INDEXES_SUCCESSFUL_DETAILS.get(),
329            ERR_CTRL_PANEL_REBUILDING_INDEXES_ERROR_SUMMARY.get(), null,
330            ERR_CTRL_PANEL_REBUILDING_INDEXES_ERROR_DETAILS, progressDialog);
331        progressDialog.setVisible(true);
332        Utilities.getParentDialog(this).setVisible(false);
333      }
334    }
335    if (!errors.isEmpty())
336    {
337      displayErrorDialog(errors);
338    }
339  }
340
341  @Override
342  protected boolean displayBackend(final BackendDescriptor backend)
343  {
344    return !backend.isConfigBackend() && backend.getType() == BackendDescriptor.Type.PLUGGABLE;
345  }
346
347  private String getSelectedBaseDN()
348  {
349    CategorizedComboBoxElement o = (CategorizedComboBoxElement) baseDNs.getSelectedItem();
350    return o != null ? (String) o.getValue() : null;
351  }
352
353  private void filterIndexes(final Map<String, SortedSet<AbstractIndexDescriptor>> hmIndexes)
354  {
355    // Remove the indexes that are not to be added.
356    for (SortedSet<AbstractIndexDescriptor> indexes : hmIndexes.values())
357    {
358      for (Iterator<AbstractIndexDescriptor> it = indexes.iterator(); it.hasNext();)
359      {
360        if (!mustBeDisplayed(it.next()))
361        {
362          it.remove();
363        }
364      }
365    }
366  }
367
368  private boolean mustBeDisplayed(final AbstractIndexDescriptor index)
369  {
370    if (index instanceof IndexDescriptor)
371    {
372      for (String name : RebuildIndexTask.INDEXES_NOT_TO_SPECIFY)
373      {
374        if (name.equalsIgnoreCase(index.getName()))
375        {
376          return false;
377        }
378      }
379    }
380    return true;
381  }
382}