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