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 }