001/* 002 * Units of Measurement Reference Implementation 003 * Copyright (c) 2005-2018, Jean-Marie Dautelle, Werner Keil, Otavio Santana. 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:units@catmedia.us">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 @SuppressWarnings("unchecked") 148 public static <U extends Unit<?>> U addUnit(Set<Unit<?>> units, U unit, String name, String symbol) { 149 if (name != null && symbol != null && unit instanceof AbstractUnit) { 150 AbstractUnit<?> aUnit = (AbstractUnit<?>) unit; 151 aUnit.setName(name); 152 aUnit.setSymbol(symbol); 153 units.add(aUnit); 154 return (U) aUnit; 155 } 156 if (name != null && unit instanceof AbstractUnit) { 157 AbstractUnit<?> aUnit = (AbstractUnit<?>) unit; 158 aUnit.setName(name); 159 units.add(aUnit); 160 return (U) aUnit; 161 } 162 units.add(unit); 163 return unit; 164 } 165 166 /** 167 * Adds a new named unit to the collection. 168 * 169 * @param unit 170 * the unit being added. 171 * @param name 172 * the name of the unit. 173 * @param name 174 * the symbol of the unit. 175 * @param style 176 * style of the unit. 177 * @return <code>unit</code>. 178 * @since 1.0.1 179 */ 180 @SuppressWarnings("unchecked") 181 public static <U extends Unit<?>> U addUnit(Set<Unit<?>> units, U unit, final String name, final String symbol, 182 UnitStyle style) { 183 switch (style) { 184 case NAME: 185 case SYMBOL: 186 case SYMBOL_AND_LABEL: 187 if (name != null && symbol != null && unit instanceof AbstractUnit) { 188 AbstractUnit<?> aUnit = (AbstractUnit<?>) unit; 189 aUnit.setName(name); 190 if (SYMBOL.equals(style) || SYMBOL_AND_LABEL.equals(style)) { 191 aUnit.setSymbol(symbol); 192 } 193 if (LABEL.equals(style) || SYMBOL_AND_LABEL.equals(style)) { 194 SimpleUnitFormat.getInstance().label(unit, symbol); 195 } 196 units.add(aUnit); 197 return (U) aUnit; 198 } 199 if (name != null && unit instanceof AbstractUnit) { 200 AbstractUnit<?> aUnit = (AbstractUnit<?>) unit; 201 aUnit.setName(name); 202 units.add(aUnit); 203 return (U) aUnit; 204 } 205 break; 206 default: 207 if (logger.isLoggable(Level.FINEST)) { 208 logger.log(Level.FINEST, 209 "Unknown style " + style + "; unit " + unit + " can't be rendered with '" + symbol + "'."); 210 } 211 break; 212 } 213 if (LABEL.equals(style) || SYMBOL_AND_LABEL.equals(style)) { 214 SimpleUnitFormat.getInstance().label(unit, symbol); 215 } 216 units.add(unit); 217 return unit; 218 } 219 220 /** 221 * Adds a new labeled unit to the set. 222 * 223 * @param units 224 * the set to add to. 225 * 226 * @param unit 227 * the unit being added. 228 * @param text 229 * the text for the unit. 230 * @param style 231 * style of the unit. 232 * @return <code>unit</code>. 233 * @since 1.0.1 234 */ 235 @SuppressWarnings("unchecked") 236 public static <U extends Unit<?>> U addUnit(Set<Unit<?>> units, U unit, String text, UnitStyle style) { 237 switch (style) { 238 case NAME: 239 if (text != null && unit instanceof AbstractUnit) { 240 AbstractUnit<?> aUnit = (AbstractUnit<?>) unit; 241 aUnit.setName(text); 242 units.add(aUnit); 243 return (U) aUnit; 244 } 245 break; 246 case SYMBOL: 247 if (text != null && unit instanceof AbstractUnit) { 248 AbstractUnit<?> aUnit = (AbstractUnit<?>) unit; 249 aUnit.setSymbol(text); 250 units.add(aUnit); 251 return (U) aUnit; 252 } 253 break; 254 case SYMBOL_AND_LABEL: 255 if (text != null && unit instanceof AbstractUnit) { 256 AbstractUnit<?> aUnit = (AbstractUnit<?>) unit; 257 aUnit.setSymbol(text); 258 units.add(aUnit); 259 SimpleUnitFormat.getInstance().label(aUnit, text); 260 return (U) aUnit; 261 } else { // label in any case, returning below 262 SimpleUnitFormat.getInstance().label(unit, text); 263 } 264 break; 265 case LABEL: 266 SimpleUnitFormat.getInstance().label(unit, text); 267 break; 268 default: 269 logger.log(Level.FINEST, 270 "Unknown style " + style + "; unit " + unit + " can't be rendered with '" + text + "'."); 271 break; 272 } 273 units.add(unit); 274 return unit; 275 } 276 } 277}