001package com.identityworksllc.iiq.common; 002 003import sailpoint.object.SailPointObject; 004import sailpoint.tools.Util; 005 006import java.util.Collections; 007import java.util.Comparator; 008import java.util.Date; 009import java.util.List; 010 011/** 012 * A {@link Comparator} to sort {@link SailPointObject}s in a reliable way: first by date, and if the dates are 013 * identical, by ID. SPOs may have a null modified date, in which case the created 014 * date is checked. 015 * 016 * IMPORTANT: Before a new SPO is saved, the values of both 'created' and 'id' will be 017 * null. Take care that this class is not used in that context. 018 */ 019public final class SailPointObjectDateSorter implements Comparator<SailPointObject> { 020 021 /** 022 * Returns the latest date for the given SPO, including modified if the flag 023 * is set to true. If the object has no created or modified date (which will 024 * happen if it's not yet saved), returns null. 025 * 026 * @param sailPointObject The SPO to get the date 027 * @param includeModified If true, use the modified date if it is set; if false, use create only 028 * @return The modified or created date, or null if none 029 */ 030 public static Date latestDate(SailPointObject sailPointObject, boolean includeModified) { 031 if (includeModified && sailPointObject.getModified() != null) { 032 return sailPointObject.getModified(); 033 } else if (sailPointObject.getCreated() != null) { 034 return sailPointObject.getCreated(); 035 } else { 036 return null; 037 } 038 } 039 040 /** 041 * Sorts the given list of SPOs using this comparator 042 * @param list The list to sort 043 */ 044 public static void sort(List<? extends SailPointObject> list) { 045 list.sort(new SailPointObjectDateSorter()); 046 } 047 /** 048 * If true, the modified date will be considered in addition to create 049 */ 050 private final boolean includeModified; 051 052 /** 053 * SPO date sorter defaulting to checking modified dates 054 */ 055 public SailPointObjectDateSorter() { 056 this(true); 057 } 058 059 /** 060 * SPO date sorter allowing you to specify whether you want to include modified dates 061 * 062 * @param includeModified If true, use the modified date if it is set; if false, use create only 063 */ 064 public SailPointObjectDateSorter(boolean includeModified) { 065 this.includeModified = includeModified; 066 } 067 068 /** 069 * @see Comparator#compare(Object, Object) 070 */ 071 @Override 072 public int compare(SailPointObject o1, SailPointObject o2) { 073 // Ensures that nulls move to the start of the sorted list 074 if (o1 == null && o2 == null) { 075 return 0; 076 } else if (o1 == null) { 077 return 1; 078 } else if (o2 == null) { 079 return -1; 080 } 081 082 Date d1 = latestDate(o1, includeModified); 083 Date d2 = latestDate(o2, includeModified); 084 085 int compare = 0; 086 087 // This is convoluted to account for the weird chance that one or both of the dates is null. 088 // A null date will always go last in the list. 089 if (!Util.nullSafeEq(d1, d2, true)) { 090 if (d1 == null || d1.after(d2)) { 091 compare = 1; 092 } else if (d2 == null || d2.after(d1)) { 093 compare = -1; 094 } 095 } 096 097 if (compare == 0 && Util.isNotNullOrEmpty(o1.getId()) && Util.isNotNullOrEmpty(o2.getId())) { 098 compare = o1.getId().compareTo(o2.getId()); 099 } 100 101 return compare; 102 } 103 104}