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