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