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 2008 Sun Microsystems, Inc.
015 * Portions Copyright 2013-2015 ForgeRock AS.
016 */
017
018package org.opends.guitools.controlpanel.datamodel;
019
020import static org.opends.messages.AdminToolMessages.*;
021
022import java.util.ArrayList;
023import java.util.Comparator;
024import java.util.Date;
025import java.util.HashSet;
026import java.util.Set;
027import java.util.TreeSet;
028
029import org.opends.guitools.controlpanel.util.Utilities;
030import org.forgerock.i18n.LocalizableMessage;
031
032/**
033 * The table model used to display all the base DNs.
034 *
035 */
036public class BaseDNTableModel extends SortableTableModel
037implements Comparator<BaseDNDescriptor>
038{
039  private static final long serialVersionUID = -5650762484071136983L;
040  private HashSet<BaseDNDescriptor> data = new HashSet<>();
041  private ServerDescriptor.ServerStatus serverStatus;
042  private boolean isAuthenticated;
043
044  private ArrayList<String[]> dataArray = new ArrayList<>();
045  private String[] COLUMN_NAMES;
046  private int sortColumn;
047  private boolean sortAscending = true;
048  private boolean displayReplicationInformation;
049
050  /**
051   * Key value to identify the case of a value not available because the server
052   * is down.
053   */
054  public static String NOT_AVAILABLE_SERVER_DOWN = "NOT_AVAILABLE_SERVER_DOWN";
055
056  /**
057   * Key value to identify the case of a value not available because
058   * authentication is required.
059   */
060  public static String NOT_AVAILABLE_AUTHENTICATION_REQUIRED =
061    "NOT_AVAILABLE_AUTHENTICATION_REQUIRED";
062
063  /**
064   * Key value to identify the case of a value not available.
065   */
066  public static String NOT_AVAILABLE = "NOT_AVAILABLE";
067
068  /**
069   * Constructor for this table model.
070   * @param displayReplicationInformation whether to display replication.
071   * monitoring information or not.
072   */
073  public BaseDNTableModel(boolean displayReplicationInformation)
074  {
075    this(displayReplicationInformation, true);
076  }
077
078  /**
079   * Constructor for this table model.
080   * @param displayReplicationInformation whether to display replication.
081   * @param wrapHeader whether to wrap the headers or not.
082   * monitoring information or not.
083   */
084  public BaseDNTableModel(boolean displayReplicationInformation,
085      boolean wrapHeader)
086  {
087    this.displayReplicationInformation = displayReplicationInformation;
088    if (wrapHeader)
089    {
090     COLUMN_NAMES = new String[] {
091          getHeader(INFO_BASEDN_COLUMN.get()),
092          getHeader(INFO_BACKENDID_COLUMN.get()),
093          getHeader(INFO_NUMBER_ENTRIES_COLUMN.get()),
094          getHeader(INFO_REPLICATED_COLUMN.get()),
095          getHeader(INFO_MISSING_CHANGES_COLUMN.get()),
096          getHeader(INFO_AGE_OF_OLDEST_MISSING_CHANGE_COLUMN.get())
097      };
098    }
099    else
100    {
101      COLUMN_NAMES = new String[] {
102          INFO_BASEDN_COLUMN.get().toString(),
103          INFO_BACKENDID_COLUMN.get().toString(),
104          INFO_NUMBER_ENTRIES_COLUMN.get().toString(),
105          INFO_REPLICATED_COLUMN.get().toString(),
106          INFO_MISSING_CHANGES_COLUMN.get().toString(),
107          INFO_AGE_OF_OLDEST_MISSING_CHANGE_COLUMN.get().toString()
108      };
109    }
110  }
111
112  /**
113   * Sets the data for this table model.
114   * @param newData the data for this table model.
115   * @param status the server status.
116   * @param isAuthenticated whether the user provided authentication or not.
117   */
118  public void setData(Set<BaseDNDescriptor> newData,
119      ServerDescriptor.ServerStatus status, boolean isAuthenticated)
120  {
121    if (!newData.equals(data) || serverStatus != status || this.isAuthenticated != isAuthenticated)
122    {
123      serverStatus = status;
124      this.isAuthenticated = isAuthenticated;
125      data.clear();
126      data.addAll(newData);
127      updateDataArray();
128      fireTableDataChanged();
129    }
130  }
131
132  /**
133   * Updates the table model contents and sorts its contents depending on the
134   * sort options set by the user.
135   */
136  public void forceResort()
137  {
138    updateDataArray();
139    fireTableDataChanged();
140  }
141
142  /**
143   * Comparable implementation.
144   * @param desc1 the first replica descriptor to compare.
145   * @param desc2 the second replica descriptor to compare.
146   * @return 1 if according to the sorting options set by the user the first
147   * base DN descriptor must be put before the second descriptor, 0 if they
148   * are equivalent in terms of sorting and -1 if the second descriptor must
149   * be put before the first descriptor.
150   */
151  public int compare(BaseDNDescriptor desc1, BaseDNDescriptor desc2)
152  {
153    int result = 0;
154    if (sortColumn == 0)
155    {
156      result = compareDns(desc1, desc2);
157
158      if (result == 0)
159      {
160        result = compareBackendIDs(desc1, desc2);
161      }
162
163      if (result == 0)
164      {
165        result = compareEntries(desc1, desc2);
166      }
167
168      if (result == 0)
169      {
170        result = compareRepl(desc1, desc2);
171      }
172
173      if (result == 0)
174      {
175        result = compareMissingChanges(desc1, desc2);
176      }
177
178      if (result == 0)
179      {
180        result = compareAgeOfOldestMissingChange(desc1, desc2);
181      }
182    }
183
184    if (sortColumn == 1)
185    {
186      result = compareBackendIDs(desc1, desc2);
187
188      if (result == 0)
189      {
190        result = compareDns(desc1, desc2);
191
192      }
193
194      if (result == 0)
195      {
196        result = compareEntries(desc1, desc2);
197      }
198
199      if (result == 0)
200      {
201        result = compareRepl(desc1, desc2);
202      }
203
204      if (result == 0)
205      {
206        result = compareMissingChanges(desc1, desc2);
207      }
208
209      if (result == 0)
210      {
211        result = compareAgeOfOldestMissingChange(desc1, desc2);
212      }
213    }
214    else if (sortColumn == 2)
215    {
216      result = compareEntries(desc1, desc2);
217
218      if (result == 0)
219      {
220        result = compareBackendIDs(desc1, desc2);
221      }
222
223      if (result == 0)
224      {
225        result = compareDns(desc1, desc2);
226      }
227
228      if (result == 0)
229      {
230        result = compareRepl(desc1, desc2);
231      }
232
233      if (result == 0)
234      {
235        result = compareMissingChanges(desc1, desc2);
236      }
237
238      if (result == 0)
239      {
240        result = compareAgeOfOldestMissingChange(desc1, desc2);
241      }
242    }
243    else if (sortColumn == 3)
244    {
245      result = compareRepl(desc1, desc2);
246
247      if (result == 0)
248      {
249        result = compareBackendIDs(desc1, desc2);
250      }
251
252      if (result == 0)
253      {
254        result = compareDns(desc1, desc2);
255      }
256
257      if (result == 0)
258      {
259        result = compareEntries(desc1, desc2);
260      }
261
262      if (result == 0)
263      {
264        result = compareMissingChanges(desc1, desc2);
265      }
266
267      if (result == 0)
268      {
269        result = compareAgeOfOldestMissingChange(desc1, desc2);
270      }
271    }
272    else if (sortColumn == 4)
273    {
274      result = compareMissingChanges(desc1, desc2);
275
276      if (result == 0)
277      {
278        result = compareBackendIDs(desc1, desc2);
279      }
280
281      if (result == 0)
282      {
283        result = compareDns(desc1, desc2);
284      }
285
286      if (result == 0)
287      {
288        result = compareEntries(desc1, desc2);
289      }
290
291      if (result == 0)
292      {
293        result = compareRepl(desc1, desc2);
294      }
295
296      if (result == 0)
297      {
298        result = compareAgeOfOldestMissingChange(desc1, desc2);
299      }
300    }
301    else if (sortColumn == 5)
302    {
303      result = compareAgeOfOldestMissingChange(desc1, desc2);
304
305      if (result == 0)
306      {
307        result = compareBackendIDs(desc1, desc2);
308      }
309
310      if (result == 0)
311      {
312        result = compareDns(desc1, desc2);
313      }
314
315      if (result == 0)
316      {
317        result = compareEntries(desc1, desc2);
318      }
319
320      if (result == 0)
321      {
322        result = compareRepl(desc1, desc2);
323      }
324
325      if (result == 0)
326      {
327        result = compareMissingChanges(desc1, desc2);
328      }
329    }
330
331    if (!sortAscending)
332    {
333      result = -result;
334    }
335
336    return result;
337  }
338
339  /** {@inheritDoc} */
340  public int getColumnCount()
341  {
342    return displayReplicationInformation ? 6 : 4;
343  }
344
345  /** {@inheritDoc} */
346  public int getRowCount()
347  {
348    return dataArray.size();
349  }
350
351  /** {@inheritDoc} */
352  public Object getValueAt(int row, int col)
353  {
354    return dataArray.get(row)[col];
355  }
356
357  /** Updates the array data.  This includes resorting it. */
358  private void updateDataArray()
359  {
360    TreeSet<BaseDNDescriptor> sortedSet = new TreeSet<>(this);
361    sortedSet.addAll(data);
362    dataArray.clear();
363    for (BaseDNDescriptor desc : sortedSet)
364    {
365      dataArray.add(new String[] {
366        Utilities.unescapeUtf8(desc.getDn().toString()),
367        desc.getBackend().getBackendID(),
368        getValueForEntries(desc),
369        getStringForReplState(desc),
370        getValueForMissingChanges(desc),
371        getValueForOldestMissingChange(desc)
372      });
373    }
374  }
375
376  /** {@inheritDoc} */
377  public String getColumnName(int col) {
378    return COLUMN_NAMES[col];
379  }
380
381  /**
382   * Returns whether the sort is ascending or descending.
383   * @return <CODE>true</CODE> if the sort is ascending and <CODE>false</CODE>
384   * otherwise.
385   */
386  public boolean isSortAscending()
387  {
388    return sortAscending;
389  }
390
391  /**
392   * Sets whether to sort ascending of descending.
393   * @param sortAscending whether to sort ascending or descending.
394   */
395  public void setSortAscending(boolean sortAscending)
396  {
397    this.sortAscending = sortAscending;
398  }
399
400  /**
401   * Returns the column index used to sort.
402   * @return the column index used to sort.
403   */
404  public int getSortColumn()
405  {
406    return sortColumn;
407  }
408
409  /**
410   * Sets the column index used to sort.
411   * @param sortColumn column index used to sort..
412   */
413  public void setSortColumn(int sortColumn)
414  {
415    this.sortColumn = sortColumn;
416  }
417
418  /** Several comparison methods to be able to sort the table model. */
419  private int compareBackendIDs(BaseDNDescriptor desc1, BaseDNDescriptor desc2)
420  {
421    return desc1.getBackend().getBackendID().compareTo(
422      desc2.getBackend().getBackendID());
423  }
424
425  private int compareEntries(BaseDNDescriptor desc1, BaseDNDescriptor desc2)
426  {
427    int n1 = desc1.getEntries();
428    int n2 = desc2.getEntries();
429    return compareIntegers(n1, n2);
430  }
431
432  private int compareIntegers(int n1, int n2)
433  {
434    if (n1 == n2)
435    {
436      return 0;
437    }
438    if (n1 > n2)
439    {
440      return 1;
441    }
442    return -1;
443  }
444
445  private int compareLongs(long n1, long n2)
446  {
447    if (n1 == n2)
448    {
449      return 0;
450    }
451    if (n1 > n2)
452    {
453      return 1;
454    }
455    return -1;
456  }
457
458  private int compareDns(BaseDNDescriptor desc1, BaseDNDescriptor desc2)
459  {
460    return Utilities.unescapeUtf8(desc1.getDn().toString()).compareTo(
461        Utilities.unescapeUtf8(desc2.getDn().toString()));
462  }
463
464  private int compareRepl(BaseDNDescriptor desc1, BaseDNDescriptor desc2)
465  {
466    String val1 = String.valueOf(desc1.getType());
467    String val2 = String.valueOf(desc2.getType());
468    return val1.compareTo(val2);
469  }
470
471  private int compareMissingChanges(BaseDNDescriptor desc1,
472      BaseDNDescriptor desc2)
473  {
474    return compareIntegers(desc1.getMissingChanges(),
475        desc2.getMissingChanges());
476  }
477
478  private int compareAgeOfOldestMissingChange(BaseDNDescriptor desc1,
479      BaseDNDescriptor desc2)
480  {
481    return compareLongs(desc1.getAgeOfOldestMissingChange(),
482        desc2.getAgeOfOldestMissingChange());
483  }
484
485  /**
486   * Returns the Object describing the number of entries of a given Base DN.
487   * The Object will be an Integer.
488   * @param rep the Base DN object to handle.
489   * @return the Object describing the number of entries of a given Base DN.
490   */
491  private String getValueForEntries(BaseDNDescriptor rep)
492  {
493    String returnValue;
494    if (serverStatus != ServerDescriptor.ServerStatus.STARTED)
495    {
496      returnValue = NOT_AVAILABLE_SERVER_DOWN;
497    }
498    else if (!isAuthenticated)
499    {
500      returnValue = NOT_AVAILABLE_AUTHENTICATION_REQUIRED;
501    }
502    else
503    {
504      if (rep.getEntries() < 0)
505      {
506        returnValue = NOT_AVAILABLE;
507      }
508      else
509      {
510        returnValue = String.valueOf(rep.getEntries());
511      }
512    }
513    return returnValue;
514  }
515
516  /**
517   * Returns the Object describing the number of missing changes of a given Base
518   * DN.  The Object will be a String unless the base DN is
519   * replicated and we could not find a valid value (in this case we return
520   * an Integer with the invalid value).
521   * @param rep the Base DN object to handle.
522   * @return the Object describing the number of missing changes of
523   * a given Base DN.
524   */
525  private String getValueForMissingChanges(BaseDNDescriptor rep)
526  {
527    String returnValue;
528    if (rep.getType() == BaseDNDescriptor.Type.REPLICATED)
529    {
530      if (serverStatus != ServerDescriptor.ServerStatus.STARTED)
531      {
532        returnValue = NOT_AVAILABLE_SERVER_DOWN;
533      }
534      else if (!isAuthenticated)
535      {
536        returnValue = NOT_AVAILABLE_AUTHENTICATION_REQUIRED;
537      }
538      else
539      {
540        if (rep.getMissingChanges() < 0)
541        {
542          returnValue = NOT_AVAILABLE;
543        }
544        else
545        {
546          returnValue = String.valueOf(rep.getMissingChanges());
547        }
548      }
549    }
550    else
551    {
552      returnValue = INFO_NOT_APPLICABLE_LABEL.get().toString();
553    }
554    return returnValue;
555  }
556
557  /**
558   * Returns the Object describing the age of oldest missing change of
559   * a given Base DN.  The Object will be a String unless the base DN is
560   * replicated and we could not find a valid value (in this case we return
561   * an Integer with the invalid value).
562   * @param rep the Base DN object to handle.
563   * @return the Object describing the age of oldest missing change of
564   * a given Base DN.
565   */
566  private String getValueForOldestMissingChange(BaseDNDescriptor rep)
567  {
568    String returnValue;
569    if (rep.getType() == BaseDNDescriptor.Type.REPLICATED)
570    {
571      if (serverStatus != ServerDescriptor.ServerStatus.STARTED)
572      {
573        returnValue = NOT_AVAILABLE_SERVER_DOWN;
574      }
575      else if (!isAuthenticated)
576      {
577        returnValue = NOT_AVAILABLE_AUTHENTICATION_REQUIRED;
578      }
579      else
580      {
581        long age = rep.getAgeOfOldestMissingChange();
582        if (age > 0)
583        {
584          Date date = new Date(age);
585          returnValue = date.toString();
586        }
587        else
588        {
589          // Not available
590          returnValue = NOT_AVAILABLE;
591        }
592      }
593    }
594    else
595    {
596      returnValue = INFO_NOT_APPLICABLE_LABEL.get().toString();
597    }
598    return returnValue;
599  }
600
601  /**
602   * Returns the localized String describing the replication state of
603   * a given Base DN.
604   * @param rep the Base DN object to handle.
605   * @return the localized String describing the replication state of
606   * a given Base DN.
607   */
608  private String getStringForReplState(BaseDNDescriptor rep)
609  {
610    LocalizableMessage s;
611    if (rep.getType() == BaseDNDescriptor.Type.REPLICATED)
612    {
613      s = INFO_BASEDN_REPLICATED_LABEL.get();
614    }
615    else if (rep.getType() == BaseDNDescriptor.Type.NOT_REPLICATED)
616    {
617      s = INFO_BASEDN_NOT_REPLICATED_LABEL.get();
618    }
619    else
620    {
621      s = INFO_BASEDN_DISABLED_LABEL.get();
622    }
623    return s.toString();
624  }
625}