    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    }