001/* 002 Copyright (c) 2012, 2014, Credit Suisse (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 static java.util.Objects.requireNonNull; 019 020import java.math.BigDecimal; 021import java.math.MathContext; 022import java.math.RoundingMode; 023import java.util.Objects; 024 025import javax.money.MonetaryAmount; 026import javax.money.MonetaryOperator; 027 028/** 029 * This implementation uses a scale and {@link RoundingMode} and precision to does the rounding operations. The implementation will use both the <b>scale</b> and <b>precision</b>, in other words, the number of digits to the right of the decimal point and the number of digits. 030 * The derived class will implements the {@link org.javamoney.moneta.RoundedMoney} with this rounding monetary operator 031 * <pre> 032 * {@code 033 * int scale = 3; 034 * int precision = 5; 035 * MathContext mathContext = new MathContext(precision, RoundingMode.HALF_EVEN); 036 * MonetaryOperator monetaryOperator = PrecisionScaleRoundedOperator.of(scale, mathContext); 037 * CurrencyUnit real = Monetary.getCurrency("BRL"); 038 * MonetaryAmount money = Money.of(BigDecimal.valueOf(35.34567), real); 039 * MonetaryAmount result = monetaryOperator.apply(money); // BRL 35.346 040 * 041 * } 042* </pre> 043 * Case the parameter in {@link MonetaryOperator#apply(MonetaryAmount)} be null, the apply will return a {@link NullPointerException} 044 * @author Otavio Santana 045 * @see org.javamoney.moneta.RoundedMoney 046 * @see MonetaryOperator 047 * @see BigDecimal#scale() 048 * @see MathContext 049 * @see BigDecimal#precision() 050 */ 051public final class PrecisionScaleRoundedOperator implements MonetaryOperator { 052 053 private final PrecisionContextRoundedOperator mathContextOperator; 054 055 private final ScaleRoundedOperator scaleRoundedOperator; 056 057 private final int scale; 058 059 private final MathContext mathContext; 060 061 private PrecisionScaleRoundedOperator(int scale, MathContext mathContext) { 062 this.scale = scale; 063 this.mathContext = mathContext; 064 this.mathContextOperator = PrecisionContextRoundedOperator.of(mathContext); 065 this.scaleRoundedOperator = ScaleRoundedOperator.of(scale, mathContext.getRoundingMode()); 066 } 067 068 /** 069 * Creates the rounded Operator from scale and roundingMode 070 * @param mathContext the math context, not null. 071 * @return the {@link MonetaryOperator} using the scale and {@link RoundingMode} used in parameter 072 * @throws NullPointerException when the {@link MathContext} is null 073 * @throws IllegalArgumentException if {@link MathContext#getPrecision()} is lesser than zero 074 * @throws IllegalArgumentException if {@link MathContext#getRoundingMode()} is {@link RoundingMode#UNNECESSARY} 075 * @see RoundingMode 076 */ 077 public static PrecisionScaleRoundedOperator of(int scale, MathContext mathContext) { 078 079 Objects.requireNonNull(mathContext); 080 081 if(RoundingMode.UNNECESSARY.equals(mathContext.getRoundingMode())) { 082 throw new IllegalArgumentException("To create the ScaleRoundedOperator you cannot use the RoundingMode.UNNECESSARY on MathContext"); 083 } 084 085 if(mathContext.getPrecision() <= 0) { 086 throw new IllegalArgumentException("To create the ScaleRoundedOperator you cannot use the zero precision on MathContext"); 087 } 088 return new PrecisionScaleRoundedOperator(scale, mathContext); 089 } 090 091 @Override 092 public MonetaryAmount apply(MonetaryAmount amount) { 093 return scaleRoundedOperator.apply(requireNonNull(amount)).with(mathContextOperator); 094 } 095 096 public int getScale() { 097 return scale; 098 } 099 100 public MathContext getMathContext() { 101 return mathContext; 102 } 103 104 @Override 105 public String toString() { 106 return PrecisionScaleRoundedOperator.class.getName() + '{' + 107 "scale:" + Integer.toString(scale) + ',' + 108 "mathContext:" + mathContext + '}'; 109 } 110 111}