001 //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/branches/2.4_testing/src/org/deegree/crs/Identifiable.java $
002 /*----------------------------------------------------------------------------
003 This file is part of deegree, http://deegree.org/
004 Copyright (C) 2001-2009 by:
005 Department of Geography, University of Bonn
006 and
007 lat/lon GmbH
008
009 This library is free software; you can redistribute it and/or modify it under
010 the terms of the GNU Lesser General Public License as published by the Free
011 Software Foundation; either version 2.1 of the License, or (at your option)
012 any later version.
013 This library is distributed in the hope that it will be useful, but WITHOUT
014 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
015 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
016 details.
017 You should have received a copy of the GNU Lesser General Public License
018 along with this library; if not, write to the Free Software Foundation, Inc.,
019 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
020
021 Contact information:
022
023 lat/lon GmbH
024 Aennchenstr. 19, 53177 Bonn
025 Germany
026 http://lat-lon.de/
027
028 Department of Geography, University of Bonn
029 Prof. Dr. Klaus Greve
030 Postfach 1147, 53001 Bonn
031 Germany
032 http://www.geographie.uni-bonn.de/deegree/
033
034 e-mail: info@deegree.org
035 ----------------------------------------------------------------------------*/
036
037 package org.deegree.crs;
038
039 import static org.deegree.framework.log.LoggerFactory.getLogger;
040
041 import java.io.Serializable;
042
043 import org.deegree.framework.log.ILogger;
044 import org.deegree.i18n.Messages;
045
046 /**
047 * The <code>Identifiable</code> class can be used to identify a crs, ellipsoid, Datum and primemeridian
048 *
049 * @author <a href="mailto:bezema@lat-lon.de">Rutger Bezema</a>
050 *
051 * @author last edited by: $Author: aschmitz $
052 *
053 * @version $Revision: 21456 $, $Date: 2009-12-15 15:17:33 +0100 (Di, 15. Dez 2009) $
054 *
055 */
056
057 public class Identifiable implements Serializable {
058
059 private static final long serialVersionUID = 4687689233685635124L;
060
061 private static final ILogger LOG = getLogger( Identifiable.class );
062
063 private String[] identifiers;
064
065 private String[] versions;
066
067 private String[] names;
068
069 private String[] descriptions;
070
071 private String[] areasOfUse;
072
073 private double[] areaOfUseBBox;
074
075 /**
076 * Takes the references of the other object and stores them in this Identifiable Object.
077 *
078 * @param other
079 * identifiable object.
080 */
081 public Identifiable( Identifiable other ) {
082 this( other.getIdentifiers(), other.getNames(), other.getVersions(), other.getDescriptions(),
083 other.getAreasOfUse() );
084 }
085
086 /**
087 *
088 * @param identifiers
089 * @param names
090 * the human readable names of the object.
091 * @param versions
092 * @param descriptions
093 * @param areasOfUse
094 * @throws IllegalArgumentException
095 * if no identifier(s) was/were given.
096 */
097 public Identifiable( String[] identifiers, String[] names, String[] versions, String[] descriptions,
098 String[] areasOfUse ) {
099 if ( identifiers == null || identifiers.length == 0 ) {
100 throw new IllegalArgumentException( "An identifiable object must at least have one identifier." );
101 }
102 this.identifiers = identifiers;
103
104 this.names = names;
105 this.versions = versions;
106 this.descriptions = descriptions;
107 this.areasOfUse = areasOfUse;
108 }
109
110 /**
111 * Creates arrays fromt the given identifier and name without setting the versions, descriptions and areasOfUse.
112 *
113 * @param identifiers
114 * of the object.
115 */
116 public Identifiable( String[] identifiers ) {
117 this( identifiers, null, null, null, null );
118 }
119
120 // /**
121 // * Creates arrays fromt the given identifier and name without setting the versions,
122 // descriptions and areasOfUse.
123 // *
124 // * @param identifier of the object.
125 // * @param name the human readable name of the object.
126 // */
127 // protected Identifiable( String identifier, String name ) {
128 // this( new String[]{identifier}, new String[]{name}, null, null, null );
129 // }
130
131 /**
132 * @param id
133 * of the Identifier
134 */
135 public Identifiable( String id ) {
136 this( new String[] { id } );
137 }
138
139 /**
140 * @return the first of all areasOfUse or <code>null</code> if no areasOfUse were given.
141 */
142 public final String getAreaOfUse() {
143 return ( areasOfUse != null && areasOfUse.length > 0 ) ? areasOfUse[0] : null;
144 }
145
146 /**
147 * @return the first of all descriptions or <code>null</code> if no descriptions were given.
148 */
149 public final String getDescription() {
150 return ( descriptions != null && descriptions.length > 0 ) ? descriptions[0] : null;
151 }
152
153 /**
154 * @return the first of all identifiers.
155 */
156 public final String getIdentifier() {
157 return identifiers[0];
158 }
159
160 /**
161 * @return the first of all names or <code>null</code> if no names were given.
162 */
163 public final String getName() {
164 return ( names != null && names.length > 0 ) ? names[0] : null;
165 }
166
167 /**
168 * @return the first of all versions or <code>null</code> if no versions were given.
169 */
170 public final String getVersion() {
171 return ( versions != null && versions.length > 0 ) ? versions[0] : null;
172 }
173
174 /**
175 * throws an InvalidParameterException if the given object is null
176 *
177 * @param toBeChecked
178 * for <code>null</code>
179 * @param message
180 * to put into the exception. If absent, the default message (CRS_INVALID_NULL_PARAMETER) will be
181 * inserted.
182 * @throws IllegalArgumentException
183 * if the given object is <code>null</code>.
184 */
185 protected void checkForNullObject( Object toBeChecked, String message )
186 throws IllegalArgumentException {
187 if ( toBeChecked == null ) {
188 if ( message == null || "".equals( message.trim() ) ) {
189 message = Messages.getMessage( "CRS_INVALID_NULL_PARAMETER" );
190 }
191 throw new IllegalArgumentException( message );
192 }
193
194 }
195
196 /**
197 * throws an InvalidParameterException if the given object is null
198 *
199 * @param toBeChecked
200 * for <code>null</code>
201 * @param functionName
202 * of the caller
203 * @param paramName
204 * of the parameter to be checked.
205 * @throws IllegalArgumentException
206 * if the given object is <code>null</code>.
207 */
208 public static void checkForNullObject( Object toBeChecked, String functionName, String paramName )
209 throws IllegalArgumentException {
210 if ( toBeChecked == null ) {
211 throw new IllegalArgumentException( Messages.getMessage( "CRS_PARAMETER_NOT_NULL", functionName, paramName ) );
212 }
213 }
214
215 /**
216 * throws an IllegalArgumentException if the given object array is null or empty
217 *
218 * @param toBeChecked
219 * for <code>null</code> or empty
220 * @param message
221 * to put into the exception. If absent, the default message (CRS_INVALID_NULL_PARAMETER) will be
222 * inserted.
223 * @throws IllegalArgumentException
224 * if the given object array is <code>null</code> or empty.
225 */
226 public static void checkForNullObject( Object[] toBeChecked, String message )
227 throws IllegalArgumentException {
228 if ( toBeChecked != null && toBeChecked.length != 0 ) {
229 return;
230 }
231 if ( message == null || "".equals( message.trim() ) ) {
232 message = Messages.getMessage( "CRS_INVALID_NULL_ARRAY" );
233 }
234 throw new IllegalArgumentException( message );
235 }
236
237 @Override
238 public String toString() {
239 StringBuilder sb = new StringBuilder( "id: [" );
240 for ( int i = 0; i < identifiers.length; ++i ) {
241 sb.append( identifiers[i] );
242 if ( ( i + 1 ) < identifiers.length ) {
243 sb.append( ", " );
244 }
245 }
246 if ( getName() != null ) {
247 sb.append( "], name: [" );
248 for ( int i = 0; i < names.length; ++i ) {
249 sb.append( names[i] );
250 if ( ( i + 1 ) < names.length ) {
251 sb.append( ", " );
252 }
253 }
254 }
255 if ( getVersion() != null ) {
256 sb.append( "], version: [" );
257 for ( int i = 0; i < versions.length; ++i ) {
258 sb.append( versions[i] );
259 if ( ( i + 1 ) < versions.length ) {
260 sb.append( ", " );
261 }
262 }
263 }
264 if ( getDescription() != null ) {
265 sb.append( "], description: [" );
266 for ( int i = 0; i < descriptions.length; ++i ) {
267 sb.append( descriptions[i] );
268 if ( ( i + 1 ) < descriptions.length ) {
269 sb.append( ", " );
270 }
271 }
272 }
273 if ( getAreaOfUse() != null ) {
274 sb.append( "], areasOfUse: [" );
275 for ( int i = 0; i < areasOfUse.length; ++i ) {
276 sb.append( areasOfUse[i] );
277 if ( ( i + 1 ) < areasOfUse.length ) {
278 sb.append( ", " );
279 }
280 }
281 }
282 return sb.toString();
283 }
284
285 /**
286 * @return the first id and the name (if given) as id: id, name: name.
287 */
288 public String getIdAndName() {
289 StringBuilder sb = new StringBuilder( "id: " ).append( getIdentifier() );
290 if ( getName() != null ) {
291 sb.append( ", name: " ).append( getName() );
292 }
293 return sb.toString();
294 }
295
296 @Override
297 public boolean equals( Object other ) {
298 if ( other != null && other instanceof Identifiable ) {
299 final Identifiable that = (Identifiable) other;
300 boolean isThisEPSG = false;
301 boolean isThatEPSG = false;
302 for ( String id : getIdentifiers() ) {
303 if ( id.toLowerCase().contains( "epsg" ) ) {
304 isThisEPSG = true;
305 break;
306 }
307 }
308 for ( String id : that.getIdentifiers() ) {
309 if ( id.toLowerCase().contains( "epsg" ) ) {
310 isThatEPSG = true;
311 break;
312 }
313 }
314 if ( isThatEPSG && isThisEPSG ) {
315 return idsMatch( that.identifiers );
316 }
317 return true;// idsMatch( that.identifiers );
318 }
319 return false;
320 }
321
322 /**
323 * Checks for the equality of id's between to different identifiable objects.
324 *
325 * @param otherIDs
326 * of the other identifiable object.
327 * @return true if the given strings match this.identifiers false otherwise.
328 */
329 private boolean idsMatch( String[] otherIDs ) {
330 if ( otherIDs == null || identifiers.length != otherIDs.length ) {
331 return false;
332 }
333 for ( int i = 0; i < identifiers.length; ++i ) {
334 String tmp = identifiers[i];
335 String other = otherIDs[i];
336 if ( tmp != null ) {
337 if ( !tmp.equals( other ) ) {
338 return false;
339 }
340 } else if ( other != null ) {
341 return false;
342 }
343 }
344 return true;
345
346 }
347
348 /**
349 * @return the areasOfUse or <code>null</code> if no areasOfUse were given.
350 */
351 public final String[] getAreasOfUse() {
352 return areasOfUse;
353 }
354
355 /**
356 * @return the descriptions or <code>null</code> if no descriptions were given.
357 */
358 public final String[] getDescriptions() {
359 return descriptions;
360 }
361
362 /**
363 * @return the identifiers, each identifiable object has atleast one id.
364 */
365 public final String[] getIdentifiers() {
366 return identifiers;
367 }
368
369 /**
370 * @return the names or <code>null</code> if no names were given.
371 */
372 public final String[] getNames() {
373 return names;
374 }
375
376 /**
377 * @return the versions or <code>null</code> if no versions were given.
378 */
379 public final String[] getVersions() {
380 return versions;
381 }
382
383 /**
384 * @param id
385 * a string which could match this identifiable.
386 * @return true if this identifiable can be identified with the given string, false otherwise.
387 */
388 public boolean hasID( String id ) {
389 if ( id == null || "".equals( id.trim() ) ) {
390 return false;
391 }
392 for ( String s : getIdentifiers() ) {
393 if ( id.equalsIgnoreCase( s ) ) {
394 return true;
395 }
396 }
397 return false;
398 }
399
400 /**
401 * Returns the area of use, i.e. the domain where this {@link Identifiable} is valid.
402 *
403 * @return the domain of validity (EPSG:4326 coordinates), order: minX, minY, maxX, maxY, never <code>null</code>
404 * (-180,-90,180,90) if no such information is available
405 */
406 public double[] getAreaOfUseBBox() {
407
408 if ( areaOfUseBBox == null ) {
409 areaOfUseBBox = new double[4];
410 areaOfUseBBox[0] = Double.NaN;
411 areaOfUseBBox[1] = Double.NaN;
412 areaOfUseBBox[2] = Double.NaN;
413 areaOfUseBBox[3] = Double.NaN;
414 if ( areasOfUse != null ) {
415 for ( String bboxString : areasOfUse ) {
416 try {
417 double[] ords = parseAreaBBox( bboxString );
418 for ( int i = 0; i < 4; i++ ) {
419 if ( Double.isNaN( areaOfUseBBox[i] ) || areaOfUseBBox[i] > ords[i] ) {
420 areaOfUseBBox[i] = ords[i];
421 }
422 }
423 } catch ( Exception e ) {
424 LOG.logDebug( "Error parsing areaOfUse bbox (ignoring it): '" + e.getMessage() + "'" );
425 }
426 }
427 }
428 if ( Double.isNaN( areaOfUseBBox[0] ) ) {
429 LOG.logDebug( "No areaOfUse BBox available, assuming world." );
430 areaOfUseBBox[0] = -180;
431 areaOfUseBBox[1] = -90;
432 areaOfUseBBox[2] = 180;
433 areaOfUseBBox[3] = 90;
434 }
435 }
436 return areaOfUseBBox;
437 }
438
439 private double[] parseAreaBBox( String s )
440 throws IllegalArgumentException, NumberFormatException {
441 String[] tokens = s.split( "," );
442 if ( tokens.length != 4 ) {
443 throw new IllegalArgumentException( "Invalid areaOfUse: expected CSV-list of length 4." );
444 }
445 double[] ords = new double[4];
446 for ( int i = 0; i < 4; i++ ) {
447 ords[i] = Double.parseDouble( tokens[i] );
448 }
449 return ords;
450 }
451 }