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; 031 032import javax.measure.Dimension; 033import javax.measure.Quantity; 034import javax.measure.Unit; 035import javax.measure.spi.SystemOfUnits; 036 037import tech.units.indriya.format.SimpleUnitFormat; 038import tech.units.indriya.format.UnitStyle; 039import tech.uom.lib.common.function.Nameable; 040 041import static tech.units.indriya.format.UnitStyle.*; 042 043import java.util.*; 044import java.util.logging.Level; 045import java.util.logging.Logger; 046import java.util.stream.Collectors; 047 048/** 049 * <p> 050 * An abstract base class for unit systems. 051 * </p> 052 * 053 * @author <a href="mailto:werner@units.tech">Werner Keil</a> 054 * @version 1.2, June 21, 2018 055 * @since 1.0 056 */ 057public abstract class AbstractSystemOfUnits implements SystemOfUnits, Nameable { 058 /** 059 * Holds the units. 060 */ 061 protected final Set<Unit<?>> units = new HashSet<>(); 062 063 /** 064 * Holds the mapping quantity to unit. 065 */ 066 @SuppressWarnings("rawtypes") 067 protected final Map<Class<? extends Quantity>, Unit> quantityToUnit = new HashMap<>(); 068 069 protected static final Logger logger = Logger.getLogger(AbstractSystemOfUnits.class.getName()); 070 071 /** 072 * The natural logarithm. 073 **/ 074 protected static final double E = 2.71828182845904523536028747135266; 075 076 /* 077 * (non-Javadoc) 078 * 079 * @see SystemOfUnits#getName() 080 */ 081 public abstract String getName(); 082 083 // /////////////////// 084 // Collection View // 085 // /////////////////// 086 @Override 087 public Set<Unit<?>> getUnits() { 088 return Collections.unmodifiableSet(units); 089 } 090 091 @Override 092 public Set<? extends Unit<?>> getUnits(Dimension dimension) { 093 return this.getUnits().stream().filter(unit -> dimension.equals(unit.getDimension())) 094 .collect(Collectors.toSet()); 095 } 096 097 @SuppressWarnings("unchecked") 098 @Override 099 public <Q extends Quantity<Q>> Unit<Q> getUnit(Class<Q> quantityType) { 100 return quantityToUnit.get(quantityType); 101 } 102 103 @Override 104 public Unit<?> getUnit(String string) { 105 Objects.requireNonNull(string); 106 return this.getUnits().stream() 107 .filter((u) -> string.equals(u.toString())) 108 .findAny() 109 .orElse(null); 110 } 111 112 protected static class Helper { 113 static Set<Unit<?>> getUnitsOfDimension(final Set<Unit<?>> units, Dimension dimension) { 114 if (dimension != null) { 115 return units.stream().filter(u -> dimension.equals(u.getDimension())).collect(Collectors.toSet()); 116 117 } 118 return null; 119 } 120 121 /** 122 * Adds a new named unit to the collection. 123 * 124 * @param unit 125 * the unit being added. 126 * @param name 127 * the name of the unit. 128 * @return <code>unit</code>. 129 * @since 1.0 130 */ 131 public static <U extends Unit<?>> U addUnit(Set<Unit<?>> units, U unit, String name) { 132 return addUnit(units, unit, name, NAME); 133 } 134 135 /** 136 * Adds a new named unit to the collection. 137 * 138 * @param unit 139 * the unit being added. 140 * @param name 141 * the name of the unit. 142 * @param name 143 * the symbol of the unit. 144 * @return <code>unit</code>. 145 * @since 1.0 146 */ 147 public static <U extends Unit<?>> U addUnit(Set<Unit<?>> units, U unit, String name, String symbol) { 148 return addUnit(units, unit, name, symbol, NAME_AND_SYMBOL); 149 } 150 151 /** 152 * Adds a new named unit to the collection. 153 * 154 * @param unit 155 * the unit being added. 156 * @param name 157 * the name of the unit. 158 * @param name 159 * the symbol of the unit. 160 * @param style 161 * style of the unit. 162 * @return <code>unit</code>. 163 * @since 1.0.1 164 */ 165 @SuppressWarnings("unchecked") 166 public static <U extends Unit<?>> U addUnit(Set<Unit<?>> units, U unit, final String name, final String symbol, 167 UnitStyle style) { 168 switch (style) { 169 case NAME: 170 if (name != null && unit instanceof AbstractUnit) { 171 AbstractUnit<?> aUnit = (AbstractUnit<?>) unit; 172 aUnit.setName(name); 173 units.add(aUnit); 174 return (U) aUnit; 175 } 176 break; 177 case NAME_AND_SYMBOL: 178 case SYMBOL: 179 if (unit instanceof AbstractUnit) { 180 AbstractUnit<?> aUnit = (AbstractUnit<?>) unit; 181 if (name != null && NAME_AND_SYMBOL.equals(style)) { 182 aUnit.setName(name); 183 } 184 if (name != null && (SYMBOL.equals(style) || NAME_AND_SYMBOL.equals(style))) { 185 aUnit.setSymbol(symbol); 186 } 187 units.add(aUnit); 188 return (U) aUnit; 189 } 190 break; 191 case SYMBOL_AND_LABEL: 192 if (name != null && symbol != null && unit instanceof AbstractUnit) { 193 AbstractUnit<?> aUnit = (AbstractUnit<?>) unit; 194 aUnit.setName(name); 195 if (SYMBOL.equals(style) || SYMBOL_AND_LABEL.equals(style)) { 196 aUnit.setSymbol(symbol); 197 } 198 if (LABEL.equals(style) || SYMBOL_AND_LABEL.equals(style)) { 199 SimpleUnitFormat.getInstance().label(unit, symbol); 200 } 201 units.add(aUnit); 202 return (U) aUnit; 203 } 204 break; 205 default: 206 if (logger.isLoggable(Level.FINEST)) { 207 logger.log(Level.FINEST, 208 "Unknown style " + style + "; unit " + unit + " can't be rendered with '" + symbol + "'."); 209 } 210 break; 211 } 212 if (LABEL.equals(style) || SYMBOL_AND_LABEL.equals(style)) { 213 SimpleUnitFormat.getInstance().label(unit, symbol); 214 } 215 units.add(unit); 216 return unit; 217 } 218 219 /** 220 * Adds a new labeled unit to the set. 221 * 222 * @param units 223 * the set to add to. 224 * 225 * @param unit 226 * the unit being added. 227 * @param text 228 * the text for the unit. 229 * @param style 230 * style of the unit. 231 * @return <code>unit</code>. 232 * @since 1.0.1 233 */ 234 @SuppressWarnings("unchecked") 235 public static <U extends Unit<?>> U addUnit(Set<Unit<?>> units, U unit, String text, UnitStyle style) { 236 switch (style) { 237 case NAME: 238 if (text != null && unit instanceof AbstractUnit) { 239 AbstractUnit<?> aUnit = (AbstractUnit<?>) unit; 240 aUnit.setName(text); 241 units.add(aUnit); 242 return (U) aUnit; 243 } 244 break; 245 case SYMBOL: 246 if (text != null && unit instanceof AbstractUnit) { 247 AbstractUnit<?> aUnit = (AbstractUnit<?>) unit; 248 aUnit.setSymbol(text); 249 units.add(aUnit); 250 return (U) aUnit; 251 } 252 break; 253 case SYMBOL_AND_LABEL: 254 if (text != null && unit instanceof AbstractUnit) { 255 AbstractUnit<?> aUnit = (AbstractUnit<?>) unit; 256 aUnit.setSymbol(text); 257 units.add(aUnit); 258 SimpleUnitFormat.getInstance().label(aUnit, text); 259 return (U) aUnit; 260 } 261 // label in any case, returning below 262 SimpleUnitFormat.getInstance().label(unit, text); 263 break; 264 case LABEL: 265 SimpleUnitFormat.getInstance().label(unit, text); 266 break; 267 default: 268 logger.log(Level.FINEST, 269 "Unknown style " + style + "; unit " + unit + " can't be rendered with '" + text + "'."); 270 break; 271 } 272 units.add(unit); 273 return unit; 274 } 275 } 276}