001/* 002 * Units of Measurement Enum Implementation 003 * Copyright © 2005-2021, Werner Keil and others. 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, Unit-API 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.uom.impl.enums.format; 031 032import java.io.IOException; 033import java.text.ParsePosition; 034import java.util.HashMap; 035import java.util.Map; 036 037import javax.measure.Unit; 038import javax.measure.format.MeasurementParseException; 039import javax.measure.format.UnitFormat; 040 041import tech.uom.impl.enums.unit.MixedUnit; 042import tech.uom.impl.enums.unit.DimensionlessUnit; 043import tech.uom.impl.enums.unit.DistanceUnit; 044 045/** 046 * <p> 047 * This class provides a simple interface for formatting and parsing {@linkplain javax.measure.Unit units}. 048 * </p> 049 * 050 * @author <a href="mailto:werner@units.tech">Werner Keil</a> 051 * @version 2.0, $Date: 2020-12-06 $ 052 */ 053public class SimpleUnitFormat extends AbstractUnitFormat { 054 /** 055 * 056 */ 057 // private static final long serialVersionUID = -7753687108842507677L; 058 059 private final Map<String, String> symbolMap = new HashMap<String, String>(); // Diamond (Java 7+) 060 /** 061 * Holds the unique symbols collection. 062 */ 063 private static final Map<String, Unit<?>> unitMap = new HashMap<>(); 064 065 private static final UnitFormat DEFAULT = new SimpleUnitFormat(); 066 067 // ///////////////// 068 // Class methods // 069 // ///////////////// 070 /** Returns the default instance for formatting */ 071 public static UnitFormat getInstance() { 072 return DEFAULT; 073 } 074 075 // //////////////// 076 // Constructors // 077 // //////////////// 078 /** 079 * Base constructor. 080 */ 081 SimpleUnitFormat() { 082 unitMap.put("m", DistanceUnit.METRE); 083 } 084 085 // ////////////// 086 // Formatting // 087 // ////////////// 088 public Appendable format(Unit<?> unit, Appendable appendable) throws IOException { 089 // Mixed unit. 090 if (unit instanceof MixedUnit) { 091 MixedUnit<?> cpdUnit = (MixedUnit<?>) unit; 092 final StringBuilder mixable = new StringBuilder(); 093 mixable.append(cpdUnit.getUpper().getSymbol()); 094 mixable.append(":"); // FIXME we need a more flexible pattern here 095 mixable.append(cpdUnit.getLower().getSymbol()); 096 return mixable; 097 } else { 098 CharSequence symbol; 099 100 @SuppressWarnings("unlikely-arg-type") 101 String mapSymbol = symbolMap.get(unit); 102 if (mapSymbol != null) { 103 symbol = mapSymbol; 104 } else { 105 throw new IllegalArgumentException("Symbol mapping for unit of type " + //$NON-NLS-1$ 106 unit.getClass().getName() + " has not been set " + //$NON-NLS-1$ 107 "(see UnitFormat.SymbolMap)"); //$NON-NLS-1$ 108 } 109 110 appendable.append(symbol); 111 112 return appendable; 113 } 114 } 115 116 public void label(Unit<?> unit, String label) { 117 // do nothing 118 } 119 120 public boolean isLocaleSensitive() { 121 return false; 122 } 123 124 protected Unit<?> parse(CharSequence csq, int index) throws MeasurementParseException { 125 // Parsing reads the whole character sequence from the parse position. 126 int start = index; // cursor != null ? cursor.getIndex() : 0; 127 int end = csq.length(); 128 if (end <= start) { 129 return DimensionlessUnit.ONE; 130 } 131 final Unit<?> result = unitMap.get(csq); 132 if (result != null) { 133 return result; 134 } 135 throw new MeasurementParseException("Error", csq, index); 136 } 137 138 /** 139 * Parses the specified character sequence to produce a unit (convenience method). If the specified sequence is empty, the unitary unit 140 * (dimensionless) is returned. 141 * 142 * @param csq 143 * the <code>CharSequence</code> to parse. 144 * @return the unit parsed from the specified character sub-sequence. 145 * @throws MeasurementParseException 146 * if any problem occurs while parsing the specified character sequence (e.g. illegal syntax). 147 */ 148 public final Unit<?> parse(CharSequence csq, ParsePosition pos) throws MeasurementParseException { 149 return parse(csq, pos.getIndex()); 150 } 151}