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