/*---------------- FILE HEADER ------------------------------------------
This file is part of deegree.
Copyright (C) 2001 by:
EXSE, Department of Geography, University of Bonn
http://www.giub.uni-bonn.de/exse/
lat/lon GmbH
http://www.lat-lon.de
It has been implemented within SEAGIS - An OpenSource implementation of OpenGIS specification
(C) 2001, Institut de Recherche pour le D�veloppement (http://sourceforge.net/projects/seagis/)
SEAGIS Contacts: Surveillance de l'Environnement Assist�e par Satellite
Institut de Recherche pour le D�veloppement / US-Espace
mailto:seasnet@teledetection.fr
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser 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
Contact:
Andreas Poth
lat/lon GmbH
Aennchenstr. 19
53115 Bonn
Germany
E-Mail: poth@lat-lon.de
Klaus Greve
Department of Geography
University of Bonn
Meckenheimer Allee 166
53115 Bonn
Germany
E-Mail: klaus.greve@uni-bonn.de
---------------------------------------------------------------------------*/
package org.deegree.model.csct.cs;
// OpenGIS dependencies
import java.io.ObjectStreamException;
import java.io.Serializable;
import java.util.Locale;
import java.util.Map;
import org.deegree.model.csct.resources.Utilities;
import org.deegree.model.csct.resources.WeakHashSet;
import org.deegree.model.csct.resources.css.ResourceKeys;
import org.deegree.model.csct.resources.css.Resources;
import org.deegree.model.csct.units.Unit;
/**
* A base class for metadata applicable to coordinate system objects.
* The metadata items "Abbreviation", "Alias", "Authority", "AuthorityCode",
* "Name" and "Remarks" were specified in the Simple Features interfaces,
* so they have been kept here.
*
* This specification does not dictate what the contents of these items
* should be. However, the following guidelines are suggested:
* <ul>
* <li>When {@link org.deegree.model.csct.cs.CoordinateSystemAuthorityFactory}
* is used to create an object, the "Authority" and "AuthorityCode"
* values should be set to the authority name of the factory object,
* and the authority code supplied by the client, respectively. The
* other values may or may not be set. (If the authority is EPSG,
* the implementer may consider using the corresponding metadata values
* in the EPSG tables.)</li>
* <li>When {@link org.deegree.model.csct.cs.CoordinateSystemFactory} creates an
* object, the "Name" should be set to the value supplied by the client.
* All of the other metadata items should be left empty.</li>
* </ul>
*
* @version 1.00
* @author OpenGIS (www.opengis.org)
* @author Martin Desruisseaux
*
* @see org.opengis.cs.CS_Info
*/
public class Info implements Serializable {
/**
* Serial number for interoperability with different versions.
*/
private static final long serialVersionUID = -771181600202966524L;
/**
* Set of weak references to existing coordinate systems.
* This set is used in order to return pre-existing object
* instead of creating new one.
*/
static final WeakHashSet pool = new WeakHashSet();
/**
* The non-localized object name.
*/
private final String name;
/**
* Properties for all methods except {@link #getName}. For
* example the method {@link #getAuthorityCode} returns the
* value of property <code>"authorityCode"</code>. May be
* null if there is no properties for this object.
*/
private final Map properties;
/**
* OpenGIS object returned by {@link #cachedOpenGIS}.
* It may be a hard or a weak reference.
*/
private transient Object proxy;
/**
* Create an object with the specified name.
*
* @param name This object name.
*/
public Info( final String name ) {
this.name = name;
this.properties = null;
ensureNonNull( "name", name );
}
/**
* Create an object with the specified properties.
* Property keys are any of the following strings:
* <ul>
* <li>"name" (mandatory)</li>
* <li>"authority"</li>
* <li>"authorityCode"</li>
* <li>"alias"</li>
* <li>"abbreviation"</li>
* <li>"remarks"</li>
* </ul>
* Values are usually {@link String}, or may be <code>null</code>
* if a particular property is not defined. The "name" property
* is mandatory.
*
* @param properties The set of properties.
*/
Info( final Map properties ) {
ensureNonNull( "properties", properties );
this.properties = properties;
this.name = (String) properties.get( "name" );
this.proxy = properties.get( "proxy" );
}
/**
* Gets the name of this object. The default implementation
* returns the non-localized name given at construction time.
*
* @param locale The desired locale, or <code>null</code> for a default locale.
* If no string is available for the specified locale, an arbitrary locale
* is used.
*
* @see org.opengis.cs.CS_Info#getName()
*/
public String getName( final Locale locale ) {
return name;
}
/**
* Gets the authority name, or <code>null</code> if unspecified.
* An Authority is an organization that maintains definitions of Authority
* Codes. For example the European Petroleum Survey Group (EPSG) maintains
* a database of coordinate systems, and other spatial referencing objects,
* where each object has a code number ID. For example, the EPSG code for a
* WGS84 Lat/Lon coordinate system is '4326'.
*
* @param locale The desired locale, or <code>null</code> for the default locale.
* If no string is available for the specified locale, an arbitrary locale
* is used.
*
* @see org.opengis.cs.CS_Info#getAuthority()
*/
public String getAuthority( final Locale locale ) {
return ( properties != null ) ? (String) properties.get( "authority" ) : null;
}
/**
* Gets the authority-specific identification code, or <code>null</code> if unspecified.
* The AuthorityCode is a compact string defined by an Authority to reference
* a particular spatial reference object. For example, the European Survey
* Group (EPSG) authority uses 32 bit integers to reference coordinate systems,
* so all their code strings will consist of a few digits. The EPSG code for
* WGS84 Lat/Lon is '4326'.
*
* @param locale The desired locale, or <code>null</code> for the default locale.
* If no string is available for the specified locale, an arbitrary locale
* is used.
*
* @see org.opengis.cs.CS_Info#getAuthorityCode()
*/
public String getAuthorityCode( final Locale locale ) {
return ( properties != null ) ? (String) properties.get( "authorityCode" ) : null;
}
/**
* Gets the alias, or <code>null</code> if there is none.
*
* @param locale The desired locale, or <code>null</code> for the default locale.
* If no string is available for the specified locale, an arbitrary locale
* is used.
*
* @see org.opengis.cs.CS_Info#getAlias()
*/
public String getAlias( final Locale locale ) {
return ( properties != null ) ? (String) properties.get( "alias" ) : null;
}
/**
* Gets the abbreviation, or <code>null</code> if there is none.
*
* @param locale The desired locale, or <code>null</code> for the default locale.
* If no string is available for the specified locale, an arbitrary locale
* is used.
*
* @see org.opengis.cs.CS_Info#getAbbreviation()
*/
public String getAbbreviation( final Locale locale ) {
return ( properties != null ) ? (String) properties.get( "abbreviation" ) : null;
}
/**
* Gets the provider-supplied remarks,
* or <code>null</code> if there is none.
*
* @param locale The desired locale, or <code>null</code> for the default locale.
* If no string is available for the specified locale, an arbitrary locale
* is used.
*
* @see org.opengis.cs.CS_Info#getRemarks()
*/
public String getRemarks( final Locale locale ) {
return ( properties != null ) ? (String) properties.get( "remarks" ) : null;
}
/**
* Returns a hash value for this info.
*/
public int hashCode() {
final String name = getName( null );
return ( name != null ) ? name.hashCode() : 369781;
}
/**
* Compares the specified object
* with this info for equality.
*/
public boolean equals( final Object object ) {
if ( object != null && getClass().equals( object.getClass() ) ) {
final Info that = (Info) object;
return Utilities.equals( this.name, that.name )
&& Utilities.equals( this.properties, that.properties );
}
return false;
}
/**
* Returns a <em>Well Know Text</em> (WKT) for this info.
* "Well know text" are part of OpenGIS's specification.
*/
public String toString() {
final StringBuffer buffer = new StringBuffer( 40 );
buffer.append( "[\"" );
buffer.append( getName( null ) );
buffer.append( '"' );
buffer.insert( 0, addString( buffer ) );
if ( properties != null ) {
final Object authority = properties.get( "authority" );
if ( authority != null ) {
buffer.append( ", AUTHORITY[" );
buffer.append( authority );
// TODO: Add code (as is AUTHORITY["EPSG","8901"])
buffer.append( "\"]" );
}
}
buffer.append( ']' );
return buffer.toString();
}
/**
* Add more information inside the "[...]" part of {@link #toString}.
* The default implementation add nothing. Subclasses will override
* this method in order to complete string representation.
*
* @param buffer The buffer to add string to.
* @return The WKT code name (e.g. "GEOGCS").
*/
String addString( final StringBuffer buffer ) {
return Utilities.getShortClassName( this );
}
/**
* Add a unit in WKT form.
*/
final void addUnit( final StringBuffer buffer, final Unit unit ) {
if ( unit != null ) {
buffer.append( "UNIT[" );
if ( Unit.METRE.canConvert( unit ) ) {
buffer.append( "\"metre\"," );
buffer.append( Unit.METRE.convert( 1, unit ) );
} else if ( Unit.DEGREE.canConvert( unit ) ) {
buffer.append( "\"degree\"," );
buffer.append( Unit.DEGREE.convert( 1, unit ) );
} else if ( Unit.SECOND.canConvert( unit ) ) {
buffer.append( "\"second\"," );
buffer.append( Unit.SECOND.convert( 1, unit ) );
}
buffer.append( ']' );
}
}
/**
* Make sure an argument is non-null. This is a
* convenience method for subclasses constructors.
*
* @param name Argument name.
* @param object User argument.
* @throws IllegalArgumentException if <code>object</code> is null.
*/
protected static void ensureNonNull( final String name, final Object object )
throws IllegalArgumentException {
if ( object == null )
throw new IllegalArgumentException(
Resources.format(
ResourceKeys.ERROR_NULL_ARGUMENT_$1,
name ) );
}
/**
* Make sure an array element is non-null.
*
* @param name Argument name.
* @param array User argument.
* @param index Element to check.
* @throws IllegalArgumentException if <code>array[i]</code> is null.
*/
static void ensureNonNull( final String name, final Object[] array, final int index )
throws IllegalArgumentException {
if ( array[index] == null )
throw new IllegalArgumentException(
Resources.format(
ResourceKeys.ERROR_NULL_ARGUMENT_$1,
name + '[' + index + ']' ) );
}
/**
* Make sure that the specified unit is a temporal one.
*
* @param unit Unit to check.
* @throws IllegalArgumentException if <code>unit</code> is not a temporal unit.
*/
static void ensureTimeUnit( final Unit unit )
throws IllegalArgumentException {
if ( !Unit.SECOND.canConvert( unit ) )
throw new IllegalArgumentException(
Resources.format(
ResourceKeys.ERROR_NON_TEMPORAL_UNIT_$1,
unit ) );
}
/**
* Make sure that the specified unit is a linear one.
*
* @param unit Unit to check.
* @throws IllegalArgumentException if <code>unit</code> is not a linear unit.
*/
static void ensureLinearUnit( final Unit unit )
throws IllegalArgumentException {
if ( !Unit.METRE.canConvert( unit ) )
throw new IllegalArgumentException(
Resources.format(
ResourceKeys.ERROR_NON_LINEAR_UNIT_$1,
unit ) );
}
/**
* Make sure that the specified unit is an angular one.
*
* @param unit Unit to check.
* @throws IllegalArgumentException if <code>unit</code> is not an angular unit.
*/
static void ensureAngularUnit( final Unit unit )
throws IllegalArgumentException {
if ( !Unit.DEGREE.canConvert( unit ) )
throw new IllegalArgumentException(
Resources.format(
ResourceKeys.ERROR_NON_ANGULAR_UNIT_$1,
unit ) );
}
/**
* Returns a reference to an unique instance of this <code>Info</code>.
* This method is automatically invoked during deserialization.
*
* NOTE ABOUT ACCESS-MODIFIER: This method can't be private,
* because it would prevent it from being invoked from subclasses
* in this package (e.g. {@link CoordinateSystem}). This method
* <em>will not</em> be invoked for classes outside this package,
* unless we give it <code>protected</code> access. TODO: Would
* it be a good idea?
*/
Object readResolve()
throws ObjectStreamException {
return pool.intern( this );
}
}