001/* 002 * Units of Measurement Reference Implementation 003 * Copyright (c) 2005-2016, 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.units.ri.unit; 031 032import java.util.Map; 033 034import javax.measure.Dimension; 035import javax.measure.Quantity; 036import javax.measure.Unit; 037import javax.measure.UnitConverter; 038 039import tec.units.ri.AbstractUnit; 040import tec.uom.lib.common.function.UnitConverterSupplier; 041 042/** 043 * <p> 044 * This class represents the units derived from other units using {@linkplain UnitConverter converters}. 045 * </p> 046 * 047 * <p> 048 * Examples of transformed units:<code> 049 * CELSIUS = KELVIN.shift(273.15); 050 * FOOT = METRE.multiply(3048).divide(10000); 051 * MILLISECOND = MILLI(SECOND); 052 * </code> 053 * </p> 054 * 055 * <p> 056 * Transformed units have no symbol. But like all other units, they may have labels attached to them (see 057 * {@link javax.measure.format.UnitFormat#label(Unit, String)} 058 * </p> 059 * 060 * <p> 061 * Instances of this class are created through the {@link AbstractUnit#transform} method. 062 * </p> 063 * 064 * @param <Q> 065 * The type of the quantity measured by this unit. 066 * 067 * @author <a href="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a> 068 * @author <a href="mailto:units@catmedia.us">Werner Keil</a> 069 * @version 0.7, December 28, 2015 070 */ 071public final class TransformedUnit<Q extends Quantity<Q>> extends AbstractUnit<Q> implements UnitConverterSupplier { 072 073 /** 074 * 075 */ 076 // private static final long serialVersionUID = 1L; 077 078 /** 079 * Holds the parent unit (always a system unit). 080 */ 081 private final AbstractUnit<Q> parentUnit; 082 083 /** 084 * Holds the converter to the parent unit. 085 */ 086 private final UnitConverter converter; 087 088 /** 089 * Holds the symbol. 090 */ 091 private String symbol; 092 093 /** 094 * Creates a transformed unit from the specified system unit. 095 * 096 * @param parentUnit 097 * the system unit from which this unit is derived. 098 * @param unitConverter 099 * the converter to the parent units. 100 * @throws IllegalArgumentException 101 * if the specified parent unit is not an {@link AbstractUnit#isSystemUnit() system unit} 102 */ 103 public TransformedUnit(AbstractUnit<Q> parentUnit, UnitConverter unitConverter) { 104 if (!parentUnit.isSystemUnit()) 105 throw new IllegalArgumentException("The parent unit: " + parentUnit + " is not a system unit"); 106 this.parentUnit = parentUnit; 107 this.converter = unitConverter; 108 // this.symbol = parentUnit.getSymbol(); 109 } 110 111 /** 112 * Creates a transformed unit from the specified system unit. 113 * 114 * @parem symbol the symbol to use with this transformed unit. 115 * @param parentUnit 116 * the system unit from which this unit is derived. 117 * @param unitConverter 118 * the converter to the parent units. 119 * @throws IllegalArgumentException 120 * if the specified parent unit is not an {@link AbstractUnit#isSystemUnit() system unit} 121 */ 122 public TransformedUnit(String symbol, Unit<Q> parentUnit, UnitConverter unitConverter) { 123 if (parentUnit instanceof AbstractUnit) { 124 final AbstractUnit<Q> abParent = (AbstractUnit<Q>) parentUnit; 125 if (!abParent.isSystemUnit()) { 126 throw new IllegalArgumentException("The parent unit: " + abParent + " is not a system unit"); 127 } 128 this.parentUnit = abParent; 129 this.converter = unitConverter; 130 this.symbol = symbol; // TODO see 131 // https://github.com/unitsofmeasurement/uom-se/issues/54 132 } else { 133 throw new IllegalArgumentException("The parent unit: " + parentUnit + " is not an abstract unit."); 134 } 135 } 136 137 /** 138 * Creates a transformed unit from the specified system unit. 139 * 140 * @param parentUnit 141 * the system unit from which this unit is derived. 142 * @param toParentUnit 143 * the converter to the parent units. 144 * @throws IllegalArgumentException 145 * if the specified parent unit is not an {@link AbstractUnit#isSystemUnit() system unit} 146 * @throws ClassCastException 147 * if parentUnit is not a valid {@link Unit} implementation 148 */ 149 public TransformedUnit(Unit<Q> parentUnit, UnitConverter toParentUnit) { 150 this((AbstractUnit<Q>) parentUnit, toParentUnit); 151 } 152 153 @Override 154 public Dimension getDimension() { 155 return parentUnit.getDimension(); 156 } 157 158 @Override 159 public UnitConverter getSystemConverter() { 160 return parentUnit.getSystemConverter().concatenate(converter); 161 } 162 163 @Override 164 public AbstractUnit<Q> toSystemUnit() { 165 return parentUnit.getSystemUnit(); 166 } 167 168 @Override 169 public Map<? extends Unit<?>, Integer> getBaseUnits() { 170 return parentUnit.getBaseUnits(); 171 } 172 173 @Override 174 public int hashCode() { 175 return parentUnit.hashCode() + converter.hashCode(); 176 } 177 178 @Override 179 public boolean equals(Object that) { 180 if (this == that) 181 return true; 182 if (!(that instanceof TransformedUnit)) 183 return false; 184 TransformedUnit<?> thatUnit = (TransformedUnit<?>) that; 185 return this.parentUnit.equals(thatUnit.parentUnit) && this.converter.equals(thatUnit.converter); 186 } 187 188 @Override 189 // TODO clarify JavaDoc or adjust to what the Unit JavaDoc says. 190 public String getSymbol() { 191 if (super.getSymbol() != null) { 192 return super.getSymbol(); 193 } 194 return symbol; 195 } 196 197 public Unit<Q> getParentUnit() { 198 return parentUnit; 199 } 200 201 @Override 202 public UnitConverter getConverter() { 203 return converter; 204 } 205}