001/** 002 * Copyright (c) 2012, 2015, Anatole Tresch, Werner Keil and others by the @author tag. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); you may not 005 * use this file except in compliance with the License. You may obtain a copy of 006 * the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 012 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 013 * License for the specific language governing permissions and limitations under 014 * the License. 015 */ 016package org.javamoney.moneta.function; 017 018import java.util.Comparator; 019import java.util.List; 020import java.util.Map; 021import java.util.Objects; 022import java.util.function.BinaryOperator; 023import java.util.function.Predicate; 024import java.util.function.Supplier; 025import java.util.stream.Collector; 026import java.util.stream.Collectors; 027 028import javax.money.CurrencyUnit; 029import javax.money.MonetaryAmount; 030import javax.money.MonetaryException; 031import javax.money.convert.CurrencyConversion; 032import javax.money.convert.ExchangeRate; 033import javax.money.convert.ExchangeRateProvider; 034 035import org.javamoney.moneta.spi.MoneyUtils; 036 037/** 038 * This singleton class provides access to the predefined monetary functions. 039 * 040 * @author otaviojava 041 * @author anatole 042 * @author keilw 043 */ 044public final class MonetaryFunctions { 045 046 /** 047 * Private constructor for static accessor class. 048 */ 049 private MonetaryFunctions(){} 050 /** 051 * Collector to group by CurrencyUnit 052 * @return the Collector to of Map<CurrencyUnit, List<MonetaryAmount>> 053 */ 054 public static Collector<MonetaryAmount,?,Map<CurrencyUnit,List<MonetaryAmount>>> groupByCurrencyUnit(){ 055 return Collectors.groupingBy(MonetaryAmount::getCurrency); 056 } 057 058 /** 059 * Creates a the summary of MonetaryAmounts. 060 * @param currencyUnit the target {@link javax.money.CurrencyUnit} 061 * @return the MonetarySummaryStatistics 062 */ 063 public static Collector<MonetaryAmount, MonetarySummaryStatistics, MonetarySummaryStatistics> summarizingMonetary( 064 CurrencyUnit currencyUnit){ 065 Supplier<MonetarySummaryStatistics> supplier = () -> new DefaultMonetarySummaryStatistics(currencyUnit); 066 return Collector.of(supplier, MonetarySummaryStatistics::accept, MonetarySummaryStatistics::combine); 067 } 068 069 /** 070 * reates a the summary of MonetaryAmounts. 071 * @param currencyUnit the target {@link javax.money.CurrencyUnit} 072 * @param provider the rate provider 073 * @return the MonetarySummaryStatistics 074 * @deprecated Use #summarizingMonetary(CurrencyUnit) instead of. 075 */ 076 @Deprecated 077 public static Collector<MonetaryAmount, MonetarySummaryStatistics, MonetarySummaryStatistics> summarizingMonetary( 078 CurrencyUnit currencyUnit,javax.money.convert.ExchangeRateProvider provider){ 079 // TODO implement method here 080 return summarizingMonetary(currencyUnit); 081 } 082 083 /** 084 * of MonetaryAmount group by MonetarySummary 085 * @return the MonetarySummaryStatistics 086 */ 087 public static Collector<MonetaryAmount,GroupMonetarySummaryStatistics,GroupMonetarySummaryStatistics> 088 groupBySummarizingMonetary(){ 089 return Collector.of(GroupMonetarySummaryStatistics::new, GroupMonetarySummaryStatistics::accept, 090 GroupMonetarySummaryStatistics::combine); 091 } 092 093 /** 094 * Get a comparator for sorting CurrencyUnits ascending. 095 * 096 * @return the Comparator to sort by CurrencyUnit in ascending order, not null. 097 */ 098 public static Comparator<MonetaryAmount> sortCurrencyUnit(){ 099 return Comparator.comparing(MonetaryAmount::getCurrency); 100 } 101 102 /** 103 * comparator to sort the {@link MonetaryAmount} considering the 104 * {@link ExchangeRate} 105 * @param provider the rate provider to be used, not null. 106 * @return the sort of {@link MonetaryAmount} using {@link ExchangeRate} 107 */ 108 public static Comparator<? super MonetaryAmount> sortValuable( 109 ExchangeRateProvider provider) { 110 111 return (m1, m2) -> { 112 CurrencyConversion conversion = provider.getCurrencyConversion(m1 113 .getCurrency()); 114 return m1.compareTo(conversion.apply(m2)); 115 }; 116 } 117 118 /** 119 * comparator to sort the {@link MonetaryAmount} considering the 120 * {@link ExchangeRate} 121 * @param provider the rate provider to be used. 122 * @return the sort of {@link MonetaryAmount} using {@link ExchangeRate} 123 * @deprecated call #sortValuable instead of. 124 */ 125 @Deprecated 126 public static Comparator<? super MonetaryAmount> sortValiable(final ExchangeRateProvider provider) { 127 return sortValuable(provider); 128 } 129 130 /** 131 * Descending order of 132 * {@link MonetaryFunctions#sortValuable(ExchangeRateProvider)} 133 * @param provider the rate provider to be used. 134 * @return the Descending order of 135 * {@link MonetaryFunctions#sortValuable(ExchangeRateProvider)} 136 * @deprecated Use #sortValiableDesc instead of. 137 */ 138 @Deprecated 139 public static Comparator<? super MonetaryAmount> sortValiableDesc( 140 final ExchangeRateProvider provider) { 141 return sortValuableDesc(provider); 142 } 143 144 /** 145 * Descending order of 146 * {@link MonetaryFunctions#sortValuable(ExchangeRateProvider)} 147 * @param provider the rate provider to be used, not null. 148 * @return the Descending order of 149 * {@link MonetaryFunctions#sortValuable(ExchangeRateProvider)} 150 */ 151 public static Comparator<? super MonetaryAmount> sortValuableDesc( 152 ExchangeRateProvider provider) { 153 return sortValuable(provider).reversed(); 154 } 155 156 /** 157 * Get a comparator for sorting CurrencyUnits descending. 158 * @return the Comparator to sort by CurrencyUnit in descending order, not null. 159 */ 160 public static Comparator<MonetaryAmount> sortCurrencyUnitDesc(){ 161 return sortCurrencyUnit().reversed(); 162 } 163 164 /** 165 * Get a comparator for sorting amount by number value ascending. 166 * @return the Comparator to sort by number in ascending way, not null. 167 */ 168 public static Comparator<MonetaryAmount> sortNumber(){ 169 return Comparator.comparing(MonetaryAmount::getNumber); 170 } 171 172 /** 173 * Get a comparator for sorting amount by number value descending. 174 * @return the Comparator to sort by number in descending way, not null. 175 */ 176 public static Comparator<MonetaryAmount> sortNumberDesc(){ 177 return sortNumber().reversed(); 178 } 179 180 /** 181 * Create predicate that filters by CurrencyUnit. 182 * @param currencies 183 * the target {@link javax.money.CurrencyUnit} 184 * @return the predicate from CurrencyUnit 185 */ 186 public static Predicate<MonetaryAmount> isCurrency( 187 CurrencyUnit... currencies) { 188 189 if (Objects.isNull(currencies) || currencies.length == 0) { 190 return m -> true; 191 } 192 Predicate<MonetaryAmount> predicate = null; 193 194 for (CurrencyUnit currencyUnit : currencies) { 195 if (Objects.isNull(predicate)) { 196 predicate = m -> m.getCurrency().equals(currencyUnit); 197 } else { 198 predicate = predicate.or(m -> m.getCurrency().equals( 199 currencyUnit)); 200 } 201 } 202 return predicate; 203 } 204 205 /** 206 * Create predicate that filters by CurrencyUnit. 207 * @param currencies the target {@link javax.money.CurrencyUnit} instances 208 * @return the predicate from CurrencyUnit 209 */ 210 public static Predicate<MonetaryAmount> filterByExcludingCurrency( 211 CurrencyUnit... currencies) { 212 213 if (Objects.isNull(currencies) || currencies.length == 0) { 214 return m -> true; 215 } 216 return isCurrency(currencies).negate(); 217 } 218 219 /** 220 * Creates filter using isGreaterThan in MonetaryAmount. 221 * @param amount the amount to be compared to. 222 * @return the filter with isGreaterThan conditions 223 */ 224 public static Predicate<MonetaryAmount> isGreaterThan(MonetaryAmount amount){ 225 return m -> m.isGreaterThan(amount); 226 } 227 228 /** 229 * Creates filter using isGreaterThanOrEqualTo in MonetaryAmount 230 * @param amount the amount to be compared to. 231 * @return the filter with isGreaterThanOrEqualTo conditions 232 */ 233 public static Predicate<MonetaryAmount> isGreaterThanOrEqualTo(MonetaryAmount amount){ 234 return m -> m.isGreaterThanOrEqualTo(amount); 235 } 236 237 /** 238 * Creates filter using isLessThan in MonetaryAmount 239 * @param amount the amount to be compared to. 240 * @return the filter with isLessThan conditions 241 */ 242 public static Predicate<MonetaryAmount> isLessThan(MonetaryAmount amount){ 243 return m -> m.isLessThan(amount); 244 } 245 246 /** 247 * Creates filter using isLessThanOrEqualTo in MonetaryAmount 248 * @param amount the amount to be compared to. 249 * @return the filter with isLessThanOrEqualTo conditions 250 */ 251 public static Predicate<MonetaryAmount> isLessThanOrEqualTo(MonetaryAmount amount){ 252 return m -> m.isLessThanOrEqualTo(amount); 253 } 254 255 /** 256 * Creates a filter using the isBetween predicate. 257 * @param min min value inclusive, not null. 258 * @param max max value inclusive, not null. 259 * @return the Predicate between min and max. 260 */ 261 public static Predicate<MonetaryAmount> isBetween(MonetaryAmount min, MonetaryAmount max){ 262 return isLessThanOrEqualTo(max).and(isGreaterThanOrEqualTo(min)); 263 } 264 265 /** 266 * Adds two monetary together 267 * @param a the first operand 268 * @param b the second operand 269 * @return the sum of {@code a} and {@code b} 270 * @throws NullPointerException if a o b be null 271 * @throws MonetaryException if a and b have different currency 272 */ 273 public static MonetaryAmount sum(MonetaryAmount a, MonetaryAmount b){ 274 MoneyUtils.checkAmountParameter(Objects.requireNonNull(a), Objects.requireNonNull(b.getCurrency())); 275 return a.add(b); 276 } 277 278 /** 279 * Returns the smaller of two {@code MonetaryAmount} values. If the arguments 280 * have the same value, the result is that same value. 281 * @param a an argument. 282 * @param b another argument. 283 * @return the smaller of {@code a} and {@code b}. 284 */ 285 static MonetaryAmount min(MonetaryAmount a, MonetaryAmount b) { 286 MoneyUtils.checkAmountParameter(Objects.requireNonNull(a), Objects.requireNonNull(b.getCurrency())); 287 return a.isLessThan(b) ? a : b; 288 } 289 290 /** 291 * Returns the greater of two {@code MonetaryAmount} values. If the 292 * arguments have the same value, the result is that same value. 293 * @param a an argument. 294 * @param b another argument. 295 * @return the larger of {@code a} and {@code b}. 296 */ 297 static MonetaryAmount max(MonetaryAmount a, MonetaryAmount b) { 298 MoneyUtils.checkAmountParameter(Objects.requireNonNull(a), Objects.requireNonNull(b.getCurrency())); 299 return a.isGreaterThan(b) ? a : b; 300 } 301 302 /** 303 * Creates a BinaryOperator to sum. 304 * @return the sum BinaryOperator, not null. 305 */ 306 public static BinaryOperator<MonetaryAmount> sum(){ 307 return MonetaryFunctions::sum; 308 } 309 310 /** 311 * return the sum and convert all values to specific currency using the 312 * provider, if necessary 313 * @param provider the rate provider to be used, not null. 314 * @param currency 315 * currency 316 * @return the list convert to specific currency unit 317 */ 318 public static BinaryOperator<MonetaryAmount> sum( 319 ExchangeRateProvider provider, CurrencyUnit currency) { 320 CurrencyConversion currencyConversion = provider 321 .getCurrencyConversion(currency); 322 323 return (m1, m2) -> currencyConversion.apply(m1).add( 324 currencyConversion.apply(m2)); 325 } 326 327 /** 328 * Creates a BinaryOperator to calculate the minimum amount 329 * @return the minimum BinaryOperator, not null. 330 */ 331 public static BinaryOperator<MonetaryAmount> min(){ 332 return MonetaryFunctions::min; 333 } 334 335 /** 336 * return the minimum value, if the monetary amounts have different 337 * currencies, will converter first using the given ExchangeRateProvider 338 * @param provider 339 * the ExchangeRateProvider to convert the currencies 340 * @return the minimum value 341 */ 342 public static BinaryOperator<MonetaryAmount> min( 343 ExchangeRateProvider provider) { 344 345 return (m1, m2) -> { 346 CurrencyConversion conversion = provider.getCurrencyConversion(m1 347 .getCurrency()); 348 349 if (m1.isGreaterThan(conversion.apply(m2))) { 350 return m2; 351 } 352 return m1; 353 }; 354 } 355 356 /** 357 * Creates a BinaryOperator to calculate the maximum amount. 358 * @return the max BinaryOperator, not null. 359 */ 360 public static BinaryOperator<MonetaryAmount> max(){ 361 return MonetaryFunctions::max; 362 } 363 364 /** 365 * return the maximum value, if the monetary amounts have different 366 * currencies, will converter first using the given ExchangeRateProvider 367 * @param provider 368 * the ExchangeRateProvider to convert the currencies 369 * @return the maximum value 370 */ 371 public static BinaryOperator<MonetaryAmount> max( 372 ExchangeRateProvider provider) { 373 374 return (m1, m2) -> { 375 CurrencyConversion conversion = provider 376 .getCurrencyConversion(m1.getCurrency()); 377 378 if (m1.isGreaterThan(conversion.apply(m2))) { 379 return m1; 380 } 381 return m2; 382 }; 383 } 384 385 386}