SearchConditionsValidator.java (5670B)
1 package xyz.kebigon.housesearch.domain; 2 3 import java.util.Arrays; 4 import java.util.Collection; 5 import java.util.stream.Stream; 6 7 import org.springframework.expression.Expression; 8 import org.springframework.expression.ExpressionParser; 9 import org.springframework.expression.spel.standard.SpelExpressionParser; 10 import org.springframework.expression.spel.support.StandardEvaluationContext; 11 12 import lombok.AllArgsConstructor; 13 import lombok.extern.slf4j.Slf4j; 14 import xyz.kebigon.housesearch.ApplicationContext; 15 16 @AllArgsConstructor 17 @Slf4j 18 public class SearchConditionsValidator 19 { 20 public static boolean validateBasicConditions(Posting posting, SearchConditions conditions) 21 { 22 final String url = posting.getUrl(); 23 if (url == null) 24 { 25 log.debug("Missing url for {}", posting); 26 return false; 27 } 28 29 final Long price = posting.getPrice(); 30 if (price == null) 31 { 32 log.debug("Missing price for {}", posting); 33 return false; 34 } 35 if (conditions.getMinPrice() != null && price < conditions.getMinPrice()) 36 return false; 37 if (conditions.getMaxPrice() != null && price > conditions.getMaxPrice()) 38 return false; 39 40 final Integer age = posting.getAge(); 41 if (age == null) 42 { 43 log.debug("Missing age for {}", posting); 44 return false; 45 } 46 if (conditions.getMinAge() != null && age < conditions.getMinAge()) 47 return false; 48 if (conditions.getMaxAge() != null && age > conditions.getMaxAge()) 49 return false; 50 51 final Double landSurface = posting.getLandSurface(); 52 if (landSurface == null) 53 { 54 log.debug("Missing landSurface for {}", posting); 55 return false; 56 } 57 if (conditions.getMinLandSurface() != null && landSurface < conditions.getMinLandSurface()) 58 return false; 59 if (conditions.getMaxLandSurface() != null && landSurface > conditions.getMaxLandSurface()) 60 return false; 61 62 final Double houseSurface = posting.getHouseSurface(); 63 if (houseSurface == null) 64 { 65 log.debug("Missing houseSurface for {}", posting); 66 return false; 67 } 68 if (conditions.getMinHouseSurface() != null && houseSurface < conditions.getMinHouseSurface()) 69 return false; 70 if (conditions.getMaxHouseSurface() != null && houseSurface > conditions.getMaxHouseSurface()) 71 return false; 72 73 final Integer walkTimeToStation = posting.getWalkTimeToStation(); 74 if (walkTimeToStation == null) 75 { 76 log.debug("Missing walkTimeToStation for {}", posting); 77 return false; 78 } 79 if (conditions.getMaxWalkTimeToStation() != null && walkTimeToStation > conditions.getMaxWalkTimeToStation()) 80 return false; 81 82 final String station = posting.getStation(); 83 if (station == null) 84 { 85 log.debug("Missing station for {}", posting); 86 return false; 87 } 88 89 return true; 90 } 91 92 public static boolean validateExpression(Posting posting, SearchConditions conditions) 93 { 94 final ExpressionParser expressionParser = new SpelExpressionParser(); 95 96 final StandardEvaluationContext context = new StandardEvaluationContext(); 97 context.setVariable("property", posting); 98 99 try 100 { 101 context.registerFunction("fastestRoute", 102 SearchConditionsValidator.class.getDeclaredMethod("getFastestRoute", new Class[] { Posting.class, String[].class })); 103 context.registerFunction("cheapestRoute", 104 SearchConditionsValidator.class.getDeclaredMethod("getCheapestRoute", new Class[] { Posting.class, String[].class })); 105 context.registerFunction("easiestRoute", 106 SearchConditionsValidator.class.getDeclaredMethod("getEasiestRoute", new Class[] { Posting.class, String[].class })); 107 108 context.registerFunction("timeToStation", 109 SearchConditionsValidator.class.getDeclaredMethod("timeToStation", new Class[] { Posting.class, String.class })); 110 context.registerFunction("fareToStation", 111 SearchConditionsValidator.class.getDeclaredMethod("fareToStation", new Class[] { Posting.class, String.class })); 112 context.registerFunction("transferToStation", 113 SearchConditionsValidator.class.getDeclaredMethod("transferToStation", new Class[] { Posting.class, String.class })); 114 } 115 catch (NoSuchMethodException | SecurityException e) 116 { 117 e.printStackTrace(); 118 throw new RuntimeException(e); 119 } 120 121 final Expression expression = expressionParser.parseExpression(conditions.getExpression()); 122 return expression.getValue(context, posting, Boolean.class); 123 } 124 125 private static Stream<Route> getRoutes(Posting posting, String... stations) 126 { 127 return Arrays.stream(stations) // 128 .flatMap(station -> { 129 final Collection<Route> routes = ApplicationContext.getYahooTransitBrowser().search(posting.getStation(), station); 130 routes.forEach(posting::updateRoutes); 131 return routes.stream(); 132 }); 133 } 134 135 private static Route getFastestRoute(Posting posting, String... stations) 136 { 137 return getRoutes(posting, stations).min(Route.TIME_COMPARATOR).orElse(Route.IMPOSSIBLE_ROUTE); 138 } 139 140 private static Route getCheapestRoute(Posting posting, String... stations) 141 { 142 return getRoutes(posting, stations).min(Route.FARE_COMPARATOR).orElse(Route.IMPOSSIBLE_ROUTE); 143 } 144 145 private static Route getEasiestRoute(Posting posting, String... stations) 146 { 147 return getRoutes(posting, stations).min(Route.TRANSFER_COMPARATOR).orElse(Route.IMPOSSIBLE_ROUTE); 148 } 149 150 @SuppressWarnings("unused") 151 private static int timeToStation(Posting posting, String station) 152 { 153 return getFastestRoute(posting, station).getTime() + posting.getWalkTimeToStation(); 154 } 155 156 @SuppressWarnings("unused") 157 private static int fareToStation(Posting posting, String station) 158 { 159 return getCheapestRoute(posting, station).getFare(); 160 } 161 162 @SuppressWarnings("unused") 163 private static int transferToStation(Posting posting, String station) 164 { 165 return getEasiestRoute(posting, station).getTransfer(); 166 } 167 }