001/* 002 * Units of Measurement Reference Implementation 003 * Copyright (c) 2005-2021, 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.format; 031 032import java.io.IOException; 033import java.text.FieldPosition; 034import java.text.Format; 035import java.text.ParsePosition; 036 037import javax.measure.MeasurementException; 038import javax.measure.Quantity; 039import javax.measure.Unit; 040import javax.measure.format.MeasurementParseException; 041import javax.measure.format.QuantityFormat; 042import tech.units.indriya.ComparableQuantity; 043import tech.units.indriya.quantity.CompoundQuantity; 044import tech.units.indriya.quantity.MixedQuantity; 045import tech.uom.lib.common.function.Parser; 046 047/** 048 * <p> 049 * This class provides the interface for formatting and parsing {@link Quantity quantities}. 050 * </p> 051 * 052 * @author <a href="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a> 053 * @author <a href="mailto:werner@units.tech">Werner Keil</a> 054 * @version 2.0, $Date: 2020-02-23 $ 055 * @since 1.0 056 * 057 */ 058@SuppressWarnings("rawtypes") 059public abstract class AbstractQuantityFormat extends Format implements QuantityFormat, Parser<CharSequence, Quantity> { 060 /** 061 * The default delimiter. 062 */ 063 protected static final String DEFAULT_DELIMITER = " "; 064 065 /** 066 * 067 */ 068 private static final long serialVersionUID = -4628006924354248662L; 069 070 /** 071 * Formats the specified quantity into an <code>Appendable</code>. 072 * 073 * @param quantity 074 * the quantity to format. 075 * @param dest 076 * the appendable destination. 077 * @return the specified <code>Appendable</code>. 078 * @throws IOException 079 * if an I/O exception occurs. 080 */ 081 public abstract Appendable format(Quantity<?> quantity, Appendable dest) throws IOException; 082 083 /** 084 * Parses a portion of the specified <code>CharSequence</code> from the specified position to produce an object. If parsing succeeds, then the 085 * index of the <code>cursor</code> argument is updated to the index after the last character used. 086 * 087 * @param csq 088 * the <code>CharSequence</code> to parse. 089 * @param cursor 090 * the cursor holding the current parsing index. 091 * @return the object parsed from the specified character sub-sequence. 092 * @throws IllegalArgumentException 093 * if any problem occurs while parsing the specified character sequence (e.g. illegal syntax). 094 */ 095 public abstract Quantity<?> parse(CharSequence csq, ParsePosition cursor) throws IllegalArgumentException, MeasurementParseException; 096 097 /** 098 * Parses a portion of the specified <code>CharSequence</code> from the specified position to produce an object. If parsing succeeds, then the 099 * index of the <code>cursor</code> argument is updated to the index after the last character used. 100 * 101 * @param csq 102 * the <code>CharSequence</code> to parse. 103 * @return the object parsed from the specified character sub-sequence. 104 * @throws IllegalArgumentException 105 * if any problem occurs while parsing the specified character sequence (e.g. illegal syntax). 106 */ 107 @Override 108 public abstract Quantity<?> parse(CharSequence csq) throws MeasurementParseException; 109 110 /** 111 * Parses a portion of the specified <code>CharSequence</code> from the specified position to produce an object. If parsing succeeds, then the 112 * index of the <code>cursor</code> argument is updated to the index after the last character used. 113 * 114 * @param csq 115 * the <code>CharSequence</code> to parse. 116 * @param index 117 * the current parsing index. 118 * @return the object parsed from the specified character sub-sequence. 119 * @throws IllegalArgumentException 120 * if any problem occurs while parsing the specified character sequence (e.g. illegal syntax). 121 */ 122 protected abstract Quantity<?> parse(CharSequence csq, int index) throws IllegalArgumentException, MeasurementParseException; 123 124 @Override 125 public final StringBuffer format(Object obj, final StringBuffer toAppendTo, FieldPosition pos) { 126 if (obj instanceof MixedQuantity<?>) { 127 return formatMixed((MixedQuantity<?>) obj, toAppendTo); 128 } else if(obj instanceof CompoundQuantity<?>) { // TODO remove with next release 129 return formatCompound((CompoundQuantity<?>) obj, toAppendTo); 130 } else { 131 if (!(obj instanceof ComparableQuantity<?>)) 132 throw new IllegalArgumentException("obj: Not an instance of Quantity"); 133 if ((toAppendTo == null) || (pos == null)) 134 throw new NullPointerException(); 135 return (StringBuffer) format((ComparableQuantity<?>) obj, toAppendTo); 136 } 137 } 138 139 @Override 140 public final Quantity<?> parseObject(String source, ParsePosition pos) { 141 try { 142 return parse(source, pos); 143 } catch (IllegalArgumentException | MeasurementParseException e) { 144 return null; 145 } 146 } 147 148 /** 149 * Formats an object to produce a string. This is equivalent to <blockquote> {@link #format(Unit, StringBuilder) format}<code>(unit, 150 * new StringBuilder()).toString();</code> </blockquote> 151 * 152 * @param quantity 153 * The quantity to format 154 * @return Formatted string. 155 */ 156 public final String format(Quantity<?> quantity) { 157 if (quantity instanceof ComparableQuantity) return format((ComparableQuantity<?>) quantity, new StringBuffer()).toString(); 158 159 try { 160 return (this.format(quantity, new StringBuffer())).toString(); 161 } catch (IOException ex) { 162 throw new MeasurementException(ex); // Should never happen. 163 } 164 } 165 166 /** 167 * Convenience method equivalent to {@link #format(ComparableQuantity, Appendable)} except it does not raise an IOException. 168 * 169 * @param quantity 170 * the quantity to format. 171 * @param dest 172 * the appendable destination. 173 * @return the specified <code>StringBuilder</code>. 174 */ 175 protected final StringBuffer format(ComparableQuantity<?> quantity, StringBuffer dest) { 176 try { 177 return (StringBuffer) this.format(quantity, (Appendable) dest); 178 } catch (IOException ex) { 179 throw new MeasurementException(ex); // Should not happen. 180 } 181 } 182 183 /** 184 * Convenience method equivalent to {@link #format(MixedQuantity, Appendable)} except it does not raise an IOException. 185 * 186 * @param mixed 187 * the mixed quantity to format. 188 * @param dest 189 * the appendable destination. 190 * @return the specified <code>StringBuilder</code>. 191 */ 192 protected abstract StringBuffer formatMixed(MixedQuantity<?> mixed, StringBuffer dest); 193 194 195 /** 196 * Convenience method equivalent to {@link #format(CompoundQuantity, Appendable)} except it does not raise an IOException. 197 * 198 * @param comp 199 * the composite quantity to format. 200 * @param dest 201 * the appendable destination. 202 * @return the specified <code>StringBuilder</code>. 203 * @deprecated use #formatMixed 204 */ 205 protected abstract StringBuffer formatCompound(CompoundQuantity<?> comp, StringBuffer dest); 206}