001package org.kuali.common.util.metainf.model; 002 003import static com.google.common.base.Preconditions.checkNotNull; 004 005import java.util.Comparator; 006 007/** 008 * <p> 009 * Sort lexicographically by directory structure, then filename. 010 * </p> 011 * 012 * For example: 013 * 014 * <pre> 015 * 2 - /a/foo2.txt 1 - /a/foo1.txt 016 * 3 - /a/b/foo.txt 2 - /a/foo2.txt 017 * 1 - /a/foo1.txt 3 - /a/b/foo.txt 018 * </pre> 019 * 020 */ 021public class PathComparator implements Comparator<String> { 022 023 @Override 024 public int compare(String path1, String path2) { 025 checkNotNull(path1, "'path1' cannot be null"); 026 checkNotNull(path2, "'path2' cannot be null"); 027 028 // Split the paths up into tokens 029 // Each token represents a directory in the directory structure 030 // The final token represents the filename 031 String[] tokens1 = getPathTokens(path1); 032 String[] tokens2 = getPathTokens(path2); 033 034 // Compare the path tokens 035 return compare(tokens1, tokens2); 036 } 037 038 /** 039 * Iterate over the tokens from both locations 040 */ 041 protected int compare(String[] tokens1, String[] tokens2) { 042 043 // Stop iterating when we hit the end of either array 044 for (int i = 0; i < tokens1.length && i < tokens2.length; i++) { 045 046 // Compare the 2 tokens at this index 047 int compare = compare(i, tokens1, tokens2); 048 049 // If the comparison comes back as anything but zero, we are done 050 if (compare != 0) { 051 return compare; 052 } 053 } 054 055 // If we get here, both arrays have the exact same number of tokens and all of the tokens in both arrays are identical 056 return 0; 057 } 058 059 protected int compare(int index, String[] tokens1, String[] tokens2) { 060 // We hit the end of 'one' but 'two' still has more tokens 061 // 'one' is less than 'two' 062 if (isLastToken(index, tokens1) && !isLastToken(index, tokens2)) { 063 return -1; 064 } 065 066 // We hit the end of 'two' but 'one' still has more tokens 067 // 'one' is greater than 'two' 068 if (!isLastToken(index, tokens1) && isLastToken(index, tokens2)) { 069 return 1; 070 } 071 072 // The 2 tokens at this index are either: 073 // 1 - The last token for both paths (and therefore the filename) 074 // OR 075 // 2 - NOT the last token for both paths (and therefore a directory) 076 return tokens1[index].compareTo(tokens2[index]); 077 } 078 079 /** 080 * Replace backslashes (if there are any) with forward slashes and split the string by forward slash 081 */ 082 protected String[] getPathTokens(String s) { 083 return s.replace('\\', '/').split("/"); 084 } 085 086 protected boolean isLastToken(int index, String[] tokens) { 087 return index == tokens.length - 1; 088 } 089 090}