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