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 java.math.BigDecimal; 019import java.math.MathContext; 020import java.util.concurrent.atomic.AtomicLong; 021 022import javax.money.MonetaryOperator; 023import javax.money.MonetaryQuery; 024 025/** 026 * This singleton class provides access to the predefined monetary functions. 027 * <p> 028 * The class is thread-safe, which is also true for all functions returned by 029 * this class. 030 * 031 * @author Anatole Tresch 032 */ 033public final class MonetaryUtil { 034 /** 035 * defaulkt Math context used. 036 */ 037 private static final MathContext DEFAULT_MATH_CONTEXT = initDefaultMathContext(); 038 /** 039 * Shared reciprocal instance. 040 */ 041 private static final Reciprocal RECIPROCAL = new Reciprocal(); 042 043 /** 044 * The shared instance of this class. 045 */ 046 private static final MinorPart MINORPART = new MinorPart(); 047 /** 048 * SHared minor units class. 049 */ 050 private static final MinorUnits MINORUNITS = new MinorUnits(); 051 /** 052 * Shared major part instance. 053 */ 054 private static final MajorPart MAJORPART = new MajorPart(); 055 /** 056 * Shared major units instance. 057 */ 058 private static final MajorUnits MAJORUNITS = new MajorUnits(); 059 060 /** 061 * Private singleton constructor. 062 */ 063 private MonetaryUtil() { 064 // Singleton constructor 065 } 066 067 /** 068 * Get {@link MathContext} for {@link Permil} instances. 069 * 070 * @return the {@link MathContext} to be used, by default 071 * {@link MathContext#DECIMAL64}. 072 */ 073 private static MathContext initDefaultMathContext() { 074 // TODO Initialize default, e.g. by system properties, or better: 075 // classpath properties! 076 return MathContext.DECIMAL64; 077 } 078 079 /** 080 * Return a {@link MonetaryOperator} realizing the reciprocal value of 081 * {@code f(R) = 1/R}. 082 * 083 * @return the reciprocal operator, never {@code null} 084 */ 085 public static MonetaryOperator reciprocal() { 086 return RECIPROCAL; 087 } 088 089 /** 090 * Factory method creating a new instance with the given {@code BigDecimal} permil value. 091 * 092 * @param decimal the decimal value of the permil operator being created. 093 * @return a new {@code Permil} operator 094 */ 095 public static MonetaryOperator permil(BigDecimal decimal) { 096 return new Permil(decimal); 097 } 098 099 /** 100 * Factory method creating a new instance with the given {@code Number} permil value. 101 * 102 * @param number the number value of the permil operator being created. 103 * @return a new {@code Permil} operator 104 */ 105 public static MonetaryOperator permil(Number number) { 106 return permil(number, DEFAULT_MATH_CONTEXT); 107 } 108 109 /** 110 * Factory method creating a new instance with the given {@code Number} permil value. 111 * 112 * @param number the number value of the permil operator being created. 113 * @return a new {@code Permil} operator 114 */ 115 public static MonetaryOperator permil(Number number, MathContext mathContext) { 116 return new Permil(getBigDecimal(number, mathContext)); 117 } 118 119 /** 120 * Factory method creating a new instance with the given {@code BigDecimal} percent value. 121 * 122 * @param decimal the decimal value of the percent operator being created. 123 * @return a new {@code Percent} operator 124 */ 125 public static MonetaryOperator percent(BigDecimal decimal) { 126 return new Percent(decimal); // TODO caching, e.g. array for 1-100 might 127 // work. 128 } 129 130 /** 131 * Factory method creating a new instance with the given {@code Number} percent value. 132 * 133 * @param number the number value of the percent operator being created. 134 * @return a new {@code Percent} operator 135 */ 136 public static MonetaryOperator percent(Number number) { 137 return percent(getBigDecimal(number, DEFAULT_MATH_CONTEXT)); 138 } 139 140 /** 141 * Access the shared instance of {@link MinorPart} for use. 142 * 143 * @return the shared instance, never {@code null}. 144 */ 145 public static MonetaryOperator minorPart() { 146 return MINORPART; 147 } 148 149 /** 150 * Access the shared instance of {@link MajorPart} for use. 151 * 152 * @return the shared instance, never {@code null}. 153 */ 154 public static MonetaryOperator majorPart() { 155 return MAJORPART; 156 } 157 158 /** 159 * Access the shared instance of {@link MinorUnits} for use. 160 * 161 * @return the shared instance, never {@code null}. 162 */ 163 public static MonetaryQuery<Long> minorUnits() { 164 return MINORUNITS; 165 } 166 167 /** 168 * Access the shared instance of {@link MajorUnits} for use. 169 * 170 * @return the shared instance, never {@code null}. 171 */ 172 public static MonetaryQuery<Long> majorUnits() { 173 return MAJORUNITS; 174 } 175 176 /** 177 * Converts to {@link BigDecimal}, if necessary, or casts, if possible. 178 * 179 * @param num The {@link Number} 180 * @param mathContext the {@link MathContext} 181 * @return the {@code number} as {@link BigDecimal} 182 */ 183 private static BigDecimal getBigDecimal(Number num, 184 MathContext mathContext) { 185 if (num instanceof BigDecimal) { 186 return (BigDecimal) num; 187 } 188 if (num instanceof Long || num instanceof Integer 189 || num instanceof Byte || num instanceof AtomicLong) { 190 return BigDecimal.valueOf(num.longValue()); 191 } 192 if (num instanceof Float || num instanceof Double) { 193 return new BigDecimal(num.toString()); 194 } 195 try { 196 // Avoid imprecise conversion to double value if at all possible 197 return new BigDecimal(num.toString(), mathContext); 198 } catch (NumberFormatException ignored) { 199 } 200 return BigDecimal.valueOf(num.doubleValue()); 201 } 202}