All Downloads are FREE. Search and download functionalities are using the official Maven repository.

ucar.units.UnitDBImpl Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 1998-2018 University Corporation for Atmospheric Research/Unidata
 * See LICENSE for license information.
 */
package ucar.units;

import java.io.Serializable;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;

/**
 * Provides most of a concrete implementation of a database of units.
 * 
 * @author Steven R. Emmerson
 */
public class UnitDBImpl implements UnitDB, Serializable {
  private static final long serialVersionUID = 1L;

  /**
   * The set of units.
   * 
   * @serial
   */
  private final Set unitSet;

  /**
   * The name-to-unit map.
   * 
   * @serial
   */
  private final Map nameMap;

  /**
   * The symbol-to-unit map.
   * 
   * @serial
   */
  private final Map symbolMap;

  /**
   * Constructs from the expected number of names and symbols. The sizes will
   * be used to construct the initial database but will not limit its growth.
   * 
   * @param nameCount
   *        The expected number of names (including plurals and aliases).
   * @param symbolCount
   *        The expected number of symbols.
   */
  protected UnitDBImpl(final int nameCount, final int symbolCount) {
    unitSet = new TreeSet<>((obj1, obj2) -> (obj1).getName().compareTo((obj2).getName()));
    nameMap = new Hashtable<>(nameCount + 1);
    symbolMap = new Hashtable<>(symbolCount + 1);
  }

  /**
   * Adds all the entries in another UnitDBImpl to this database.
   * 
   * @param that
   *        The other UnitDBImpl.
   * @throws UnitExistsException
   *         Attempt to redefine an existing entry.
   */
  public void add(final UnitDBImpl that) throws UnitExistsException {
    unitSet.addAll(that.unitSet);
    nameMap.putAll(that.nameMap);
    symbolMap.putAll(that.symbolMap);
  }

  /**
   * Return the number of names in this database
   * 
   * @return The total number of names, plurals, and aliases.
   */
  public int nameCount() {
    return nameMap.size();
  }

  /**
   * Return the number of symbols in this database.
   * 
   * @return The number of symbols in this database.
   */
  public int symbolCount() {
    return symbolMap.size();
  }

  /**
   * Adds a unit to the database.
   * 
   * @param unit
   *        The unit to be added.
   * @throws UnitExistsException
   *         Another unit with the same name or symbol already exists in
   *         the database.
   * @throws NameException
   *         Bad unit name.
   */
  public void addUnit(final Unit unit) throws UnitExistsException, NameException {
    if (unit.getName() == null) {
      throw new NameException("Unit name can't be null");
    }
    addByName(unit.getName(), unit);
    addByName(unit.getPlural(), unit);
    addBySymbol(unit.getSymbol(), unit);
    unitSet.add(unit);
  }

  /**
   * Adds an alias for a unit already in the database.
   * 
   * @param alias
   *        An alias for the unit.
   * @param name
   *        The name of the unit already in the database.
   * @throws UnitExistsException
   *         Another unit with the same name or symbol already exists in
   *         the database.
   * @throws NoSuchUnitException
   *         The unit isn't in the database.
   */
  public final void addAlias(final String alias, final String name) throws NoSuchUnitException, UnitExistsException {
    addAlias(alias, name, null);
  }

  /**
   * Adds an alias for a unit already in the database.
   * 
   * @param alias
   *        An alias for the unit.
   * @param name
   *        The name of the unit already in the database.
   * @param symbol
   *        The symbol for the unit.
   * @throws UnitExistsException
   *         Another unit with the same name or symbol already exists in
   *         the database.
   * @throws NoSuchUnitException
   *         The unit isn't in the database.
   */
  public final void addAlias(final String alias, final String name, final String symbol)
      throws NoSuchUnitException, UnitExistsException {
    addAlias(alias, name, symbol, null);
  }

  /**
   * Adds a symbol for a unit already in the database.
   * 
   * @param symbol
   *        The symbol for the unit.
   * @param name
   *        The name of the unit already in the database.
   * @throws UnitExistsException
   *         Another unit with the same name or symbol already exists in
   *         the database.
   * @throws NoSuchUnitException
   *         The unit isn't in the database.
   */
  public final void addSymbol(final String symbol, final String name) throws NoSuchUnitException, UnitExistsException {
    addAlias(null, name, symbol, null);
  }

