/*
* Copyright 1998-2014 University Corporation for Atmospheric Research/Unidata
*
* Portions of this software were developed by the Unidata Program at the
* University Corporation for Atmospheric Research.
*
* Access and use of this software shall impose the following obligations
* and understandings on the user. The user is granted the right, without
* any fee or cost, to use, copy, modify, alter, enhance and distribute
* this software, and any derivative works thereof, and its supporting
* documentation for any purpose whatsoever, provided that this entire
* notice appears in all copies of the software, derivative works and
* supporting documentation. Further, UCAR requests that the user credit
* UCAR/Unidata in any publications that result from the use of this
* software or in any product that includes this software. The names UCAR
* and/or Unidata, however, may not be used in any advertising or publicity
* to endorse or promote any products or commercial entity unless specific
* written permission is obtained from UCAR/Unidata. The user also
* understands that UCAR/Unidata is not obligated to provide the user with
* any support, consulting, training or assistance of any kind with regard
* to the use, operation and performance of this software nor to provide
* the user with any updates, revisions, new versions or "bug fixes."
*
* THIS SOFTWARE IS PROVIDED BY UCAR/UNIDATA "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL UCAR/UNIDATA BE LIABLE FOR ANY SPECIAL,
* INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
* FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
* WITH THE ACCESS, USE OR PERFORMANCE OF THIS SOFTWARE.
*/
package ucar.units;
import net.jcip.annotations.Immutable;
import java.util.SortedMap;
import java.util.TreeMap;
/**
* Provides support for base units.
*
* @author Steven R. Emmerson
*/
@Immutable
public class BaseUnit extends DerivedUnitImpl implements Base {
private static final long serialVersionUID = 1L;
/**
* The identifier-to-unit map.
*
* @serial
*/
private static final SortedMap<UnitName, BaseUnit> nameMap = new TreeMap<>();
/**
* The quantity-to-unit map.
*
* @serial
*/
private static final SortedMap<BaseQuantity, BaseUnit> quantityMap = new TreeMap<>();
/**
* The base quantity associated with this base unit.
*
* @serial
*/
private final BaseQuantity baseQuantity;
/**
* Constructs from identifiers and a base quantity.
*
* @param id
* The identifiers for the base unit. <code>
* id.getSymbol()</code>
* shall not return <code>
* null</code>.
* @param baseQuantity
* The base quantity of the base unit.
* @throws NameException
* <code>id.getSymbol()</code> returned <code>
* null</code>.
*/
protected BaseUnit(final UnitName id, final BaseQuantity baseQuantity)
throws NameException {
super(id);
if (id.getSymbol() == null) {
throw new NameException("Base unit must have symbol");
}
setDimension(new UnitDimension(this));
this.baseQuantity = baseQuantity;
}
/**
* Factory method for creating a new BaseUnit or obtaining a
* previously-created one.
*
* @param id
* The identifier for the base unit. <code>
* id.getSymbol()</code>
* shall not return <code>
* null</code>.
* @param baseQuantity
* The base quantity of the base unit.
* @throws NameException
* <code>id.getSymbol()</code> returned <code>
* null</code>.
* @throws UnitExistsException
* Attempt to incompatibly redefine an existing base unit.
*/
public static synchronized BaseUnit getOrCreate(final UnitName id,
final BaseQuantity baseQuantity) throws NameException,
UnitExistsException {
BaseUnit baseUnit;
final BaseUnit nameUnit = nameMap.get(id);
final BaseUnit quantityUnit = quantityMap.get(baseQuantity);
if (nameUnit != null || quantityUnit != null) {
baseUnit = nameUnit != null
? nameUnit
: quantityUnit;
if ((nameUnit != null && !baseQuantity.equals(nameUnit
.getBaseQuantity()))
|| (quantityUnit != null && !id.equals(quantityUnit
.getUnitName()))) {
throw new UnitExistsException(
"Attempt to incompatibly redefine base unit \""
+ baseUnit + '"');
}
}
else {
baseUnit = new BaseUnit(id, baseQuantity);
quantityMap.put(baseQuantity, baseUnit);
nameMap.put(id, baseUnit);
}
return baseUnit;
}
/**
* Returns the base quantity associated with this base unit.
*
* @return The base quantity associated with this base unit.
*/
public final BaseQuantity getBaseQuantity() {
return baseQuantity;
}
/**
* Returns the identifier for this base unit. This is identical to
* <code>getSymbol()</code>.
*
* @return The identifier for this base unit.
*/
public final String getID() {
return getSymbol();
}
/**
* Returns the string representation of this base unit. This is identical to
* <code>getID()</code>.
*
* @return The string representation of this base unit.
*/
@Override
public final String toString() {
return getID();
}
/**
* Indicates if this base unit is dimensionless.
*
* @return <code>true</code> if and only if this base unit is dimensionless
* (e.g. "radian").
*/
@Override
public boolean isDimensionless() {
return baseQuantity.isDimensionless();
}
/**
* Tests this class.
*/
public static void main(final String[] args) throws Exception {
final BaseUnit meter = new BaseUnit(UnitName.newUnitName("meter", null,
"m"), BaseQuantity.LENGTH);
System.out
.println("meter.getBaseQuantity()=" + meter.getBaseQuantity());
System.out
.println("meter.toDerivedUnit(1.)=" + meter.toDerivedUnit(1.));
System.out.println("meter.toDerivedUnit(new float[] {2})[0]="
+ meter.toDerivedUnit(new float[] { 2 }, new float[1])[0]);
System.out.println("meter.fromDerivedUnit(1.)="
+ meter.fromDerivedUnit(1.));
System.out.println("meter.fromDerivedUnit(new float[] {3})[0]="
+ meter.fromDerivedUnit(new float[] { 3 }, new float[1])[0]);
System.out.println("meter.isCompatible(meter)="
+ meter.isCompatible(meter));
final BaseUnit radian = new BaseUnit(UnitName.newUnitName("radian",
null, "rad"), BaseQuantity.PLANE_ANGLE);
System.out.println("meter.isCompatible(radian)="
+ meter.isCompatible(radian));
System.out
.println("meter.isDimensionless()=" + meter.isDimensionless());
System.out.println("radian.isDimensionless()="
+ radian.isDimensionless());
}
}