001/* 002 * Units of Measurement Reference Implementation 003 * Copyright (c) 2005-2023, 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 static tech.units.indriya.format.FormatBehavior.LOCALE_SENSITIVE; 033 034import java.text.NumberFormat; 035import java.util.HashMap; 036import java.util.Locale; 037import java.util.Map; 038import java.util.Objects; 039import java.util.Set; 040 041import javax.measure.format.QuantityFormat; 042import javax.measure.format.UnitFormat; 043import javax.measure.spi.FormatService; 044 045import tech.units.indriya.format.SimpleUnitFormat.Flavor; 046import tech.uom.lib.common.function.IntPrioritySupplier; 047 048/** 049 * Default format service. 050 * 051 * @author Werner Keil 052 * @version 2.3, November 26, 2020 053 * @since 2.0 054 */ 055public class DefaultFormatService implements FormatService, IntPrioritySupplier { 056 private static final int PRIO = 1000; 057 058 private static final String SIMPLE_KEY = "SIMPLE"; 059 private static final String EBNF_KEY = "EBNF"; 060 private static final String LOCAL_KEY = "LOCAL"; 061 062 private static final String DEFAULT_QUANTITY_FORMAT_NAME = SIMPLE_KEY; 063 064 private static final String DEFAULT_UNIT_FORMAT_NAME = SIMPLE_KEY + "_DEFAULT"; 065 private static final String ASCII_UNIT_FORMAT_NAME = SIMPLE_KEY + "_ASCII"; 066 067 private final Map<String, QuantityFormat> quantityFormats = new HashMap<>(); 068 private final Map<String, UnitFormat> unitFormats = new HashMap<>(); 069 070 private final Map<String, String> unitFormatAliases = new HashMap<>(); 071 private final Map<String, String> quantityFormatAliases = new HashMap<>(); 072 073 /** 074 * Holds the default format instance (EBNFUnitFormat). 075 */ 076 private static final NumberDelimiterQuantityFormat EBNF_QUANTITY_FORMAT = new NumberDelimiterQuantityFormat.Builder() 077 .setNumberFormat(NumberFormat.getInstance(Locale.ROOT)).setUnitFormat(EBNFUnitFormat.getInstance()).build(); 078 079 public DefaultFormatService() { 080 unitFormats.put(DEFAULT_UNIT_FORMAT_NAME, SimpleUnitFormat.getInstance()); 081 unitFormats.put(ASCII_UNIT_FORMAT_NAME, SimpleUnitFormat.getInstance(Flavor.ASCII)); 082 unitFormats.put(EBNF_KEY, EBNFUnitFormat.getInstance()); 083 unitFormats.put(LOCAL_KEY, LocalUnitFormat.getInstance()); 084 085 unitFormatAliases.put("DEFAULT", DEFAULT_UNIT_FORMAT_NAME); 086 unitFormatAliases.put("ASCII", ASCII_UNIT_FORMAT_NAME); 087 088 quantityFormats.put(DEFAULT_QUANTITY_FORMAT_NAME, SimpleQuantityFormat.getInstance()); 089 quantityFormats.put("NUMBERDELIMITER", NumberDelimiterQuantityFormat.getInstance()); 090 quantityFormats.put(EBNF_KEY, EBNF_QUANTITY_FORMAT); 091 quantityFormats.put(LOCAL_KEY, NumberDelimiterQuantityFormat.getInstance(LOCALE_SENSITIVE)); 092 093 quantityFormatAliases.put("NUMBERSPACE", "NUMBERDELIMITER"); 094 } 095 096 @Override 097 public QuantityFormat getQuantityFormat(String key) { 098 Objects.requireNonNull(key, "Format name or alias required"); 099 String alias = quantityFormatAliases.get(key.toUpperCase()); 100 if (alias != null && alias.length() > 0) { 101 return quantityFormats.get(alias.toUpperCase()); 102 } 103 return quantityFormats.get(key.toUpperCase()); 104 } 105 106 @Override 107 public QuantityFormat getQuantityFormat() { 108 return getQuantityFormat(DEFAULT_QUANTITY_FORMAT_NAME); 109 } 110 111 @Override 112 public Set<String> getAvailableFormatNames(FormatType type) { 113 switch (type) { 114 case QUANTITY_FORMAT: 115 return quantityFormats.keySet(); 116 default: 117 return unitFormats.keySet(); 118 } 119 } 120 121 /* 122 * (non-Javadoc) 123 * 124 * @see UnitFormatService#getUnitFormat(String) 125 */ 126 @Override 127 public UnitFormat getUnitFormat(String key) { 128 Objects.requireNonNull(key, "Format name or alias required"); 129 String alias = unitFormatAliases.get(key.toUpperCase()); 130 if (alias != null && alias.length() > 0) { 131 return unitFormats.get(alias); 132 } 133 return unitFormats.get(key.toUpperCase()); 134 } 135 136 /* 137 * (non-Javadoc) 138 * 139 * @see UnitFormatService#getUnitFormat() 140 */ 141 @Override 142 public UnitFormat getUnitFormat() { 143 return getUnitFormat(DEFAULT_UNIT_FORMAT_NAME); 144 } 145 146 @Override 147 public UnitFormat getUnitFormat(String name, String variant) { 148 final StringBuilder sb = new StringBuilder(name); 149 if (null != variant && !variant.isEmpty()) { 150 sb.append("_"); 151 sb.append(variant); 152 } 153 return getUnitFormat(sb.toString()); 154 } 155 156 @Override 157 public int getPriority() { 158 return PRIO; 159 } 160}