001/* 002 * Units of Measurement Implementation for Java SE 003 * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. 004 * 005 * All rights reserved. 006 * 007 * Redistribution and use in source and binary forms, with or without modification, 008 * are permitted provided that the following conditions are met: 009 * 010 * 1. Redistributions of source code must retain the above copyright notice, 011 * this list of conditions and the following disclaimer. 012 * 013 * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions 014 * and the following disclaimer in the documentation and/or other materials provided with the distribution. 015 * 016 * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products 017 * derived from this software without specific prior written permission. 018 * 019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 020 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 021 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 022 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 023 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 024 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 025 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 026 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 027 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 028 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 029 */ 030package tec.uom.se; 031 032import javax.measure.UnitConverter; 033 034import tec.uom.se.function.Converter; 035 036import java.io.Serializable; 037import java.math.BigDecimal; 038import java.math.MathContext; 039import java.util.ArrayList; 040import java.util.List; 041import java.util.Objects; 042 043/** 044 * <p> 045 * The base class for our {@link UnitConverter} implementations. 046 * </p> 047 * 048 * @author <a href="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a> 049 * @author <a href="mailto:units@catmedia.us">Werner Keil</a> 050 * @version 1.0, August 9, 2016 051 * @since 1.0 052 */ 053public abstract class AbstractConverter implements UnitConverter, Converter<Number, Number>, Serializable { 054 055 /** 056 * 057 */ 058 private static final long serialVersionUID = 5790242858468427131L; 059 060 /** 061 * The ratio of the circumference of a circle to its diameter. 062 **/ 063 protected static final double PI = 3.1415926535897932384626433832795; 064 065 /** 066 * Holds identity converter. 067 */ 068 public static final AbstractConverter IDENTITY = new Identity(); 069 070 /** 071 * DefaultQuantityFactory constructor. 072 */ 073 protected AbstractConverter() { 074 } 075 076 /** 077 * Concatenates this physics converter with another physics converter. The resulting converter is equivalent to first converting by the specified 078 * converter (right converter), and then converting by this converter (left converter). 079 * 080 * @param that 081 * the other converter. 082 * @return the concatenation of this converter with that converter. 083 */ 084 public AbstractConverter concatenate(AbstractConverter that) { 085 return (that == IDENTITY) ? this : new Pair(this, that); 086 } 087 088 @Override 089 public boolean isIdentity() { 090 return false; 091 } 092 093 @Override 094 public abstract boolean equals(Object cvtr); 095 096 @Override 097 public abstract int hashCode(); 098 099 @Override 100 public abstract AbstractConverter inverse(); 101 102 @Override 103 public UnitConverter concatenate(UnitConverter converter) { 104 return (converter == IDENTITY) ? this : new Pair(this, converter); 105 } 106 107 @Override 108 public List<? extends UnitConverter> getConversionSteps() { 109 List<AbstractConverter> converters = new ArrayList<>(); 110 converters.add(this); 111 return converters; 112 } 113 114 /** 115 * @throws IllegalArgumentException 116 * if the value is </code>null</code>. 117 */ 118 public Number convert(Number value) { 119 if (value instanceof BigDecimal) { 120 return convert((BigDecimal) value, MathContext.DECIMAL128); 121 } 122 if (value != null) { 123 return convert(value.doubleValue()); 124 } else { 125 throw new IllegalArgumentException("Value cannot be null"); 126 } 127 } 128 129 @Override 130 public abstract double convert(double value); 131 132 public abstract BigDecimal convert(BigDecimal value, MathContext ctx) throws ArithmeticException; 133 134 /** 135 * This class represents the identity converter (singleton). 136 */ 137 private static final class Identity extends AbstractConverter { 138 139 /** 140 * 141 */ 142 private static final long serialVersionUID = -4460463244427587361L; 143 144 @Override 145 public boolean isIdentity() { 146 return true; 147 } 148 149 @Override 150 public Identity inverse() { 151 return this; 152 } 153 154 @Override 155 public double convert(double value) { 156 return value; 157 } 158 159 @Override 160 public BigDecimal convert(BigDecimal value, MathContext ctx) { 161 return value; 162 } 163 164 @Override 165 public UnitConverter concatenate(UnitConverter converter) { 166 return converter; 167 } 168 169 @Override 170 public boolean equals(Object cvtr) { 171 return (cvtr instanceof Identity); 172 } 173 174 @Override 175 public int hashCode() { 176 return 0; 177 } 178 179 @Override 180 public boolean isLinear() { 181 return true; 182 } 183 } 184 185 /** 186 * This class represents converters made up of two or more separate converters (in matrix notation <code>[pair] = [left] x [right]</code>). 187 */ 188 public static final class Pair extends AbstractConverter implements Serializable { 189 190 /** 191 * 192 */ 193 private static final long serialVersionUID = -123063827821728331L; 194 195 /** 196 * Holds the first converter. 197 */ 198 private final UnitConverter left; 199 200 /** 201 * Holds the second converter. 202 */ 203 private final UnitConverter right; 204 205 /** 206 * Creates a pair converter resulting from the combined transformation of the specified converters. 207 * 208 * @param left 209 * the left converter, not <code>null</code>. 210 * @param right 211 * the right converter. 212 * @throws IllegalArgumentException 213 * if either the left or right converter are </code> null</code> 214 */ 215 public Pair(UnitConverter left, UnitConverter right) { 216 if (left != null && right != null) { 217 this.left = left; 218 this.right = right; 219 } else { 220 throw new IllegalArgumentException("Converters cannot be null"); 221 } 222 } 223 224 @Override 225 public boolean isLinear() { 226 return left.isLinear() && right.isLinear(); 227 } 228 229 @Override 230 public boolean isIdentity() { 231 return false; 232 } 233 234 @Override 235 public List<UnitConverter> getConversionSteps() { 236 final List<UnitConverter> steps = new ArrayList<>(); 237 List<? extends UnitConverter> leftCompound = left.getConversionSteps(); 238 List<? extends UnitConverter> rightCompound = right.getConversionSteps(); 239 steps.addAll(leftCompound); 240 steps.addAll(rightCompound); 241 return steps; 242 } 243 244 @Override 245 public Pair inverse() { 246 return new Pair(right.inverse(), left.inverse()); 247 } 248 249 @Override 250 public double convert(double value) { 251 return left.convert(right.convert(value)); 252 } 253 254 @Override 255 public BigDecimal convert(BigDecimal value, MathContext ctx) { 256 if (right instanceof AbstractConverter) { 257 return ((AbstractConverter) left).convert(((AbstractConverter) right).convert(value, ctx), ctx); 258 } 259 return (BigDecimal) left.convert(right.convert(value)); 260 } 261 262 @Override 263 public boolean equals(Object obj) { 264 if (this == obj) { 265 return true; 266 } 267 if (obj instanceof Pair) { 268 Pair that = (Pair) obj; 269 return Objects.equals(left, that.left) && Objects.equals(right, that.right); 270 } 271 return false; 272 } 273 274 @Override 275 public int hashCode() { 276 return Objects.hash(left, right); 277 } 278 279 public UnitConverter getLeft() { 280 return left; 281 } 282 283 public UnitConverter getRight() { 284 return right; 285 } 286 } 287}