001package org.kuali.common.util.metainf.model; 002 003import com.google.common.collect.ImmutableList; 004import com.google.common.collect.Ordering; 005import org.apache.commons.lang3.EnumUtils; 006import org.apache.commons.lang3.StringUtils; 007import org.kuali.common.util.metainf.spring.MetaInfDataLocation; 008import org.kuali.common.util.metainf.spring.MetaInfDataType; 009import org.springframework.util.CollectionUtils; 010 011import java.util.Collections; 012import java.util.List; 013 014/** 015 * <p> 016 * Sort first by the data passed into the configurable comparator, then sort lexicographically by directory structure, 017 * then filename 018 * </p> 019 * 020 * For example: 021 * 022 * <pre> 023 * 2 - server/demo/a/foo2.txt 1 - client/bootstrap/a/foo1.txt 024 * 3 - server/demo/a/b/foo.txt 2 - server/demo/a/foo2.txt 025 * 1 - client/bootstrap/a/foo1.txt 3 - server/demo/a/b/foo.txt 026 * </pre> 027 * 028 */ 029public class ConfigurablePathComparator extends PathComparator { 030 031 private List<String> qualifierOrder = Collections.emptyList(); 032 private List<MetaInfDataLocation> locationOrder = Collections.emptyList(); 033 private List<MetaInfDataType> typeOrder = Collections.emptyList(); 034 035 @Override 036 protected int compare(int index, String[] tokens1, String[] tokens2) { 037 String string1 = tokens1[index]; 038 String string2 = tokens2[index]; 039 040 if (!CollectionUtils.isEmpty(qualifierOrder)) { 041 if (qualifierOrder.contains(string1) && qualifierOrder.contains(string2)) { 042 int compare = Ordering.explicit(qualifierOrder).compare(string1, string2); 043 044 // If the comparison comes back as anything but zero, we are done 045 if (compare != 0) { 046 return compare; 047 } 048 } 049 } 050 051 if (!CollectionUtils.isEmpty(locationOrder)) { 052 if (isLocation(string1) && isLocation(string2)) { 053 MetaInfDataLocation location1 = MetaInfDataLocation.valueOf(StringUtils.upperCase(string1)); 054 MetaInfDataLocation location2 = MetaInfDataLocation.valueOf(StringUtils.upperCase(string2)); 055 056 int compare = Ordering.explicit(locationOrder).compare(location1, location2); 057 058 // If the comparison comes back as anything but zero, we are done 059 if (compare != 0) { 060 return compare; 061 } 062 } 063 } 064 065 if (!CollectionUtils.isEmpty(typeOrder)) { 066 if (isType(string1) && isType(string2)) { 067 MetaInfDataType type1 = MetaInfDataType.valueOf(StringUtils.upperCase(string1)); 068 MetaInfDataType type2 = MetaInfDataType.valueOf(StringUtils.upperCase(string2)); 069 070 int compare = Ordering.explicit(typeOrder).compare(type1, type2); 071 072 // If the comparison comes back as anything but zero, we are done 073 if (compare != 0) { 074 return compare; 075 } 076 } 077 } 078 079 return super.compare(index, tokens1, tokens2); 080 } 081 082 protected boolean isLocation(String token) { 083 return EnumUtils.isValidEnum(MetaInfDataLocation.class, StringUtils.upperCase(token)); 084 } 085 086 protected boolean isType(String token) { 087 return EnumUtils.isValidEnum(MetaInfDataType.class, StringUtils.upperCase(token)); 088 } 089 090 public static Builder builder() { 091 return new Builder(); 092 } 093 094 public static class Builder { 095 096 // Optional 097 private List<String> qualifierOrder = Collections.emptyList(); 098 private List<MetaInfDataLocation> locationOrder = Collections.emptyList(); 099 private List<MetaInfDataType> typeOrder = Collections.emptyList(); 100 101 public Builder qualifierOrder(List<String> qualifierOrder) { 102 this.qualifierOrder = qualifierOrder; 103 return this; 104 } 105 106 public Builder locationOrder(List<MetaInfDataLocation> locationOrder) { 107 this.locationOrder = locationOrder; 108 return this; 109 } 110 111 public Builder typeOrder(List<MetaInfDataType> typeOrder) { 112 this.typeOrder = typeOrder; 113 return this; 114 } 115 116 public ConfigurablePathComparator build() { 117 this.qualifierOrder = ImmutableList.copyOf(qualifierOrder); 118 this.locationOrder = ImmutableList.copyOf(locationOrder); 119 this.typeOrder = ImmutableList.copyOf(typeOrder); 120 return new ConfigurablePathComparator(this); 121 } 122 123 } 124 125 private ConfigurablePathComparator(Builder builder) { 126 this.qualifierOrder = builder.qualifierOrder; 127 this.locationOrder = builder.locationOrder; 128 this.typeOrder = builder.typeOrder; 129 } 130 131}