  /**
   * Adds an alias for a unit already in the database.
   * 
   * @param alias
   *        The alias to be added to the database. May be null.
   * @param name
   *        The name of the unit to have an alias added to the database.
   * @param symbol
   *        The symbol to be added. May be null.
   * @param plural
   *        The plural form of the alias. If null
   *        , then regular
   *        plural-forming rules are followed.
   * @throws NoSuchUnitException
   *         The unit is not in the database.
   * @throws UnitExistsException
   *         Another unit with the same alias is already in the database.
   */
  public final void addAlias(final String alias, final String name, final String symbol, final String plural)
      throws NoSuchUnitException, UnitExistsException {
    addAlias(UnitID.newUnitID(alias, plural, symbol), name);
  }

  /**
   * Adds an alias for a unit already in the database.
   * 
   * @param alias
   *        The alias to be added to the database.
   * @param name
   *        The name of the unit to have an alias added to the database.
   * @throws NoSuchUnitException
   *         The unit is not in the database.
   * @throws UnitExistsException
   *         Another unit with the same alias is already in the database.
   */
  public final void addAlias(final UnitID alias, final String name) throws NoSuchUnitException, UnitExistsException {
    final Unit unit = getByName(name);
    if (unit == null) {
      throw new NoSuchUnitException(name);
    }
    addByName(alias.getName(), unit);
    addByName(alias.getPlural(), unit);
    addBySymbol(alias.getSymbol(), unit);
  }

  /**
   * Gets a unit by either name, plural, or symbol. Retrieving the unit by
   * symbol is attempted before retrieving the unit by name because symbol
   * comparisons are case sensitive and, hence, should be more robust.
   * 
   * @param id
   *        The id to be matched.
   * @return The unit whose name, plural, or symbol matches or
   *         null if no such unit was found.
   */
  public Unit get(final String id) {
    Unit unit = getBySymbol(id);
    if (unit == null) {
      unit = getByName(id);
    }
    return unit;
  }

  /**
   * Gets a unit by name.
   * 
   * @param name
   *        The name to be matched.
   * @return The unit whose name, plural, or alias matches or
   *         null if no such unit was found.
   */
  public Unit getByName(final String name) {
    return nameMap.get(canonicalize(name));
  }

  /**
   * Returns the canonical form of a unit name.
   * 
   * @param name
   *        A unit name.
   * @return The canonical form of the name.
   */
  private static String canonicalize(final String name) {
    return name.toLowerCase().replace(' ', '_');
  }

  /**
   * Gets a unit by symbol.
   * 
   * @param symbol
   *        The symbol to be matched.
   * @return The unit whose symbol matches or null
   *         if no such unit was
   *         found.
   */
  public Unit getBySymbol(final String symbol) {
    return symbolMap.get(symbol);
  }

  /**
   * Returns the string representation of this database.
   * 
   * @return The string representation of this database.
   */
  @Override
  public String toString() {
    return unitSet.toString();
  }

  /**
   * Gets an iterator over the units in the database.
   * 
   * @return An iterator over the units in the database. The iterator's
   *         next() method returns objects of type
   *         Unit.
   */
  public final Iterator getIterator() {
    return unitSet.iterator();
  }

  /**
   * Adds a unit to the database by name.
   * 
   * @param name
   *        The name of the unit. If null then the unit is
   *        not added.
   * @param newUnit
   *        The unit to be added.
   * @throws UnitExistsException
   *         Attempt to redefine an existing unit.
   */
  private void addByName(final String name, final Unit newUnit) throws UnitExistsException {
    if (name != null) {
      addUnique(nameMap, canonicalize(name), newUnit);
    }
  }

  /**
   * Adds a unit to the database by symbol.
   * 
   * @param symbol
   *        The symbol for the unit. If null then the unit is
   *        not added.
   * @param newUnit
   *        The unit to be added.
   * @throws UnitExistsException
   *         Attempt to redefine an existing unit.
   */
  private void addBySymbol(final String symbol, final Unit newUnit) throws UnitExistsException {
    if (symbol != null) {
      addUnique(symbolMap, symbol, newUnit);
    }
  }

  /**
   * Adds a unique unit to a map..
   * 
   * @param map
   *        The map to be added to.
   * @param key
   *        The key for the unit entry.
   * @param newUnit
   *        The unit to be added.
   * @throws UnitExistsException
   *         Attempt to redefine an existing unit.
   */
  private static void addUnique(final Map map, final String key, final Unit newUnit)
      throws UnitExistsException {
    final Unit oldUnit = map.put(key, newUnit);
    if (oldUnit != null && !oldUnit.equals(newUnit)) {
      throw new UnitExistsException(oldUnit, newUnit);
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy