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