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 2009 Sun Microsystems, Inc.
025 *      Portions Copyright 2014-2015 ForgeRock AS
026 */
027package org.opends.guitools.controlpanel.datamodel;
028
029import java.util.ArrayList;
030import java.util.Collection;
031import java.util.Comparator;
032import java.util.HashSet;
033import java.util.LinkedHashSet;
034import java.util.Set;
035import java.util.TreeSet;
036
037import org.forgerock.i18n.LocalizableMessage;
038
039import static org.opends.guitools.controlpanel.util.Utilities.*;
040import static org.opends.messages.AdminToolMessages.*;
041import static org.opends.server.util.CollectionUtils.*;
042
043/**
044 * The abstract table model used to display all the network groups.
045 */
046public class DBEnvironmentMonitoringTableModel extends SortableTableModel
047implements Comparator<BackendDescriptor>
048{
049  private static final long serialVersionUID = 548035716525600536L;
050  private Set<BackendDescriptor> data = new HashSet<>();
051  private ArrayList<String[]> dataArray = new ArrayList<>();
052  private ArrayList<BackendDescriptor> dataSourceArray = new ArrayList<>();
053
054  private String[] columnNames = {};
055  private LocalizableMessage NO_VALUE_SET = INFO_CTRL_PANEL_NO_MONITORING_VALUE.get();
056  private LocalizableMessage NOT_IMPLEMENTED = INFO_CTRL_PANEL_NOT_IMPLEMENTED.get();
057
058  /** The operations to be displayed. */
059  private LinkedHashSet<String> attributes = new LinkedHashSet<>();
060  /** The sort column of the table. */
061  private int sortColumn;
062  /** Whether the sorting is ascending or descending. */
063  private boolean sortAscending = true;
064
065  /**
066   * Sets the data for this table model.
067   * @param newData the data for this table model.
068   */
069  public void setData(Set<BackendDescriptor> newData)
070  {
071    if (!newData.equals(data))
072    {
073      data.clear();
074      data.addAll(newData);
075      updateDataArray();
076      fireTableDataChanged();
077    }
078  }
079
080  /**
081   * Updates the table model contents and sorts its contents depending on the
082   * sort options set by the user.
083   */
084  @Override
085  public void forceResort()
086  {
087    updateDataArray();
088    fireTableDataChanged();
089  }
090
091  /**
092   * Updates the table model contents, sorts its contents depending on the
093   * sort options set by the user and updates the column structure.
094   */
095  public void forceDataStructureChange()
096  {
097    updateDataArray();
098    fireTableStructureChanged();
099    fireTableDataChanged();
100  }
101
102  /** {@inheritDoc} */
103  @Override
104  public int getColumnCount()
105  {
106    return columnNames.length;
107  }
108
109  /** {@inheritDoc} */
110  @Override
111  public int getRowCount()
112  {
113    return dataArray.size();
114  }
115
116  /** {@inheritDoc} */
117  @Override
118  public Object getValueAt(int row, int col)
119  {
120    return dataArray.get(row)[col];
121  }
122
123  /** {@inheritDoc} */
124  @Override
125  public String getColumnName(int col) {
126    return columnNames[col];
127  }
128
129  /** {@inheritDoc} */
130  @Override
131  public int compare(BackendDescriptor desc1, BackendDescriptor desc2)
132  {
133    CustomSearchResult monitor1 = desc1.getMonitoringEntry();
134    CustomSearchResult monitor2 = desc2.getMonitoringEntry();
135
136    ArrayList<Integer> possibleResults = newArrayList(getName(desc1).compareTo(getName(desc2)));
137    computeMonitoringPossibleResults(monitor1, monitor2, possibleResults, attributes);
138
139    int result = possibleResults.get(getSortColumn());
140    if (result == 0)
141    {
142      result = getFirstNonZero(possibleResults);
143    }
144    if (!isSortAscending())
145    {
146      result = -result;
147    }
148    return result;
149  }
150
151  private int getFirstNonZero(ArrayList<Integer> possibleResults)
152  {
153    for (int i : possibleResults)
154    {
155      if (i != 0)
156      {
157        return i;
158      }
159    }
160    return 0;
161  }
162
163  /**
164   * Returns whether the sort is ascending or descending.
165   * @return <CODE>true</CODE> if the sort is ascending and <CODE>false</CODE>
166   * otherwise.
167   */
168  @Override
169  public boolean isSortAscending()
170  {
171    return sortAscending;
172  }
173
174  /**
175   * Sets whether to sort ascending of descending.
176   * @param sortAscending whether to sort ascending or descending.
177   */
178  @Override
179  public void setSortAscending(boolean sortAscending)
180  {
181    this.sortAscending = sortAscending;
182  }
183
184  /**
185   * Returns the column index used to sort.
186   * @return the column index used to sort.
187   */
188  @Override
189  public int getSortColumn()
190  {
191    return sortColumn;
192  }
193
194  /**
195   * Sets the column index used to sort.
196   * @param sortColumn column index used to sort..
197   */
198  @Override
199  public void setSortColumn(int sortColumn)
200  {
201    this.sortColumn = sortColumn;
202  }
203
204  /**
205   * Returns the operations displayed by this table model.
206   * @return the operations displayed by this table model.
207   */
208  public Collection<String> getAttributes()
209  {
210    return attributes;
211  }
212
213  /**
214   * Sets the operations displayed by this table model.
215   * @param operations the operations displayed by this table model.
216   */
217  public void setAttributes(LinkedHashSet<String> operations)
218  {
219    this.attributes.clear();
220    this.attributes.addAll(operations);
221    columnNames = new String[operations.size() + 1];
222    columnNames[0] = INFO_CTRL_PANEL_DB_HEADER.get().toString();
223    int i = 1;
224    for (String operation : operations)
225    {
226      columnNames[i] = operation;
227      i++;
228    }
229  }
230
231  /**
232   * Updates the array data.  This includes resorting it.
233   */
234  private void updateDataArray()
235  {
236    TreeSet<BackendDescriptor> sortedSet = new TreeSet<>(this);
237    sortedSet.addAll(data);
238    dataArray.clear();
239    dataSourceArray.clear();
240    for (BackendDescriptor ach : sortedSet)
241    {
242      String[] s = getLine(ach);
243      dataArray.add(s);
244      dataSourceArray.add(ach);
245    }
246
247    // Add the total: always at the end
248
249    String[] line = new String[attributes.size() + 1];
250    line[0] = "<html><b>" + INFO_CTRL_PANEL_TOTAL_LABEL.get() + "</b>";
251    for (int i=1; i<line.length; i++)
252    {
253      boolean valueSet = false;
254      boolean notImplemented = false;
255      long totalValue = 0;
256      for (int j=0; j<dataArray.size(); j++)
257      {
258        String[] l = dataArray.get(j);
259        String value = l[i];
260        try
261        {
262          long v = Long.parseLong(value);
263          totalValue += v;
264          valueSet = true;
265        }
266        catch (Throwable t)
267        {
268          try
269          {
270            double v = Double.parseDouble(value);
271            totalValue += v;
272            valueSet = true;
273          }
274          catch (Throwable t2)
275          {
276            notImplemented = NOT_IMPLEMENTED.toString().equals(value);
277          }
278        }
279      }
280      if (notImplemented)
281      {
282        line[i] = NOT_IMPLEMENTED.toString();
283      }
284      else if (valueSet)
285      {
286        line[i] = String.valueOf(totalValue);
287      }
288      else
289      {
290        line[i] = NO_VALUE_SET.toString();
291      }
292    }
293    dataArray.add(line);
294  }
295
296  /**
297   * Returns the label to be used for the provided backend.
298   * @param backend the backend.
299   * @return the label to be used for the provided backend.
300   */
301  protected String getName(BackendDescriptor backend)
302  {
303    return backend.getBackendID();
304  }
305
306  /**
307   * Returns the monitoring entry associated with the provided backend.
308   * @param backend the backend.
309   * @return the monitoring entry associated with the provided backend.  Returns
310   * <CODE>null</CODE> if there is no monitoring entry associated.
311   */
312  protected CustomSearchResult getMonitoringEntry(BackendDescriptor backend)
313  {
314    return backend.getMonitoringEntry();
315  }
316
317  private String[] getLine(BackendDescriptor backend)
318  {
319    String[] line = new String[attributes.size() + 1];
320    line[0] = getName(backend);
321    int i = 1;
322    CustomSearchResult monitoringEntry = getMonitoringEntry(backend);
323    for (String attr : attributes)
324    {
325      String o = getFirstValueAsString(monitoringEntry, attr);
326      if (o != null)
327      {
328        line[i] = o;
329      }
330      else
331      {
332        line[i] = NO_VALUE_SET.toString();
333      }
334      i++;
335    }
336    return line;
337  }
338
339}