001 //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/tags/2.1/src/org/deegree/model/csct/cs/Info.java $ 002 /*---------------- FILE HEADER ------------------------------------------ 003 004 This file is part of deegree. 005 Copyright (C) 2001 by: 006 EXSE, Department of Geography, University of Bonn 007 http://www.giub.uni-bonn.de/exse/ 008 lat/lon GmbH 009 http://www.lat-lon.de 010 011 It has been implemented within SEAGIS - An OpenSource implementation of OpenGIS specification 012 (C) 2001, Institut de Recherche pour le D�veloppement (http://sourceforge.net/projects/seagis/) 013 SEAGIS Contacts: Surveillance de l'Environnement Assist�e par Satellite 014 Institut de Recherche pour le D�veloppement / US-Espace 015 mailto:seasnet@teledetection.fr 016 017 018 This library is free software; you can redistribute it and/or 019 modify it under the terms of the GNU Lesser General Public 020 License as published by the Free Software Foundation; either 021 version 2.1 of the License, or (at your option) any later version. 022 023 This library is distributed in the hope that it will be useful, 024 but WITHOUT ANY WARRANTY; without even the implied warranty of 025 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 026 Lesser General Public License for more details. 027 028 You should have received a copy of the GNU Lesser General Public 029 License along with this library; if not, write to the Free Software 030 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 031 032 Contact: 033 034 Andreas Poth 035 lat/lon GmbH 036 Aennchenstr. 19 037 53115 Bonn 038 Germany 039 E-Mail: poth@lat-lon.de 040 041 Klaus Greve 042 Department of Geography 043 University of Bonn 044 Meckenheimer Allee 166 045 53115 Bonn 046 Germany 047 E-Mail: klaus.greve@uni-bonn.de 048 049 050 ---------------------------------------------------------------------------*/ 051 package org.deegree.model.csct.cs; 052 053 // OpenGIS dependencies 054 import java.io.Serializable; 055 import java.util.Map; 056 057 import org.deegree.model.csct.resources.Utilities; 058 import org.deegree.model.csct.resources.WeakHashSet; 059 import org.deegree.model.csct.resources.css.ResourceKeys; 060 import org.deegree.model.csct.resources.css.Resources; 061 import org.deegree.model.csct.units.Unit; 062 063 /** 064 * A base class for metadata applicable to coordinate system objects. The metadata items 065 * "Abbreviation", "Alias", "Authority", "AuthorityCode", "Name" and "Remarks" were specified in the 066 * Simple Features interfaces, so they have been kept here. 067 * 068 * This specification does not dictate what the contents of these items should be. However, the 069 * following guidelines are suggested: 070 * <ul> 071 * <li>When {@link org.deegree.model.csct.cs.CoordinateSystemAuthorityFactory} is used to create an 072 * object, the "Authority" and "AuthorityCode" values should be set to the authority name of the 073 * factory object, and the authority code supplied by the client, respectively. The other values may 074 * or may not be set. (If the authority is EPSG, the implementer may consider using the 075 * corresponding metadata values in the EPSG tables.)</li> 076 * <li>When {@link org.deegree.model.csct.cs.CoordinateSystemFactory} creates an object, the "Name" 077 * should be set to the value supplied by the client. All of the other metadata items should be left 078 * empty.</li> 079 * </ul> 080 * 081 * @version 1.00 082 * @author OpenGIS (www.opengis.org) 083 * @author Martin Desruisseaux 084 * 085 * @author last edited by: $Author: bezema $ 086 * 087 * @version $Revision: 6259 $, $Date: 2007-03-20 10:15:15 +0100 (Di, 20 Mär 2007) $ 088 * 089 * @see "org.opengis.cs.CS_Info" 090 */ 091 public class Info implements Serializable { 092 /** 093 * Serial number for interoperability with different versions. 094 */ 095 private static final long serialVersionUID = -771181600202966524L; 096 097 /** 098 * Set of weak references to existing coordinate systems. This set is used in order to return 099 * pre-existing object instead of creating new one. 100 */ 101 static final WeakHashSet pool = new WeakHashSet(); 102 103 /** 104 * The non-localized object name. 105 */ 106 private final String name; 107 108 /** 109 * Properties for all methods except {@link #getName}. For example the method 110 * {@link #getAuthorityCode} returns the value of property <code>"authorityCode"</code>. May 111 * be null if there is no properties for this object. 112 */ 113 private final Map properties; 114 115 /** 116 * Create an object with the specified name. 117 * 118 * @param name 119 * This object name. 120 */ 121 public Info( final String name ) { 122 this.name = name; 123 this.properties = null; 124 ensureNonNull( "name", name ); 125 } 126 127 /** 128 * Create an object with the specified properties. Property keys are any of the following 129 * strings: 130 * <ul> 131 * <li>"name" (mandatory)</li> 132 * <li>"authority"</li> 133 * <li>"authorityCode"</li> 134 * <li>"alias"</li> 135 * <li>"abbreviation"</li> 136 * <li>"remarks"</li> 137 * </ul> 138 * Values are usually {@link String}, or may be <code>null</code> if a particular property is 139 * not defined. The "name" property is mandatory. 140 * 141 * @param properties 142 * The set of properties. 143 */ 144 Info( final Map properties ) { 145 ensureNonNull( "properties", properties ); 146 this.properties = properties; 147 this.name = (String) properties.get( "name" ); 148 } 149 150 /** 151 * Gets the name of this object. The default implementation returns the non-localized name given 152 * at construction time. 153 * 154 * @param locale 155 * The desired locale, or <code>null</code> for a default locale. If no string is 156 * available for the specified locale, an arbitrary locale is used. 157 * @return the name of this object. 158 * 159 * @see "org.opengis.cs.CS_Info#getName()" 160 */ 161 public String getName() { 162 return name; 163 } 164 165 /** 166 * Gets the authority name, or <code>null</code> if unspecified. An Authority is an 167 * organization that maintains definitions of Authority Codes. For example the European 168 * Petroleum Survey Group (EPSG) maintains a database of coordinate systems, and other spatial 169 * referencing objects, where each object has a code number ID. For example, the EPSG code for a 170 * WGS84 Lat/Lon coordinate system is '4326'. 171 * 172 * @return the authority name, or <code>null</code> if unspecified. 173 * 174 * @see "org.opengis.cs.CS_Info#getAuthority()" 175 */ 176 public String getAuthority() { 177 return ( properties != null ) ? (String) properties.get( "authority" ) : null; 178 } 179 180 /** 181 * Gets the authority-specific identification code, or <code>null</code> if unspecified. The 182 * AuthorityCode is a compact string defined by an Authority to reference a particular spatial 183 * reference object. For example, the European Survey Group (EPSG) authority uses 32 bit 184 * integers to reference coordinate systems, so all their code strings will consist of a few 185 * digits. The EPSG code for WGS84 Lat/Lon is '4326'. 186 * 187 * @return the authority-specific identification code, or <code>null</code> if unspecified. 188 * 189 * 190 * @see "org.opengis.cs.CS_Info#getAuthorityCode()" 191 */ 192 public String getAuthorityCode() { 193 return ( properties != null ) ? (String) properties.get( "authorityCode" ) : null; 194 } 195 196 /** 197 * Gets the alias, or <code>null</code> if there is none. 198 * 199 * @return he alias, or <code>null</code> if there is none. 200 * 201 * @see "org.opengis.cs.CS_Info#getAlias()" 202 */ 203 public String getAlias() { 204 return ( properties != null ) ? (String) properties.get( "alias" ) : null; 205 } 206 207 /** 208 * Gets the abbreviation, or <code>null</code> if there is none. 209 * 210 * @return the abbreviation, or <code>null</code> if there is none. 211 * 212 * @see "org.opengis.cs.CS_Info#getAbbreviation()" 213 */ 214 public String getAbbreviation() { 215 return ( properties != null ) ? (String) properties.get( "abbreviation" ) : null; 216 } 217 218 /** 219 * Gets the provider-supplied remarks, or <code>null</code> if there is none. 220 * 221 * @return the provider-supplied remarks, or <code>null</code> if there is none. 222 * 223 * @see "org.opengis.cs.CS_Info#getRemarks()" 224 */ 225 public String getRemarks() { 226 return ( properties != null ) ? (String) properties.get( "remarks" ) : null; 227 } 228 229 /** 230 * Returns a hash value for this info. 231 * 232 * @return a hash value for this info. 233 */ 234 public int hashCode() { 235 final String name = getName(); 236 return ( name != null ) ? name.hashCode() : 369781; 237 } 238 239 /** 240 * Compares the specified object with this info for equality. 241 * 242 * @return 243 */ 244 public boolean equals( final Object object ) { 245 if ( object != null && getClass().equals( object.getClass() ) ) { 246 final Info that = (Info) object; 247 return Utilities.equals( this.name, that.name ) 248 && Utilities.equals( this.properties, that.properties ); 249 } 250 return false; 251 } 252 253 /** 254 * Returns a <em>Well Know Text</em> (WKT) for this info. "Well know text" are part of 255 * OpenGIS's specification. 256 * 257 * @return a <em>Well Know Text</em> (WKT) for this info. 258 */ 259 public String toString() { 260 final StringBuffer buffer = new StringBuffer( 40 ); 261 buffer.append( "[\"" ); 262 buffer.append( getName() ); 263 buffer.append( '"' ); 264 buffer.insert( 0, addString() ); 265 if ( properties != null ) { 266 final Object authority = properties.get( "authority" ); 267 if ( authority != null ) { 268 buffer.append( ", AUTHORITY[" ); 269 buffer.append( authority ); 270 // TODO: Add code (as is AUTHORITY["EPSG","8901"]) 271 buffer.append( "\"]" ); 272 } 273 } 274 buffer.append( ']' ); 275 return buffer.toString(); 276 } 277 278 /** 279 * Add more information inside the "[...]" part of {@link #toString}. The default 280 * implementation add nothing. Subclasses will override this method in order to complete string 281 * representation. 282 * 283 * @return The WKT code name (e.g. "GEOGCS"). 284 */ 285 String addString() { 286 return Utilities.getShortClassName( this ); 287 } 288 289 /** 290 * Add a unit in WKT form. 291 * 292 * @param buffer 293 * @param unit 294 */ 295 final void addUnit( final StringBuffer buffer, final Unit unit ) { 296 if ( unit != null ) { 297 buffer.append( "UNIT[" ); 298 if ( Unit.METRE.canConvert( unit ) ) { 299 buffer.append( "\"metre\"," ); 300 buffer.append( Unit.METRE.convert( 1, unit ) ); 301 } else if ( Unit.DEGREE.canConvert( unit ) ) { 302 buffer.append( "\"degree\"," ); 303 buffer.append( Unit.DEGREE.convert( 1, unit ) ); 304 } else if ( Unit.SECOND.canConvert( unit ) ) { 305 buffer.append( "\"second\"," ); 306 buffer.append( Unit.SECOND.convert( 1, unit ) ); 307 } 308 buffer.append( ']' ); 309 } 310 } 311 312 /** 313 * Make sure an argument is non-null. This is a convenience method for subclasses constructors. 314 * 315 * @param name 316 * Argument name. 317 * @param object 318 * User argument. 319 * @throws IllegalArgumentException 320 * if <code>object</code> is null. 321 */ 322 protected static void ensureNonNull( final String name, final Object object ) 323 throws IllegalArgumentException { 324 if ( object == null ) 325 throw new IllegalArgumentException( 326 Resources.format( 327 ResourceKeys.ERROR_NULL_ARGUMENT_$1, 328 name ) ); 329 } 330 331 /** 332 * Make sure an array element is non-null. 333 * 334 * @param name 335 * Argument name. 336 * @param array 337 * User argument. 338 * @param index 339 * Element to check. 340 * @throws IllegalArgumentException 341 * if <code>array[i]</code> is null. 342 */ 343 static void ensureNonNull( final String name, final Object[] array, final int index ) 344 throws IllegalArgumentException { 345 if ( array[index] == null ) 346 throw new IllegalArgumentException( 347 Resources.format( 348 ResourceKeys.ERROR_NULL_ARGUMENT_$1, 349 name + '[' + index + ']' ) ); 350 } 351 352 /** 353 * Make sure that the specified unit is a temporal one. 354 * 355 * @param unit 356 * Unit to check. 357 * @throws IllegalArgumentException 358 * if <code>unit</code> is not a temporal unit. 359 */ 360 static void ensureTimeUnit( final Unit unit ) 361 throws IllegalArgumentException { 362 if ( !Unit.SECOND.canConvert( unit ) ) 363 throw new IllegalArgumentException( 364 Resources.format( 365 ResourceKeys.ERROR_NON_TEMPORAL_UNIT_$1, 366 unit ) ); 367 } 368 369 /** 370 * Make sure that the specified unit is a linear one. 371 * 372 * @param unit 373 * Unit to check. 374 * @throws IllegalArgumentException 375 * if <code>unit</code> is not a linear unit. 376 */ 377 static void ensureLinearUnit( final Unit unit ) 378 throws IllegalArgumentException { 379 if ( !Unit.METRE.canConvert( unit ) ) 380 throw new IllegalArgumentException( 381 Resources.format( 382 ResourceKeys.ERROR_NON_LINEAR_UNIT_$1, 383 unit ) ); 384 } 385 386 /** 387 * Make sure that the specified unit is an angular one. 388 * 389 * @param unit 390 * Unit to check. 391 * @throws IllegalArgumentException 392 * if <code>unit</code> is not an angular unit. 393 */ 394 static void ensureAngularUnit( final Unit unit ) 395 throws IllegalArgumentException { 396 if ( !Unit.DEGREE.canConvert( unit ) ) 397 throw new IllegalArgumentException( 398 Resources.format( 399 ResourceKeys.ERROR_NON_ANGULAR_UNIT_$1, 400 unit ) ); 401 } 402 403 /** 404 * Returns a reference to an unique instance of this <code>Info</code>. This method is 405 * automatically invoked during deserialization. 406 * 407 * NOTE ABOUT ACCESS-MODIFIER: This method can't be private, because it would prevent it from 408 * being invoked from subclasses in this package (e.g. {@link CoordinateSystem}). This method 409 * <em>will not</em> be invoked for classes outside this package, unless we give it 410 * <code>protected</code> access. TODO: Would it be a good idea? 411 * 412 * @return a reference to an unique instance of this <code>Info</code>. 413 */ 414 Object readResolve() { 415 return pool.intern( this ); 416 } 417 418 }