| /** |
| * Copyright (c) 2005, 2017, Werner Keil and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * Werner Keil and others - initial API and implementation |
| */ |
| package org.eclipse.uomo.units; |
| |
| import java.io.Serializable; |
| import java.math.BigDecimal; |
| import java.math.MathContext; |
| import java.util.Arrays; |
| import java.util.List; |
| |
| import javax.measure.UnitConverter; |
| |
| /** |
| * <p> This class represents a converter of numeric values.</p> |
| * |
| * <p> It is not required for sub-classes to be immutable |
| * (e.g. currency converter).</p> |
| * |
| * <p> Sub-classes must ensure unicity of the {@linkplain #IDENTITY identity} |
| * converter. In other words, if the result of an operation is equivalent |
| * to the identity converter, then the unique {@link #IDENTITY} instance |
| * should be returned.</p> |
| * |
| * @author <a href="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a> |
| * @author <a href="mailto:uomo@catmedia.us">Werner Keil</a> |
| * @version 1.5, $Date: 2017-12-24 $ |
| */ |
| public abstract class AbstractConverter implements UnitConverter, Serializable { |
| |
| /** |
| * For cross-version compatibility. |
| */ |
| private static final long serialVersionUID = 2557410026012911803L; |
| |
| /** |
| * Holds the identity converter (unique). This converter does nothing |
| * (<code>ONE.convert(x) == x</code>). This instance is unique. |
| */ |
| public static final UnitConverter IDENTITY = new Identity(); |
| |
| /** |
| * Default constructor. |
| */ |
| protected AbstractConverter() { |
| } |
| |
| /** |
| * Returns the inverse of this converter. If <code>x</code> is a valid |
| * value, then <code>x == inverse().convert(convert(x))</code> to within |
| * the accuracy of computer arithmetic. |
| * |
| * @return the inverse of this converter. |
| */ |
| public abstract UnitConverter inverse(); |
| |
| public abstract BigDecimal convert(BigDecimal value, MathContext ctx) throws ArithmeticException; |
| |
| /** |
| * Indicates whether this converter is considered to be the the same as the |
| * one specified. |
| * |
| * @param cvtr the converter with which to compare. |
| * @return <code>true</code> if the specified object is a converter |
| * considered equals to this converter;<code>false</code> otherwise. |
| */ |
| // @Override |
| // public abstract boolean equals(Object cvtr); |
| |
| /** |
| * Returns a hash code value for this converter. Equals object have equal |
| * hash codes. |
| * |
| * @return this converter hash code value. |
| * @see #equals |
| */ |
| //@Override |
| //public abstract int hashCode(); |
| |
| /** |
| * Concatenates this converter with another converter. The resulting |
| * converter is equivalent to first converting by the specified converter |
| * (right converter), and then converting by this converter (left converter). |
| * |
| * <p>Note: Implementations must ensure that the {@link #IDENTITY} instance |
| * is returned if the resulting converter is an identity |
| * converter.</p> |
| * |
| * @param converter the other converter. |
| * @return the concatenation of this converter with the other converter. |
| */ |
| public UnitConverter concatenate(UnitConverter converter) { |
| return (converter == IDENTITY) ? this : new CompoundImpl(this, converter); |
| } |
| |
| @Override |
| public boolean isIdentity() { |
| return false; |
| } |
| |
| @Override |
| public List<UnitConverter> getConversionSteps() { |
| return Arrays.asList((UnitConverter)new CompoundImpl(this, this)); |
| } |
| |
| /** |
| * This interface is implemented by converters made up of two |
| * separate converters (in matrix notation |
| * <code>[compound] = [left] x [right]</code>). |
| */ |
| public interface Compound { |
| |
| /** |
| * Returns the left converter of this compound converter |
| * (the last one performing the conversion). |
| * |
| * @return the left converter. |
| */ |
| AbstractConverter getLeft(); |
| |
| /** |
| * Returns the right converter of this compound converter |
| * (the first one performing the conversion). |
| * |
| * @return the right converter. |
| */ |
| AbstractConverter getRight(); |
| } |
| |
| /** |
| * This inner class represents the identity converter (singleton). |
| */ |
| private static final class Identity extends AbstractConverter { |
| |
| /** |
| * For cross-version compatibility. |
| */ |
| private static final long serialVersionUID = 7675901502919547460L; |
| |
| @Override |
| public Identity inverse() { |
| return this; |
| } |
| |
| @Override |
| public double convert(double value) { |
| return value; |
| } |
| |
| public BigDecimal convert(BigDecimal value, MathContext ctx) { |
| return value; |
| } |
| |
| public Number convert(Number value) { |
| return value; |
| } |
| |
| @Override |
| public boolean equals(Object cvtr) { |
| return this == cvtr; // Unique instance. |
| } |
| |
| @Override |
| public int hashCode() { |
| return 0; |
| } |
| |
| @Override |
| public boolean isLinear() { |
| return true; |
| } |
| |
| @Override |
| public boolean isIdentity() { |
| return true; |
| } |
| } |
| |
| /** |
| * This inner class represents a compound converter (non-linear). |
| */ |
| private static final class CompoundImpl extends AbstractConverter implements Compound { |
| |
| /** |
| * For cross-version compatibility. |
| */ |
| private static final long serialVersionUID = 2242882007946934958L; |
| |
| /** |
| * Holds the first converter. |
| */ |
| private final AbstractConverter left; |
| |
| /** |
| * Holds the second converter. |
| */ |
| private final AbstractConverter right; |
| |
| /** |
| * Creates a compound converter resulting from the combined |
| * transformation of the specified converters. |
| * |
| * @param unitConverter the left converter. |
| * @param unitConverter2 the right converter. |
| */ |
| private CompoundImpl(UnitConverter unitConverter, UnitConverter unitConverter2) { |
| this.left = (AbstractConverter) unitConverter; |
| this.right = (AbstractConverter) unitConverter2; |
| } |
| |
| @Override |
| public UnitConverter inverse() { |
| return new CompoundImpl(right.inverse(), left.inverse()); |
| } |
| |
| @Override |
| public double convert(double value) { |
| return left.convert(right.convert(value)); |
| } |
| |
| public BigDecimal convert(BigDecimal value, MathContext ctx) { |
| return ((CompoundImpl)left).convert(((CompoundImpl)right).convert(value, ctx), ctx); |
| } |
| |
| |
| public Number convert(Number value) { |
| return left.convert(right.convert(value)); |
| } |
| |
| @Override |
| public boolean equals(Object cvtr) { |
| if (this == cvtr) |
| return true; |
| if (!(cvtr instanceof Compound)) |
| return false; |
| Compound that = (Compound) cvtr; |
| return (this.left.equals(that.getLeft())) |
| && (this.right.equals(that.getRight())); |
| } |
| |
| @Override |
| public int hashCode() { |
| return left.hashCode() + right.hashCode(); |
| } |
| |
| @Override |
| public boolean isLinear() { |
| return left.isLinear() && right.isLinear(); |
| } |
| |
| public AbstractConverter getLeft() { |
| return left; |
| } |
| |
| public AbstractConverter getRight() { |
| return right; |
| } |
| |
| @Override |
| public UnitConverter concatenate(UnitConverter converter) { |
| return (converter == IDENTITY) ? this : new CompoundImpl(this, converter); |
| } |
| |
| @Override |
| public List<UnitConverter> getConversionSteps() { |
| return Arrays.asList((UnitConverter)new CompoundImpl(this, this)); |
| } |
| } |
| } |