//
// ScalarType.java
//
/*
VisAD system for interactive analysis and visualization of numerical
data. Copyright (C) 1996 - 2017 Bill Hibbard, Curtis Rueden, Tom
Rink, Dave Glowacki, Steve Emmerson, Tom Whittaker, Don Murray, and
Tommy Jasmin.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
MA 02111-1307, USA
*/
package visad;
import java.io.InvalidObjectException;
import java.lang.ref.ReferenceQueue;
import java.util.HashMap;
import java.util.Map;
import visad.util.WeakMapValue;
/**
* ScalarType is the superclass of the VisAD hierarchy of scalar data types.
*/
public abstract class ScalarType extends MathType implements Comparable {
// name of scalar type - enforce uniqueness locally
// but do not rely on it - names may be duplicated on remote systems
String Name;
/**
* Hashtable of scalar names used to make sure scalar names are unique
* (within local VM). Because the values in the hashtable are actually {@link
* WeakMapValue}s, the existance of a {@link ScalarType} in the hashtable will
* not prevent it from being garbage-collected when it is no longer strongly
* referenced.
*/
private static Map ScalarHash = new HashMap();
// Aliases for scalar names
private static Map Translations = new HashMap();
private static Map ReverseTranslations = new HashMap();
// Queue that receives garbage-collected ScalarType instances.
private static final ReferenceQueue queue = new ReferenceQueue();
/**
* Create a ScalarType with the specified name.
*
* @param name The name of this ScalarType
*
* @exception VisADException If the name is not valid.
*/
public ScalarType(String name) throws VisADException {
super();
Name = name;
synchronized(getClass()) {
checkQueue();
validateName(name, "name");
ScalarHash.put(name, new WeakMapValue(Name, this, queue));
}
}
/**
* Trusted constructor used to create standard VisAD RealTypes
* without all the name-checking overhead.
*
* @param name Trusted name.
* @param b Dummy value used to indicate that this is a trusted constructor.
*/
ScalarType(String name, boolean b) {
super(b);
Name = name;
synchronized(getClass()) {
checkQueue();
ScalarHash.put(name, new WeakMapValue(Name, this, queue));
}
}
/**
* Compares this object with another of the same type. The comparison is
* on the names.
*
* @param obj The other object of the same type.
* @return A value less than zero, zero, or greater than zero
* depending on whether this object is considered less
* than, equal to, or greater than the other object,
* respectively.
* @throws ClassCastException if the object is not a {@link ScalarType}.
*/
public int compareTo(Object obj) {
return getName().compareTo(((ScalarType)obj).getName());
}
/**
* Indicates if this ScalarType is the same as another object.
*
* @param obj The other object.
* @return true if and only if the other object is a
* ScalarType and compares equal to this ScalarType.
*/
public boolean equals(Object obj) {
return obj instanceof ScalarType && compareTo(obj) == 0;
}
/**
* Obtains the hash code for this object. If
* scalarType1.equals(scalarType2), then
* scalarType1.hashCode() == scalarType2.hashCode().
*
* @return The hash code for this object.
*/
public int hashCode() {
return getName().hashCode();
}
/**
* Change the primary name for this ScalarType.
* The original name can still be used.
* If multiple aliases are created, the last one is dominant.
* This is handy for translating standard VisAD RealType
* names to a language other than English.
*
* @param alias The new name.
*
* @exception TypeException If the new name is not valid.
*/
public void alias(String alias)
throws TypeException
{
synchronized(getClass()) {
if (!Name.equals(Translations.get(alias))) {
validateName(alias, "alias");
Translations.put(alias, Name);
}
ReverseTranslations.put(Name, alias);
}
}
/**
* Returns this ScalarType's name. If an alias exists, then it
* it is returned; otherwise, the name given to the constructor is used.
*
* @return The name of this ScalarType.
*/
public final String getName() {
synchronized(getClass()) {
String alias = (String )ReverseTranslations.get(Name);
if (alias != null) {
return alias;
}
}
return Name;
}
/**
* Returns the original name of this instance. This method ignores any alias
* and returns the name given to the constructor.
*
* @return The original name.
*/
public final String getOriginalName() {
return Name;
}
/**
* Returns the alias of this instance or null if this instance
* has no alias. This method returns the alias set by the most recent
* {@link #alias(String)} invocation.
*
* @return The alias or null.
*/
public final String getAlias() {
synchronized(getClass()) {
return (String)ReverseTranslations.get(Name);
}
}
public String getNameWithBlanks() {
return getName().replace('_', ' ');
}
/**
* Get the ScalarType which has the specified name.
*
* @param name Name of ScalarType.
* @return Either the ScalarType if found,
* or null.
*/
public static synchronized ScalarType getScalarTypeByName(String name) {
if (name == null) {
return null;
}
checkQueue();
if (Translations.containsKey(name)) {
name = (String )Translations.get(name);
}
ScalarType st;
Object obj = ScalarHash.get(name);
st =
obj == null
? null
: (ScalarType)((WeakMapValue)obj).getValue();
return st;
}
/**
* Throw a TypeException if the name is invalid.
*
* @param name Name to check.
* @param type Type used in exception message.
*
* @exception TypeException If there is a problem with the name.
*/
public static synchronized void validateName(String name, String type)
throws TypeException
{
if (name == null) {
throw new TypeException("ScalarType: " + type + " cannot be null");
}
if (name.indexOf(".") > -1 ||
name.indexOf(" ") > -1 ||
name.indexOf("(") > -1 ||
name.indexOf(")") > -1) {
throw new TypeException("ScalarType: " + type + " cannot contain " +
"space . ( or ) " + name);
}
if (getScalarTypeByName(name) != null) {
throw new TypeException("ScalarType: " + type + " already used");
}
if (Translations.containsKey(name)) {
throw new TypeException("ScalarType: " + type + " already used" +
" as an alias");
}
}
/*
public static void dumpAliases()
{
java.util.Enumeration en;
boolean needHead = true;
en = Translations.keys();
while (en.hasMoreElements()) {
Object key = en.nextElement();
if (needHead) {
System.err.println("== Translation table");
needHead = false;
}
System.err.println(" \"" + key + "\" => \"" +
Translations.get(key) + "\"");
}
boolean needMid = true;
en = ReverseTranslations.keys();
while (en.hasMoreElements()) {
Object key = en.nextElement();
if (needMid) {
if (needHead) {
System.err.println("== Reverse Translation table");
needHead = false;
} else {
System.err.println("-- Reverse Translation table");
}
needMid = false;
}
System.err.println(" \"" + key + "\" => \"" +
ReverseTranslations.get(key) + "\"");
}
if (!needHead) {
System.err.println("==");
}
}
*/
/**
*
Returns the instance corresponding to this newly deserialized instance.
* If a ScalarType with the same name as this instance already exists and
* is compatible with this instance, then it is returned. Otherwise, this
* instance is returned.
*
* This method is protected so that it is always invoked during
* deserialization and final to prevent subclasses from evading it.
*
* @return the unique ScalarType object corresponding
* to this object's name.
* @throws InvalidObjectException if an incompatible ScalarType with the same
* name as this instance already exists.
*/
protected final Object readResolve()
throws InvalidObjectException
{
ScalarType st;
synchronized(getClass()) {
st = getScalarTypeByName(Name);
if (st == null) {
ScalarHash.put(Name, new WeakMapValue(Name, this, queue));
st = this;
}
else if (!equals(st)) {
throw new InvalidObjectException(toString());
}
}
return st;
}
/**
* Checks the queue for garbage-collected instances and removes them from the
* hash table and translation tables.
*/
private static synchronized void checkQueue() {
for (WeakMapValue ref; (ref = (WeakMapValue)queue.poll()) != null; ) {
Object name = ref.getKey();
ScalarHash.remove(name);
Object alias = ReverseTranslations.remove(name);
if (alias != null)
Translations.remove(alias);
}
}
}
Ads help maintain this website.