001/** 002 * Powerunit - A JDK1.8 test framework 003 * Copyright (C) 2014 Mathieu Boretti. 004 * 005 * This file is part of Powerunit 006 * 007 * Powerunit is free software: you can redistribute it and/or modify 008 * it under the terms of the GNU General Public License as published by 009 * the Free Software Foundation, either version 3 of the License, or 010 * (at your option) any later version. 011 * 012 * Powerunit is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 015 * GNU General Public License for more details. 016 * 017 * You should have received a copy of the GNU General Public License 018 * along with Powerunit. If not, see <http://www.gnu.org/licenses/>. 019 */ 020package ch.powerunit.extensions.exceptions; 021 022import static ch.powerunit.extensions.exceptions.Constants.verifyExceptionMapper; 023import static ch.powerunit.extensions.exceptions.Constants.verifyPredicate; 024import static java.util.Objects.requireNonNull; 025 026import java.nio.file.Path; 027import java.nio.file.PathMatcher; 028import java.util.function.Function; 029import java.util.function.Supplier; 030 031/** 032 * An interface that is implemented by objects that perform match operations on 033 * paths and may throw an exception. 034 * <h3>General contract</h3> 035 * <ul> 036 * <li><b>{@link #matches(Path) boolean matches(Path path) throws 037 * E}</b> - The functional method.</li> 038 * <li><b>uncheck</b> - Return a {@code PathMatcher}</li> 039 * <li><b>lift</b> - Return a {@code PathMatcher}</li> 040 * <li><b>ignore</b> - Return a {@code PathMatcher}</li> 041 * </ul> 042 * 043 * @see PathMatcher 044 * @param <E> 045 * the type of the potential exception of the function 046 * @since 1.1.0 047 */ 048@FunctionalInterface 049public interface PathMatcherWithException<E extends Exception> 050 extends PrimitiveReturnExceptionHandlerSupport<PathMatcher, PathMatcherWithException<E>>, BooleanDefaultValue { 051 052 /** 053 * Tells if given path matches this matcher's pattern. 054 * 055 * @param path 056 * the path to match 057 * 058 * @return {@code true} if, and only if, the path matches this matcher's pattern 059 * @throws E 060 * any exception 061 * @see PathMatcher#matches(Path) 062 */ 063 boolean matches(Path path) throws E; 064 065 @Override 066 default PathMatcher uncheckOrIgnore(boolean uncheck) { 067 return value -> { 068 try { 069 return matches(value); 070 } catch (Exception e) { 071 PrimitiveReturnExceptionHandlerSupport.handleException(uncheck, e, exceptionMapper()); 072 return defaultValue(); 073 } 074 }; 075 } 076 077 /** 078 * Returns a composed PathMatcher that represents a short-circuiting logical AND 079 * of this PathMatcher and another. When evaluating the composed predicate, if 080 * this predicate is {@code false}, then the {@code other} predicate is not 081 * evaluated. 082 * 083 * <p> 084 * Any exceptions thrown during evaluation of either PathMatcher are relayed to 085 * the caller; if evaluation of this predicate throws an exception, the 086 * {@code other} PathMatcher will not be evaluated. 087 * 088 * @param other 089 * a PathMatcher that will be logically-ANDed with this predicate 090 * @return a composed PathMatcher that represents the short-circuiting logical 091 * AND of this PathMatcher and the {@code other} PathMatcher 092 * @throws NullPointerException 093 * if other is null 094 * @see #or(PathMatcherWithException) 095 * @see #negate() 096 */ 097 default PathMatcherWithException<E> and(PathMatcherWithException<? extends E> other) { 098 requireNonNull(other); 099 return t -> matches(t) && other.matches(t); 100 } 101 102 /** 103 * Returns a PathMatcher that represents the logical negation of this 104 * PathMatcher. 105 * 106 * @return a PathMatcher that represents the logical negation of this 107 * PathMatcher 108 * @see #and(PathMatcherWithException) 109 * @see #or(PathMatcherWithException) 110 */ 111 default PathMatcherWithException<E> negate() { 112 return t -> !matches(t); 113 } 114 115 /** 116 * Negate a {@code PredicateWithException}. 117 * 118 * @param predicate 119 * to be negate 120 * @param <E> 121 * the type of the potential exception 122 * @return the negated PathMatcher 123 * @see #negate() 124 * @throws NullPointerException 125 * if predicate is null 126 */ 127 static <E extends Exception> PathMatcherWithException<E> negate(PathMatcherWithException<E> predicate) { 128 return verifyPredicate(predicate).negate(); 129 } 130 131 /** 132 * Returns a composed PathMatcher that represents a short-circuiting logical OR 133 * of this PathMatcher and another. When evaluating the composed PathMatcher, if 134 * this PathMatcher is {@code true}, then the {@code other} predicate is not 135 * evaluated. 136 * 137 * <p> 138 * Any exceptions thrown during evaluation of either PathMatcher are relayed to 139 * the caller; if evaluation of this PathMatcher throws an exception, the 140 * {@code other} PathMatcher will not be evaluated. 141 * 142 * @param other 143 * a PathMatcher that will be logically-ORed with this predicate 144 * @return a composed PathMatcher that represents the short-circuiting logical 145 * OR of this predicate and the {@code other} PathMatcher 146 * @throws NullPointerException 147 * if other is null 148 * @see #and(PathMatcherWithException) 149 * @see #negate() 150 */ 151 default PathMatcherWithException<E> or(PathMatcherWithException<? extends E> other) { 152 requireNonNull(other); 153 return t -> matches(t) || other.matches(t); 154 } 155 156 /** 157 * Returns a PathMatcher that always throw exception. 158 * 159 * @param exceptionBuilder 160 * the supplier to create the exception 161 * @param <E> 162 * the type of the exception 163 * @return a PathMatcher that always throw exception 164 */ 165 static <E extends Exception> PathMatcherWithException<E> failing(Supplier<E> exceptionBuilder) { 166 return t -> { 167 throw exceptionBuilder.get(); 168 }; 169 } 170 171 /** 172 * Converts a {@code PathMatcherWithException} to a {@code PathMatcher} that 173 * wraps exception to {@code RuntimeException}. 174 * 175 * @param predicate 176 * to be unchecked 177 * @param <E> 178 * the type of the potential exception 179 * @return the unchecked PathMatcher 180 * @see #uncheck() 181 * @see #unchecked(PathMatcherWithException, Function) 182 * @throws NullPointerException 183 * if predicate is null 184 */ 185 static <E extends Exception> PathMatcher unchecked(PathMatcherWithException<E> predicate) { 186 return verifyPredicate(predicate).uncheck(); 187 } 188 189 /** 190 * Converts a {@code PathMatcherWithException} to a {@code PathMatcher} that 191 * wraps exception to {@code RuntimeException} by using the provided mapping 192 * function. 193 * 194 * @param predicate 195 * the be unchecked 196 * @param exceptionMapper 197 * a function to convert the exception to the runtime exception. 198 * @param <E> 199 * the type of the potential exception 200 * @return the unchecked PathMatcher 201 * @see #uncheck() 202 * @see #unchecked(PathMatcherWithException) 203 * @throws NullPointerException 204 * if predicate or exceptionMapper is null 205 */ 206 static <E extends Exception> PathMatcher unchecked(PathMatcherWithException<E> predicate, 207 Function<Exception, RuntimeException> exceptionMapper) { 208 verifyPredicate(predicate); 209 verifyExceptionMapper(exceptionMapper); 210 return new PathMatcherWithException<E>() { 211 212 @Override 213 public boolean matches(Path t) throws E { 214 return predicate.matches(t); 215 } 216 217 @Override 218 public Function<Exception, RuntimeException> exceptionMapper() { 219 return exceptionMapper; 220 } 221 222 }.uncheck(); 223 } 224 225 /** 226 * Converts a {@code PathMatcherWithException} to a lifted {@code PathMatcher} 227 * returning {@code false} in case of exception. 228 * 229 * @param predicate 230 * to be lifted 231 * @param <E> 232 * the type of the potential exception 233 * @return the lifted PathMatcher 234 * @see #lift() 235 * @throws NullPointerException 236 * if predicate is null 237 */ 238 static <E extends Exception> PathMatcher lifted(PathMatcherWithException<E> predicate) { 239 return verifyPredicate(predicate).lift(); 240 } 241 242 /** 243 * Converts a {@code PathMatcherWithException} to a lifted {@code PathMatcher} 244 * returning {@code false} in case of exception. 245 * 246 * @param predicate 247 * to be lifted 248 * @param <E> 249 * the type of the potential exception 250 * @return the lifted PathMatcher 251 * @see #ignore() 252 * @throws NullPointerException 253 * if predicate is null 254 */ 255 static <E extends Exception> PathMatcher ignored(PathMatcherWithException<E> predicate) { 256 return verifyPredicate(predicate).ignore(); 257 } 258 259 /** 260 * Converts a {@code PathMatcherWithException} to a lifted {@code PathMatcher} 261 * returning a default value in case of exception. 262 * 263 * @param predicate 264 * to be lifted 265 * @param defaultValue 266 * value in case of exception 267 * @param <E> 268 * the type of the potential exception 269 * @return the lifted PathMatcher 270 * @see #ignore() 271 * @see #ignored(PathMatcherWithException) 272 * @throws NullPointerException 273 * if predicate is null 274 * @since 3.0.0 275 */ 276 static <E extends Exception> PathMatcher ignored(PathMatcherWithException<E> predicate, boolean defaultValue) { 277 verifyPredicate(predicate); 278 return new PathMatcherWithException<E>() { 279 280 @Override 281 public boolean matches(Path t) throws E { 282 return predicate.matches(t); 283 } 284 285 @Override 286 public boolean defaultValue() { 287 return defaultValue; 288 } 289 290 }.ignore(); 291 } 292 293}