/* * Copyright 1998, University Corporation for Atmospheric Research * See file LICENSE for copying and redistribution conditions. * * $Id: UnitTable.java,v 1.6 2009-04-21 20:15:10 steve Exp $ */ package visad.data.units; import java.util.Collections; import java.util.Comparator; import java.util.Enumeration; import java.util.Hashtable; import java.util.Iterator; import java.util.SortedSet; import java.util.TreeSet; import visad.BaseUnit; import visad.DerivedUnit; import visad.OffsetUnit; import visad.SI; import visad.ScaledUnit; import visad.Unit; /** * Provides support for a table of units. * * @author Steven R. Emmerson */ public class UnitTable implements UnitsDB, java.io.Serializable { private static final long serialVersionUID = 1L; /** * Name-to-unit map. * @serial */ private final Hashtable nameMap; /** * Symbol-to-unit map. * @serial */ private final Hashtable symbolMap; /** * The unit set. * @serial */ private final SortedSet unitSet; /** * Construct. * * @param numNames Anticipated minimum number of names in the * database. * @throws IllegalArgumentException <code>numNames < 0</code>. */ public UnitTable(int numNames) throws IllegalArgumentException { this(numNames, 0); } /** * Construct. * * @param numNames Anticipated minimum number of names in the * database. * @param numSymbols Anticipated minimum number of symbols in the * database. * @throws IllegalArgumentException <code>numNames < 0 || numSymbols < 0 * </code>. */ public UnitTable(int numNames, int numSymbols) throws IllegalArgumentException { if (numNames < 0 || numSymbols < 0) throw new IllegalArgumentException("Negative hashtable size"); nameMap = new Hashtable(numNames); symbolMap = new Hashtable(numSymbols); unitSet = Collections.synchronizedSortedSet( new TreeSet( new Comparator() { public int compare(Object o1, Object o2) { return ((Unit)o1).toString().compareToIgnoreCase( ((Unit)o2).toString()); } })); } /** * Get a unit. * * @param name The exact name of the unit to be retrieved. If it is * the empty string, then the dimensionless, unity * unit * will be returned. * @return The unit of the matching entry or null if not found. * @require <code>name</code> is non-null. */ public Unit get(String name) { Unit unit = null; // default if (name.length() == 0) { // Return a unity, dimensionless unit. unit = new DerivedUnit(); } else { /* * Try the symbol table first because symbols are case-sensitive. */ unit = getBySymbol(name); if (unit == null) unit = getByName(name); } return unit; } /** * Get a unit by name. * * @param name The name of the unit to be retrieved. If it is * the empty string, then the dimensionless, unity * unit * will be returned. * @return The unit of the matching entry or null if not found. * @require <code>name</code> is non-null. */ protected Unit getByName(String name) { return (Unit)nameMap.get(name.toLowerCase()); } /** * Get a unit by symbol. * * @param symbol The exact symbol of the unit to be retrieved. If it is * the empty string, then the dimensionless, unity * unit * will be returned. * @return The unit of the matching entry or null if not found. * @require <code>name</code> is non-null. */ protected Unit getBySymbol(String symbol) { return (Unit)symbolMap.get(symbol); } /** * Adds a base unit. * * @param unit The base unit to be added. * @throws IllegalArgumentException * The base unit argument is invalid. */ public void put(BaseUnit unit) throws IllegalArgumentException { String name = unit.unitName(); putName(name, unit); putName(makePlural(name), unit); putSymbol(unit.unitSymbol(), unit); } /** * Returns the plural form of a name. Regular rules are used to generate * the plural form. * @param name The name. * @return The plural form of the name. */ protected String makePlural(String name) { String plural; int length = name.length(); char lastChar = name.charAt(length-1); if (lastChar != 'y') { plural = name + (lastChar == 's' || lastChar == 'x' || lastChar == 'z' || name.endsWith("ch") ? "es" : "s"); } else { if (length == 1) { plural = name + "s"; } else { char penultimateChar = name.charAt(length-2); plural = (penultimateChar == 'a' || penultimateChar == 'e' || penultimateChar == 'i' || penultimateChar == 'o' || penultimateChar == 'u') ? name + "s" : name.substring(0, length-1) + "ies"; } } return plural; } /** * Adds a name and a unit to the name table. * @param name The name to be added. * @param unit The unit to be added. * @throws IllegalArgumentException Invalid argument. */ public void putName(String name, Unit unit) { if (name == null) throw new IllegalArgumentException(this.getClass().getName() + ".putName(String,Unit): <null> unit name"); if (unit == null) throw new IllegalArgumentException(this.getClass().getName() + ".putName(String,Unit): <null> unit"); name = name.toLowerCase(); String[] names = (name.indexOf(' ') == -1 && name.indexOf('_') == -1) ? new String[] {name} : new String[] { name.replace('_', ' '), name.replace(' ', '_')}; for (int i = 0; i < names.length; i++) { Unit prevUnit = (Unit)nameMap.get(names[i]); if (prevUnit != null && !prevUnit.equals(unit)) throw new IllegalArgumentException( "Attempt to replace unit \"" + prevUnit + " with unit \"" + unit + '"'); nameMap.put(names[i], unit); } unitSet.add(unit); } /** * Adds a symbol and a unit to the symbol table. * @param symbol The symbol to be added. * @param unit The unit to be added. * @throws IllegalArgumentException Invalid argument. */ public void putSymbol(String symbol, Unit unit) { if (symbol == null) throw new IllegalArgumentException(this.getClass().getName() + ".putName(String,Unit): <null> unit symbol"); if (unit == null) throw new IllegalArgumentException(this.getClass().getName() + ".putName(String,Unit): <null> unit"); Unit prevUnit = (Unit)symbolMap.get(symbol); if (prevUnit != null && !prevUnit.equals(unit)) throw new IllegalArgumentException( "Attempt to replace unit \"" + prevUnit + " with unit \"" + unit + '"'); symbolMap.put(symbol, unit); unitSet.add(unit); } /** * Get an enumeration of the unit names in the table. The Object returned * by nextElement() is a String. */ public Enumeration getNameEnumeration() { return nameMap.keys(); } /** * Get an enumeration of the unit symbols in the table. The Object returned * by nextElement() is a String. */ public Enumeration getSymbolEnumeration() { return symbolMap.keys(); } /** * Get an enumeration of the units in the table. The Object returned * by nextElement() is a Unit. */ public Enumeration getUnitEnumeration() { return new Enumeration() { private final Iterator iter = unitSet.iterator(); public boolean hasMoreElements() { return iter.hasNext(); } public Object nextElement() { return iter.next(); } }; } /** * Return a string representation of this instance. */ public String toString() { return nameMap.toString() + symbolMap.toString(); } /** * Test this class. * @exception java.lang.Exception A problem occurred. */ public static void main(String[] args) throws Exception { UnitTable db = new UnitTable(13); db.put(SI.ampere); db.put(SI.candela); db.put(SI.kelvin); db.put(SI.kilogram); db.put(SI.meter); db.put(SI.mole); db.put(SI.second); db.put(SI.radian); db.putName("amp", SI.ampere); // alias db.putName("celsius", new OffsetUnit(273.15, SI.kelvin)); db.putName("newton", SI.kilogram.multiply(SI.meter).divide(SI.second.pow(2))); db.putName("rankine", new ScaledUnit(1/1.8, SI.kelvin)); db.putName("fahrenheit", new OffsetUnit(459.67, (ScaledUnit)db.get("rankine"))); System.out.println("db:"); System.out.println(db.toString()); } /** * List the units in the database. */ public void list() { Enumeration en = getUnitEnumeration(); while (en.hasMoreElements()) { Unit unit = (Unit)en.nextElement(); System.out.println(unit.getIdentifier() + " = " + unit.getDefinition()); } } }