001/* 002 * Units of Measurement Reference Implementation 003 * Copyright (c) 2005-2020, Units of Measurement project. 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-385, Indriya nor the names of their 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 tech.units.indriya.quantity; 031 032import static tech.units.indriya.unit.Units.AMPERE; 033import static tech.units.indriya.unit.Units.BECQUEREL; 034import static tech.units.indriya.unit.Units.CANDELA; 035import static tech.units.indriya.unit.Units.COULOMB; 036import static tech.units.indriya.unit.Units.CUBIC_METRE; 037import static tech.units.indriya.unit.Units.FARAD; 038import static tech.units.indriya.unit.Units.GRAY; 039import static tech.units.indriya.unit.Units.HENRY; 040import static tech.units.indriya.unit.Units.HERTZ; 041import static tech.units.indriya.unit.Units.JOULE; 042import static tech.units.indriya.unit.Units.KATAL; 043import static tech.units.indriya.unit.Units.KELVIN; 044import static tech.units.indriya.unit.Units.KILOGRAM; 045import static tech.units.indriya.unit.Units.LUMEN; 046import static tech.units.indriya.unit.Units.LUX; 047import static tech.units.indriya.unit.Units.METRE; 048import static tech.units.indriya.unit.Units.METRE_PER_SECOND; 049import static tech.units.indriya.unit.Units.METRE_PER_SQUARE_SECOND; 050import static tech.units.indriya.unit.Units.MOLE; 051import static tech.units.indriya.unit.Units.NEWTON; 052import static tech.units.indriya.unit.Units.OHM; 053import static tech.units.indriya.unit.Units.PASCAL; 054import static tech.units.indriya.unit.Units.RADIAN; 055import static tech.units.indriya.unit.Units.SECOND; 056import static tech.units.indriya.unit.Units.SIEMENS; 057import static tech.units.indriya.unit.Units.SIEVERT; 058import static tech.units.indriya.unit.Units.SQUARE_METRE; 059import static tech.units.indriya.unit.Units.STERADIAN; 060import static tech.units.indriya.unit.Units.TESLA; 061import static tech.units.indriya.unit.Units.VOLT; 062import static tech.units.indriya.unit.Units.WATT; 063import static tech.units.indriya.unit.Units.WEBER; 064 065import java.util.HashMap; 066import java.util.Map; 067import java.util.Objects; 068import java.util.concurrent.ConcurrentHashMap; 069import java.util.logging.Level; 070import java.util.logging.Logger; 071 072import javax.measure.Quantity; 073import javax.measure.Quantity.Scale; 074import javax.measure.Unit; 075import javax.measure.quantity.*; 076import javax.measure.spi.QuantityFactory; 077 078import tech.units.indriya.AbstractUnit; 079 080/** 081 * A factory producing simple quantities instances (tuples {@link Number}/ {@link Unit}).<br> 082 * 083 * For example:<br> 084 * <code> 085 * Mass m = DefaultQuantityFactory.getInstance(Mass.class).create(23.0, KILOGRAM); // 23.0 kg<br> 086 * Time m = DefaultQuantityFactory.getInstance(Time.class).create(124, MILLI(SECOND)); // 124 ms 087 * </code> 088 * 089 * @param <Q> 090 * The type of the quantity. 091 * 092 * @author <a href="mailto:martin.desruisseaux@geomatys.com">Martin Desruisseaux</a> 093 * @author <a href="mailto:werner@units.tech">Werner Keil</a> 094 * @author <a href="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a> 095 * @author <a href="mailto:otaviojava@java.net">Otavio Santana</a> 096 * @version 1.3, $Date: 2018-11-02 $ 097 * @since 1.0 098 */ 099public class DefaultQuantityFactory<Q extends Quantity<Q>> implements QuantityFactory<Q> { 100 @SuppressWarnings("rawtypes") 101 static final Map<Class, QuantityFactory> INSTANCES = new HashMap<>(); 102 103 static final Logger logger = Logger.getLogger(DefaultQuantityFactory.class.getName()); 104 105 static final Level LOG_LEVEL = Level.FINE; 106 107 /** 108 * The type of the quantities created by this factory. 109 */ 110 private final Class<Q> type; 111 112 /** 113 * The system unit for quantities created by this factory. 114 */ 115 private final Unit<Q> systemUnit; 116 117 @SuppressWarnings("rawtypes") 118 private static final Map<Class, Unit> CLASS_TO_SYSTEM_UNIT = new ConcurrentHashMap<>(); 119 120 static { 121 CLASS_TO_SYSTEM_UNIT.put(Dimensionless.class, AbstractUnit.ONE); 122 CLASS_TO_SYSTEM_UNIT.put(ElectricCurrent.class, AMPERE); 123 CLASS_TO_SYSTEM_UNIT.put(LuminousIntensity.class, CANDELA); 124 CLASS_TO_SYSTEM_UNIT.put(Temperature.class, KELVIN); 125 CLASS_TO_SYSTEM_UNIT.put(Mass.class, KILOGRAM); 126 CLASS_TO_SYSTEM_UNIT.put(Length.class, METRE); 127 CLASS_TO_SYSTEM_UNIT.put(AmountOfSubstance.class, MOLE); 128 CLASS_TO_SYSTEM_UNIT.put(Time.class, SECOND); 129 CLASS_TO_SYSTEM_UNIT.put(Angle.class, RADIAN); 130 CLASS_TO_SYSTEM_UNIT.put(SolidAngle.class, STERADIAN); 131 CLASS_TO_SYSTEM_UNIT.put(Frequency.class, HERTZ); 132 CLASS_TO_SYSTEM_UNIT.put(Force.class, NEWTON); 133 CLASS_TO_SYSTEM_UNIT.put(Pressure.class, PASCAL); 134 CLASS_TO_SYSTEM_UNIT.put(Energy.class, JOULE); 135 CLASS_TO_SYSTEM_UNIT.put(Power.class, WATT); 136 CLASS_TO_SYSTEM_UNIT.put(ElectricCharge.class, COULOMB); 137 CLASS_TO_SYSTEM_UNIT.put(ElectricPotential.class, VOLT); 138 CLASS_TO_SYSTEM_UNIT.put(ElectricCapacitance.class, FARAD); 139 CLASS_TO_SYSTEM_UNIT.put(ElectricResistance.class, OHM); 140 CLASS_TO_SYSTEM_UNIT.put(ElectricConductance.class, SIEMENS); 141 CLASS_TO_SYSTEM_UNIT.put(MagneticFlux.class, WEBER); 142 CLASS_TO_SYSTEM_UNIT.put(MagneticFluxDensity.class, TESLA); 143 CLASS_TO_SYSTEM_UNIT.put(ElectricInductance.class, HENRY); 144 CLASS_TO_SYSTEM_UNIT.put(LuminousFlux.class, LUMEN); 145 CLASS_TO_SYSTEM_UNIT.put(Illuminance.class, LUX); 146 CLASS_TO_SYSTEM_UNIT.put(Radioactivity.class, BECQUEREL); 147 CLASS_TO_SYSTEM_UNIT.put(RadiationDoseAbsorbed.class, GRAY); 148 CLASS_TO_SYSTEM_UNIT.put(RadiationDoseEffective.class, SIEVERT); 149 CLASS_TO_SYSTEM_UNIT.put(CatalyticActivity.class, KATAL); 150 CLASS_TO_SYSTEM_UNIT.put(Speed.class, METRE_PER_SECOND); 151 CLASS_TO_SYSTEM_UNIT.put(Acceleration.class, METRE_PER_SQUARE_SECOND); 152 CLASS_TO_SYSTEM_UNIT.put(Area.class, SQUARE_METRE); 153 CLASS_TO_SYSTEM_UNIT.put(Volume.class, CUBIC_METRE); 154 } 155 156 @SuppressWarnings("unchecked") 157 private DefaultQuantityFactory(Class<Q> quantity) { 158 type = quantity; 159 systemUnit = CLASS_TO_SYSTEM_UNIT.get(type); 160 } 161 162 /** 163 * Returns the default instance for the specified quantity type. 164 * 165 * @param <Q> 166 * The type of the quantity 167 * @param type 168 * the quantity type 169 * @return the quantity factory for the specified type 170 */ 171 @SuppressWarnings("unchecked") 172 public static <Q extends Quantity<Q>> QuantityFactory<Q> getInstance(final Class<Q> type) { 173 logger.log(LOG_LEVEL, "Type: " + type + ": " + type.isInterface()); 174 QuantityFactory<Q> factory; 175 factory = INSTANCES.get(type); 176 if (factory != null) { 177 return factory; 178 } 179 if (!Quantity.class.isAssignableFrom(type)) { 180 // This exception is not documented because it should never 181 // happen if the 182 // user don't try to trick the Java generic types system with 183 // unsafe cast. 184 throw new ClassCastException(); 185 } 186 factory = new DefaultQuantityFactory<Q>(type); 187 INSTANCES.put(type, factory); 188 return factory; 189 } 190 191 public String toString() { 192 return getClass().getName() + " <" + type.getName() + '>'; 193 } 194 195 public boolean equals(Object obj) { 196 if (DefaultQuantityFactory.class.isInstance(obj)) { 197 @SuppressWarnings("rawtypes") 198 DefaultQuantityFactory other = DefaultQuantityFactory.class.cast(obj); 199 return Objects.equals(type, other.type); 200 } 201 return false; 202 } 203 204 public int hashCode() { 205 return type.hashCode(); 206 } 207 208 public Quantity<Q> create(Number value, Unit<Q> unit) { 209 return Quantities.getQuantity(value, unit); 210 } 211 212 @Override 213 public Quantity<Q> create(Number value, Unit<Q> unit, Scale sc) { 214 return Quantities.getQuantity(value, unit, sc); 215 } 216 217 public Unit<Q> getSystemUnit() { 218 return systemUnit; 219 } 220}