Source Code Cross Referenced for AbstractIdentifiedObject.java in  » GIS » GeoTools-2.4.1 » org » geotools » referencing » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » GIS » GeoTools 2.4.1 » org.geotools.referencing 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         *    GeoTools - OpenSource mapping toolkit
0003:         *    http://geotools.org
0004:         *    (C) 2003-2006, GeoTools Project Managment Committee (PMC)
0005:         *    (C) 2001, Institut de Recherche pour le Développement
0006:         *   
0007:         *    This library is free software; you can redistribute it and/or
0008:         *    modify it under the terms of the GNU Lesser General Public
0009:         *    License as published by the Free Software Foundation;
0010:         *    version 2.1 of the License.
0011:         *
0012:         *    This library is distributed in the hope that it will be useful,
0013:         *    but WITHOUT ANY WARRANTY; without even the implied warranty of
0014:         *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0015:         *    Lesser General Public License for more details.
0016:         *
0017:         *    This package contains documentation from OpenGIS specifications.
0018:         *    OpenGIS consortium's work is fully acknowledged here.
0019:         */
0020:        package org.geotools.referencing;
0021:
0022:        // J2SE dependencies
0023:        import java.io.ObjectStreamException;
0024:        import java.io.Serializable;
0025:        import java.util.Arrays;
0026:        import java.util.Collection;
0027:        import java.util.Collections;
0028:        import java.util.Comparator;
0029:        import java.util.Iterator;
0030:        import java.util.LinkedHashSet;
0031:        import java.util.List;
0032:        import java.util.Map;
0033:        import java.util.Set;
0034:        import java.util.HashMap;
0035:        import java.util.logging.Level;
0036:        import java.util.logging.Logger;
0037:        import javax.units.SI;
0038:        import javax.units.Unit;
0039:
0040:        // OpenGIS dependencies
0041:        import org.opengis.metadata.Identifier;
0042:        import org.opengis.metadata.citation.Citation;
0043:        import org.opengis.parameter.InvalidParameterValueException;
0044:        import org.opengis.referencing.IdentifiedObject;
0045:        import org.opengis.referencing.AuthorityFactory;
0046:        import org.opengis.referencing.ObjectFactory;
0047:        import org.opengis.referencing.ReferenceIdentifier;
0048:        import org.opengis.util.GenericName;
0049:        import org.opengis.util.InternationalString;
0050:        import org.opengis.util.LocalName;
0051:        import org.opengis.util.ScopedName;
0052:
0053:        // Geotools dependencies
0054:        import org.geotools.metadata.iso.citation.Citations;
0055:        import org.geotools.referencing.wkt.Formattable;
0056:        import org.geotools.resources.Utilities;
0057:        import org.geotools.resources.i18n.Errors;
0058:        import org.geotools.resources.i18n.ErrorKeys;
0059:        import org.geotools.resources.i18n.Logging;
0060:        import org.geotools.resources.i18n.LoggingKeys;
0061:        import org.geotools.util.GrowableInternationalString;
0062:        import org.geotools.util.NameFactory;
0063:
0064:        /**
0065:         * A base class for metadata applicable to reference system objects.
0066:         * When {@link AuthorityFactory} is used to create an object, the
0067:         * {@linkplain ReferenceIdentifier#getAuthority authority} and
0068:         * {@linkplain ReferenceIdentifier#getCode authority code} values are set to the authority
0069:         * name of the factory object, and the authority code supplied by the client, respectively.
0070:         * When {@link ObjectFactory} creates an object, the {@linkplain #getName() name} is set to
0071:         * the value supplied by the client and all of the other metadata items are left empty.
0072:         * <p>
0073:         * This class is conceptually <cite>abstract</cite>, even if it is technically possible to
0074:         * instantiate it. Typical applications should create instances of the most specific subclass with
0075:         * {@code Default} prefix instead. An exception to this rule may occurs when it is not possible to
0076:         * identify the exact type. For example it is not possible to infer the exact coordinate system from
0077:         * <A HREF="http://geoapi.sourceforge.net/snapshot/javadoc/org/opengis/referencing/doc-files/WKT.html"><cite>Well
0078:         * Known Text</cite></A> is some cases (e.g. in a {@code LOCAL_CS} element). In such exceptional
0079:         * situation, a plain {@link org.geotools.referencing.cs.AbstractCS} object may be instantiated.
0080:         *
0081:         * @since 2.1
0082:         * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/referencing/src/main/java/org/geotools/referencing/AbstractIdentifiedObject.java $
0083:         * @version $Id: AbstractIdentifiedObject.java 28264 2007-12-05 21:53:08Z desruisseaux $
0084:         * @author Martin Desruisseaux
0085:         */
0086:        public class AbstractIdentifiedObject extends Formattable implements 
0087:                IdentifiedObject, Serializable {
0088:            /**
0089:             * Serial number for interoperability with different versions.
0090:             */
0091:            private static final long serialVersionUID = -5173281694258483264L;
0092:
0093:            /**
0094:             * An empty array of identifiers. This is usefull for fetching identifiers as an array,
0095:             * using the following idiom:
0096:             * <blockquote><pre>
0097:             * {@linkplain #getIdentifiers()}.toArray(EMPTY_IDENTIFIER_ARRAY);
0098:             * </pre></blockquote>
0099:             */
0100:            public static final ReferenceIdentifier[] EMPTY_IDENTIFIER_ARRAY = new ReferenceIdentifier[0];
0101:
0102:            /**
0103:             * An empty array of alias. This is usefull for fetching alias as an array,
0104:             * using the following idiom:
0105:             * <blockquote><pre>
0106:             * {@linkplain #getAlias()}.toArray(EMPTY_ALIAS_ARRAY);
0107:             * </pre></blockquote>
0108:             */
0109:            public static final GenericName[] EMPTY_ALIAS_ARRAY = new GenericName[0];
0110:
0111:            /**
0112:             * A comparator for sorting identified objects by {@linkplain #getName() name}.
0113:             */
0114:            public static final Comparator NAME_COMPARATOR = new NameComparator();
0115:
0116:            private static final class NameComparator implements  Comparator,
0117:                    Serializable {
0118:                public int compare(final Object o1, final Object o2) {
0119:                    return doCompare(((IdentifiedObject) o1).getName()
0120:                            .getCode(), ((IdentifiedObject) o2).getName()
0121:                            .getCode());
0122:                }
0123:
0124:                protected Object readResolve() throws ObjectStreamException {
0125:                    return NAME_COMPARATOR;
0126:                }
0127:            }
0128:
0129:            /**
0130:             * A comparator for sorting identified objects by {@linkplain #getIdentifiers identifiers}.
0131:             */
0132:            public static final Comparator IDENTIFIER_COMPARATOR = new IdentifierComparator();
0133:
0134:            private static final class IdentifierComparator implements 
0135:                    Comparator, Serializable {
0136:                public int compare(final Object o1, final Object o2) {
0137:                    Collection/*<ReferenceIdentifier>*/a1 = ((IdentifiedObject) o1)
0138:                            .getIdentifiers();
0139:                    Collection/*<ReferenceIdentifier>*/a2 = ((IdentifiedObject) o2)
0140:                            .getIdentifiers();
0141:                    if (a1 == null)
0142:                        a1 = Collections.EMPTY_SET;
0143:                    if (a2 == null)
0144:                        a2 = Collections.EMPTY_SET;
0145:                    final Iterator i1 = a1.iterator();
0146:                    final Iterator i2 = a2.iterator();
0147:                    boolean n1, n2;
0148:                    while ((n1 = i1.hasNext()) & (n2 = i2.hasNext())) { // Really '&', not '&&'
0149:                        final int c = doCompare(((ReferenceIdentifier) i1
0150:                                .next()).getCode(), ((ReferenceIdentifier) i2
0151:                                .next()).getCode());
0152:                        // TODO: remove (ReferenceIdentifier) cast once we will be allowed to compile for J2SE 1.5.
0153:                        if (c != 0) {
0154:                            return c;
0155:                        }
0156:                    }
0157:                    if (n1)
0158:                        return +1;
0159:                    if (n2)
0160:                        return -1;
0161:                    return 0;
0162:                }
0163:
0164:                protected Object readResolve() throws ObjectStreamException {
0165:                    return IDENTIFIER_COMPARATOR;
0166:                }
0167:            }
0168:
0169:            /**
0170:             * A comparator for sorting identified objects by {@linkplain #getRemarks remarks}.
0171:             */
0172:            public static final Comparator REMARKS_COMPARATOR = new RemarksComparator();
0173:
0174:            private static final class RemarksComparator implements  Comparator,
0175:                    Serializable {
0176:                public int compare(final Object o1, final Object o2) {
0177:                    return doCompare(((IdentifiedObject) o1).getRemarks(),
0178:                            ((IdentifiedObject) o2).getRemarks());
0179:                }
0180:
0181:                protected Object readResolve() throws ObjectStreamException {
0182:                    return REMARKS_COMPARATOR;
0183:                }
0184:            }
0185:
0186:            /**
0187:             * The name for this object or code. Should never be {@code null}.
0188:             */
0189:            private final ReferenceIdentifier name;
0190:
0191:            /**
0192:             * An alternative name by which this object is identified.
0193:             */
0194:            private final Collection/*<GenericName>*/alias;
0195:
0196:            /**
0197:             * An identifier which references elsewhere the object's defining information.
0198:             * Alternatively an identifier by which this object can be referenced.
0199:             */
0200:            private final Set/*<ReferenceIdentifier>*/identifiers;
0201:
0202:            /**
0203:             * Comments on or information about this object, or {@code null} if none.
0204:             */
0205:            private final InternationalString remarks;
0206:
0207:            /**
0208:             * Constructs a new identified object with the same values than the specified one.
0209:             * This copy constructor provides a way to wrap an arbitrary implementation into a
0210:             * Geotools one or a user-defined one (as a subclass), usually in order to leverage
0211:             * some implementation-specific API. This constructor performs a shallow copy,
0212:             * i.e. the properties are not cloned.
0213:             */
0214:            public AbstractIdentifiedObject(final IdentifiedObject object) {
0215:                name = object.getName();
0216:                alias = object.getAlias();
0217:                identifiers = object.getIdentifiers();
0218:                remarks = object.getRemarks();
0219:            }
0220:
0221:            /**
0222:             * Constructs an object from a set of properties. Keys are strings from the table below.
0223:             * Key are case-insensitive, and leading and trailing spaces are ignored. The map given in
0224:             * argument shall contains at least a {@code "name"} property. Other properties listed
0225:             * in the table below are optional.
0226:             * <p>
0227:             * <table border='1'>
0228:             *   <tr bgcolor="#CCCCFF" class="TableHeadingColor">
0229:             *     <th nowrap>Property name</th>
0230:             *     <th nowrap>Value type</th>
0231:             *     <th nowrap>Value given to</th>
0232:             *   </tr>
0233:             *   <tr>
0234:             *     <td nowrap>&nbsp;{@link #NAME_KEY "name"}&nbsp;</td>
0235:             *     <td nowrap>&nbsp;{@link String} or {@link ReferenceIdentifier}&nbsp;</td>
0236:             *     <td nowrap>&nbsp;{@link #getName()}</td>
0237:             *   </tr>
0238:             *   <tr>
0239:             *     <td nowrap>&nbsp;{@link #ALIAS_KEY "alias"}&nbsp;</td>
0240:             *     <td nowrap>&nbsp;{@link String}, <code>{@linkplain String}[]</code>,
0241:             *     {@link GenericName} or <code>{@linkplain GenericName}[]</code>&nbsp;</td>
0242:             *     <td nowrap>&nbsp;{@link #getAlias}</td>
0243:             *   </tr>
0244:             *   <tr>
0245:             *     <td nowrap>&nbsp;{@link ReferenceIdentifier#AUTHORITY_KEY "authority"}&nbsp;</td>
0246:             *     <td nowrap>&nbsp;{@link String} or {@link Citation}&nbsp;</td>
0247:             *     <td nowrap>&nbsp;{@link ReferenceIdentifier#getAuthority} on the {@linkplain #getName() name}</td>
0248:             *   </tr>
0249:             *   <tr>
0250:             *     <td nowrap>&nbsp;{@link ReferenceIdentifier#CODESPACE_KEY "version"}&nbsp;</td>
0251:             *     <td nowrap>&nbsp;{@link String}&nbsp;</td>
0252:             *     <td nowrap>&nbsp;{@link ReferenceIdentifier#getCodeSpace} on the {@linkplain #getName() name}</td>
0253:             *   </tr>
0254:             *   <tr>
0255:             *     <td nowrap>&nbsp;{@link ReferenceIdentifier#VERSION_KEY "version"}&nbsp;</td>
0256:             *     <td nowrap>&nbsp;{@link String}&nbsp;</td>
0257:             *     <td nowrap>&nbsp;{@link ReferenceIdentifier#getVersion} on the {@linkplain #getName() name}</td>
0258:             *   </tr>
0259:             *   <tr>
0260:             *     <td nowrap>&nbsp;{@link #IDENTIFIERS_KEY "identifiers"}&nbsp;</td>
0261:             *     <td nowrap>&nbsp;{@link ReferenceIdentifier} or <code>{@linkplain ReferenceIdentifier}[]</code>&nbsp;</td>
0262:             *     <td nowrap>&nbsp;{@link #getIdentifiers}</td>
0263:             *   </tr>
0264:             *   <tr>
0265:             *     <td nowrap>&nbsp;{@link #REMARKS_KEY "remarks"}&nbsp;</td>
0266:             *     <td nowrap>&nbsp;{@link String} or {@link InternationalString}&nbsp;</td>
0267:             *     <td nowrap>&nbsp;{@link #getRemarks}</td>
0268:             *   </tr>
0269:             * </table>
0270:             * <P>
0271:             * Additionally, all localizable attributes like {@code "remarks"} may have a language and
0272:             * country code suffix. For example the {@code "remarks_fr"} property stands for remarks in
0273:             * {@linkplain java.util.Locale#FRENCH French} and the {@code "remarks_fr_CA"} property stands
0274:             * for remarks in {@linkplain java.util.Locale#CANADA_FRENCH French Canadian}.
0275:             * <P>
0276:             * Note that the {@code "authority"} and {@code "version"} properties are ignored if the
0277:             * {@code "name"} property is already a {@link Citation} object instead of a {@link String}.
0278:             *
0279:             * @throws InvalidParameterValueException if a property has an invalid value.
0280:             * @throws IllegalArgumentException if a property is invalid for some other reason.
0281:             */
0282:            public AbstractIdentifiedObject(final Map properties)
0283:                    throws IllegalArgumentException {
0284:                this (properties, null, null);
0285:            }
0286:
0287:            /**
0288:             * Constructs an object from a set of properties and copy unrecognized properties in the
0289:             * specified map. The {@code properties} argument is treated as in the {@linkplain
0290:             * AbstractIdentifiedObject#AbstractIdentifiedObject(Map) one argument constructor}. All
0291:             * properties unknow to this {@code AbstractIdentifiedObject} constructor are copied
0292:             * in the {@code subProperties} map, after their key has been normalized (usually
0293:             * lower case, leading and trailing space removed).
0294:             *
0295:             * <P>If {@code localizables} is non-null, then all keys listed in this argument are
0296:             * treated as localizable one (i.e. may have a suffix like "_fr", "_de", etc.). Localizable
0297:             * properties are stored in the {@code subProperties} map as {@link InternationalString}
0298:             * objects.</P>
0299:             *
0300:             * @param properties    Set of properties. Should contains at least {@code "name"}.
0301:             * @param subProperties The map in which to copy unrecognized properties.
0302:             * @param localizables  Optional list of localized properties.
0303:             *
0304:             * @throws InvalidParameterValueException if a property has an invalid value.
0305:             * @throws IllegalArgumentException if a property is invalid for some other reason.
0306:             */
0307:            protected AbstractIdentifiedObject(final Map properties,
0308:                    final Map subProperties, final String[] localizables)
0309:                    throws IllegalArgumentException {
0310:                ensureNonNull("properties", properties);
0311:                Object name = null;
0312:                Object alias = null;
0313:                Object identifiers = null;
0314:                Object remarks = null;
0315:                GrowableInternationalString growable = null;
0316:                GrowableInternationalString[] subGrowables = null;
0317:                /*
0318:                 * Iterate through each map entry. This have two purposes:
0319:                 *
0320:                 *   1) Ignore case (a call to properties.get("foo") can't do that)
0321:                 *   2) Find localized remarks.
0322:                 *
0323:                 * This algorithm is sub-optimal if the map contains a lot of entries of no interest to
0324:                 * this object. Hopefully, most users will fill a map only with usefull entries.
0325:                 */
0326:                NEXT_KEY: for (final Iterator it = properties.entrySet()
0327:                        .iterator(); it.hasNext();) {
0328:                    Map.Entry entry = (Map.Entry) it.next();
0329:                    String key = ((String) entry.getKey()).trim().toLowerCase();
0330:                    Object value = entry.getValue();
0331:                    /*
0332:                     * Note: String.hashCode() is part of J2SE specification,
0333:                     *       so it should not change across implementations.
0334:                     */
0335:                    switch (key.hashCode()) {
0336:                    // Fix case for common keywords. They are not used
0337:                    // by this class, but are used by some subclasses.
0338:                    case -1528693765:
0339:                        if (key.equalsIgnoreCase("anchorPoint"))
0340:                            key = "anchorPoint";
0341:                        break;
0342:                    case -1805658881:
0343:                        if (key.equalsIgnoreCase("bursaWolf"))
0344:                            key = "bursaWolf";
0345:                        break;
0346:                    case 109688209:
0347:                        if (key.equalsIgnoreCase("operationVersion"))
0348:                            key = "operationVersion";
0349:                        break;
0350:                    case 1479434472:
0351:                        if (key.equalsIgnoreCase("coordinateOperationAccuracy"))
0352:                            key = "coordinateOperationAccuracy";
0353:                        break;
0354:                    case 1126917133:
0355:                        if (key.equalsIgnoreCase("positionalAccuracy"))
0356:                            key = "positionalAccuracy";
0357:                        break;
0358:                    case 1127093059:
0359:                        if (key.equalsIgnoreCase("realizationEpoch"))
0360:                            key = "realizationEpoch";
0361:                        break;
0362:                    case 1790520781:
0363:                        if (key.equalsIgnoreCase("domainOfValidity"))
0364:                            key = "domainOfValidity";
0365:                        break;
0366:                    case -1109785975:
0367:                        if (key.equalsIgnoreCase("validArea"))
0368:                            key = "validArea";
0369:                        break;
0370:
0371:                    // -------------------------------------
0372:                    // "name": String or ReferenceIdentifier
0373:                    // -------------------------------------
0374:                    case 3373707: {
0375:                        if (key.equals(NAME_KEY)) {
0376:                            if (value instanceof  String) {
0377:                                name = new NamedIdentifier(properties, false);
0378:                                assert value.equals(((Identifier) name)
0379:                                        .getCode()) : name;
0380:                            } else {
0381:                                // Should be an instance of ReferenceIdentifier, but we don't check
0382:                                // here. The type will be checked at the end of this method, which
0383:                                // will thrown an exception with detailed message in case of mismatch.
0384:                                name = value;
0385:                            }
0386:                            continue NEXT_KEY;
0387:                        }
0388:                        break;
0389:                    }
0390:                        // -------------------------------------------------------
0391:                        // "alias": String, String[], GenericName or GenericName[]
0392:                        // -------------------------------------------------------
0393:                    case 92902992: {
0394:                        if (key.equals(ALIAS_KEY)) {
0395:                            alias = NameFactory.toArray(value);
0396:                            continue NEXT_KEY;
0397:                        }
0398:                        break;
0399:                    }
0400:                        // -----------------------------------------------------------
0401:                        // "identifiers": ReferenceIdentifier or ReferenceIdentifier[]
0402:                        // -----------------------------------------------------------
0403:                    case 1368189162: {
0404:                        if (key.equals(IDENTIFIERS_KEY)) {
0405:                            if (value != null) {
0406:                                if (value instanceof  ReferenceIdentifier) {
0407:                                    identifiers = new ReferenceIdentifier[] { (ReferenceIdentifier) value };
0408:                                } else {
0409:                                    identifiers = value;
0410:                                }
0411:                            }
0412:                            continue NEXT_KEY;
0413:                        }
0414:                        break;
0415:                    }
0416:                        // ----------------------------------------
0417:                        // "remarks": String or InternationalString
0418:                        // ----------------------------------------
0419:                    case 1091415283: {
0420:                        if (key.equals(REMARKS_KEY)) {
0421:                            if (value instanceof  InternationalString) {
0422:                                remarks = value;
0423:                                continue NEXT_KEY;
0424:                            }
0425:                        }
0426:                        break;
0427:                    }
0428:                    }
0429:                    /*
0430:                     * Search for additional locales for remarks (e.g. "remarks_fr").
0431:                     * 'growable.add(...)' will add the value only if the key starts
0432:                     * with the "remarks" prefix.
0433:                     */
0434:                    if (value instanceof  String) {
0435:                        if (growable == null) {
0436:                            if (remarks instanceof  GrowableInternationalString) {
0437:                                growable = (GrowableInternationalString) remarks;
0438:                            } else {
0439:                                growable = new GrowableInternationalString();
0440:                            }
0441:                        }
0442:                        if (growable.add(REMARKS_KEY, key, value.toString())) {
0443:                            continue NEXT_KEY;
0444:                        }
0445:                    }
0446:                    /*
0447:                     * Search for user-specified localizable properties.
0448:                     */
0449:                    if (subProperties == null) {
0450:                        continue NEXT_KEY;
0451:                    }
0452:                    if (localizables != null) {
0453:                        for (int i = 0; i < localizables.length; i++) {
0454:                            final String prefix = localizables[i];
0455:                            if (key.equals(prefix)) {
0456:                                if (value instanceof  InternationalString) {
0457:                                    // Stores the value in 'subProperties' after the loop.
0458:                                    break;
0459:                                }
0460:                            }
0461:                            if (value instanceof  String) {
0462:                                if (subGrowables == null) {
0463:                                    subGrowables = new GrowableInternationalString[localizables.length];
0464:                                }
0465:                                if (subGrowables[i] == null) {
0466:                                    final Object previous = subProperties
0467:                                            .get(prefix);
0468:                                    if (previous instanceof  GrowableInternationalString) {
0469:                                        subGrowables[i] = (GrowableInternationalString) previous;
0470:                                    } else {
0471:                                        subGrowables[i] = new GrowableInternationalString();
0472:                                    }
0473:                                }
0474:                                if (subGrowables[i].add(prefix, key, value
0475:                                        .toString())) {
0476:                                    continue NEXT_KEY;
0477:                                }
0478:                            }
0479:                        }
0480:                    }
0481:                    subProperties.put(key, value);
0482:                }
0483:                /*
0484:                 * Get the localized remarks, if it was not yet set. If a user specified remarks
0485:                 * both as InternationalString and as String for some locales (which is a weird
0486:                 * usage...), then current implementation discart the later with a warning.
0487:                 */
0488:                if (growable != null && !growable.getLocales().isEmpty()) {
0489:                    if (remarks == null) {
0490:                        remarks = growable;
0491:                    } else if (!growable.isSubsetOf(remarks)) {
0492:                        org.geotools.util.logging.Logging.getLogger(
0493:                                "org.geotools.referencing").log(
0494:                                Logging.format(Level.WARNING,
0495:                                        LoggingKeys.LOCALES_DISCARTED));
0496:                    }
0497:                }
0498:                /*
0499:                 * Get the localized user-defined properties.
0500:                 */
0501:                if (subProperties != null && subGrowables != null) {
0502:                    for (int i = 0; i < subGrowables.length; i++) {
0503:                        growable = subGrowables[i];
0504:                        if (growable != null
0505:                                && !growable.getLocales().isEmpty()) {
0506:                            final String prefix = localizables[i];
0507:                            final Object current = subProperties.get(prefix);
0508:                            if (current == null) {
0509:                                subProperties.put(prefix, growable);
0510:                            } else if (!growable.isSubsetOf(current)) {
0511:                                org.geotools.util.logging.Logging.getLogger(
0512:                                        "org.geotools.referencing").log(
0513:                                        Logging.format(Level.WARNING,
0514:                                                LoggingKeys.LOCALES_DISCARTED));
0515:                            }
0516:                        }
0517:                    }
0518:                }
0519:                /*
0520:                 * Stores the definitive reference to the attributes. Note that casts are performed only
0521:                 * there (not before). This is a wanted feature, since we want to catch ClassCastExceptions
0522:                 * are rethrown them as more informative exceptions.
0523:                 */
0524:                String key = null;
0525:                Object value = null;
0526:                try {
0527:                    key = NAME_KEY;
0528:                    this .name = (ReferenceIdentifier) (value = name);
0529:                    key = ALIAS_KEY;
0530:                    this .alias = asSet((GenericName[]) (value = alias));
0531:                    key = IDENTIFIERS_KEY;
0532:                    this .identifiers = asSet((ReferenceIdentifier[]) (value = identifiers));
0533:                    key = REMARKS_KEY;
0534:                    this .remarks = (InternationalString) (value = remarks);
0535:                } catch (ClassCastException exception) {
0536:                    InvalidParameterValueException e = new InvalidParameterValueException(
0537:                            Errors.format(ErrorKeys.ILLEGAL_ARGUMENT_$2, key,
0538:                                    value), key, value);
0539:                    e.initCause(exception);
0540:                    throw e;
0541:                }
0542:                ensureNonNull(NAME_KEY, name);
0543:                ensureNonNull(NAME_KEY, name.toString());
0544:            }
0545:
0546:            /**
0547:             * The primary name by which this object is identified.
0548:             *
0549:             * @see #getName(Citation)
0550:             */
0551:            public ReferenceIdentifier getName() {
0552:                return name;
0553:            }
0554:
0555:            /**
0556:             * An alternative name by which this object is identified.
0557:             *         
0558:             * @return The aliases, or an empty array if there is none.
0559:             *
0560:             * @see #getName(Citation)
0561:             */
0562:            public Collection/*<GenericName>*/getAlias() {
0563:                return (alias != null) ? alias : Collections.EMPTY_SET;
0564:            }
0565:
0566:            /**
0567:             * An identifier which references elsewhere the object's defining information.
0568:             * Alternatively an identifier by which this object can be referenced.
0569:             *
0570:             * @return This object identifiers, or an empty array if there is none.
0571:             *
0572:             * @see #getIdentifier(Citation)
0573:             */
0574:            public Set/*<ReferenceIdentifier>*/getIdentifiers() {
0575:                return (identifiers != null) ? identifiers
0576:                        : Collections.EMPTY_SET;
0577:            }
0578:
0579:            /**
0580:             * Comments on or information about this object, including data source information.
0581:             */
0582:            public InternationalString getRemarks() {
0583:                return remarks;
0584:            }
0585:
0586:            /**
0587:             * Returns the informations provided in the specified indentified object as a map of
0588:             * properties. The returned map contains key such as {@link #NAME_KEY NAME_KEY}, and
0589:             * values from methods such as {@link #getName}.
0590:             *
0591:             * @param  info The identified object to view as a properties map.
0592:             * @return An view of the identified object as an immutable map.
0593:             */
0594:            public static Map getProperties(final IdentifiedObject info) {
0595:                return new Properties(info);
0596:            }
0597:
0598:            /**
0599:             * Returns the properties to be given to an identified object derived from the specified one.
0600:             * This method is typically used for creating a new CRS identical to an existing one except
0601:             * for axis units. This method returns the same properties than the supplied argument (as of
0602:             * <code>{@linkplain #getProperties(IdentifiedObject) getProperties}(info)</code>), except for
0603:             * the following:
0604:             * <p>
0605:             * <ul>
0606:             *   <li>The {@linkplain #getName() name}'s authority is replaced by the specified one.</li>
0607:             *   <li>All {@linkplain #getIdentifiers identifiers} are removed, because the new object
0608:             *       to be created is probably not endorsed by the original authority.</li>
0609:             * </ul>
0610:             * <p>
0611:             * This method returns a mutable map. Consequently, callers can add their own identifiers
0612:             * directly to this map if they wish.
0613:             *
0614:             * @param  info The identified object to view as a properties map.
0615:             * @param  authority The new authority for the object to be created, or {@code null} if it
0616:             *         is not going to have any declared authority.
0617:             * @return An view of the identified object as a mutable map.
0618:             */
0619:            public static Map getProperties(final IdentifiedObject info,
0620:                    final Citation authority) {
0621:                final Map properties = new HashMap(getProperties(info));
0622:                properties.put(NAME_KEY, new NamedIdentifier(authority, info
0623:                        .getName().getCode()));
0624:                properties.remove(IDENTIFIERS_KEY);
0625:                return properties;
0626:            }
0627:
0628:            /**
0629:             * Returns an identifier according the given authority. This method first checks all
0630:             * {@linkplain #getIdentifiers identifiers} in their iteration order. It returns the first
0631:             * identifier with an {@linkplain ReferenceIdentifier#getAuthority authority} citation
0632:             * {@linkplain Citations#identifierMatches(Citation,Citation) matching} the specified
0633:             * authority.
0634:             *
0635:             * @param  authority The authority for the identifier to return, or {@code null} for
0636:             *         the first identifier regarless its authority.
0637:             * @return The object's identifier, or {@code null} if no identifier matching the specified
0638:             *         authority was found.
0639:             *
0640:             * @since 2.2
0641:             */
0642:            public ReferenceIdentifier getIdentifier(final Citation authority) {
0643:                return getIdentifier0(this , authority);
0644:            }
0645:
0646:            /**
0647:             * Returns an identifier according the given authority. This method performs the same search
0648:             * than {@link #getIdentifier(Citation)} on arbitrary implementations of GeoAPI interface.
0649:             *
0650:             * @param  info The object to get the identifier from.
0651:             * @param  authority The authority for the identifier to return, or {@code null} for
0652:             *         the first identifier regarless its authority.
0653:             * @return The object's identifier, or {@code null} if no identifier matching the specified
0654:             *         authority was found.
0655:             *
0656:             * @since 2.2
0657:             */
0658:            public static ReferenceIdentifier getIdentifier(
0659:                    final IdentifiedObject info, final Citation authority) {
0660:                if (info instanceof  AbstractIdentifiedObject) {
0661:                    // Gives a chances to subclasses to get their overridden method invoked.
0662:                    return ((AbstractIdentifiedObject) info)
0663:                            .getIdentifier(authority);
0664:                }
0665:                return getIdentifier0(info, authority);
0666:            }
0667:
0668:            /**
0669:             * Implementation of {@link #getIdentifier(Citation)}.
0670:             */
0671:            private static ReferenceIdentifier getIdentifier0(
0672:                    final IdentifiedObject info, final Citation authority) {
0673:                if (info == null) {
0674:                    return null;
0675:                }
0676:                for (final Iterator it = info.getIdentifiers().iterator(); it
0677:                        .hasNext();) {
0678:                    final Identifier candidate = (Identifier) it.next();
0679:                    if (candidate instanceof  ReferenceIdentifier) {
0680:                        final ReferenceIdentifier identifier = (ReferenceIdentifier) candidate;
0681:                        if (authority == null) {
0682:                            return identifier;
0683:                        }
0684:                        final Citation infoAuthority = identifier
0685:                                .getAuthority();
0686:                        if (infoAuthority != null) {
0687:                            if (Citations.identifierMatches(authority,
0688:                                    infoAuthority)) {
0689:                                return identifier;
0690:                            }
0691:                        }
0692:                    }
0693:                }
0694:                return (authority == null) ? info.getName() : null;
0695:            }
0696:
0697:            /**
0698:             * Returns this object's name according the given authority. This method checks first the
0699:             * {@linkplain #getName() primary name}, then all {@linkplain #getAlias() alias} in their
0700:             * iteration order.
0701:             *
0702:             * <ul>
0703:             *   <li><p>If the name or alias implements the {@link ReferenceIdentifier} interface,
0704:             *       then this method compares the {@linkplain ReferenceIdentifier#getAuthority
0705:             *       identifier authority} against the specified citation using the
0706:             *       {@link Citations#identifierMatches(Citation,Citation) identifierMatches}
0707:             *       method. If a matching is found, then this method returns the
0708:             *       {@linkplain ReferenceIdentifier#getCode identifier code} of this object.</p></li>
0709:             *
0710:             *   <li><p>Otherwise, if the alias implements the {@link GenericName} interface, then this
0711:             *       method compares the {@linkplain GenericName#getScope name scope} against the specified
0712:             *       citation using the {@linkplain Citations#identifierMatches(Citation,String)
0713:             *       identifierMatches} method. If a matching is found, then this method returns the
0714:             *       {@linkplain GenericName#asLocalName local name} of this object.</p></li>
0715:             * </ul>
0716:             *
0717:             * Note that alias may implement both the {@link ReferenceIdentifier} and {@link GenericName}
0718:             * interfaces (for example {@link NamedIdentifier}). In such cases, the identifier view has
0719:             * precedence.
0720:             *
0721:             * @param  authority The authority for the name to return.
0722:             * @return The object's name (either a {@linkplain ReferenceIdentifier#getCode code}
0723:             *         or a {@linkplain GenericName#asLocalName local name}), or {@code null} if
0724:             *         no name matching the specified authority was found.
0725:             *
0726:             * @see #getName()
0727:             * @see #getAlias()
0728:             *
0729:             * @since 2.2
0730:             */
0731:            public String getName(final Citation authority) {
0732:                return getName0(this , authority);
0733:            }
0734:
0735:            /**
0736:             * Returns an object's name according the given authority. This method performs the same search
0737:             * than {@link #getName(Citation)} on arbitrary implementations of GeoAPI interface.
0738:             *
0739:             * @param  info The object to get the name from.
0740:             * @param  authority The authority for the name to return.
0741:             * @return The object's name (either a {@linkplain ReferenceIdentifier#getCode code}
0742:             *         or a {@linkplain GenericName#asLocalName local name}), or {@code null} if
0743:             *         no name matching the specified authority was found.
0744:             *
0745:             * @since 2.2
0746:             */
0747:            public static String getName(final IdentifiedObject info,
0748:                    final Citation authority) {
0749:                if (info instanceof  AbstractIdentifiedObject) {
0750:                    // Gives a chances to subclasses to get their overridden method invoked.
0751:                    return ((AbstractIdentifiedObject) info).getName(authority);
0752:                }
0753:                return getName0(info, authority);
0754:            }
0755:
0756:            /**
0757:             * Implementation of {@link #getName(Citation)}.
0758:             */
0759:            private static String getName0(final IdentifiedObject info,
0760:                    final Citation authority) {
0761:                Identifier identifier = info.getName();
0762:                if (authority == null) {
0763:                    return identifier.getCode();
0764:                }
0765:                String name = null;
0766:                Citation infoAuthority = identifier.getAuthority();
0767:                if (infoAuthority != null) {
0768:                    if (Citations.identifierMatches(authority, infoAuthority)) {
0769:                        name = identifier.getCode();
0770:                    } else {
0771:                        for (final Iterator it = info.getAlias().iterator(); it
0772:                                .hasNext();) {
0773:                            final GenericName alias = (GenericName) it.next();
0774:                            if (alias instanceof  Identifier) {
0775:                                identifier = (Identifier) alias;
0776:                                infoAuthority = identifier.getAuthority();
0777:                                if (infoAuthority != null) {
0778:                                    if (Citations.identifierMatches(authority,
0779:                                            infoAuthority)) {
0780:                                        name = identifier.getCode();
0781:                                        break;
0782:                                    }
0783:                                }
0784:                            } else {
0785:                                final GenericName scope = alias.getScope();
0786:                                if (scope != null) {
0787:                                    if (Citations.identifierMatches(authority,
0788:                                            scope.toString())) {
0789:                                        name = alias.asLocalName().toString();
0790:                                        break;
0791:                                    }
0792:                                }
0793:                            }
0794:                        }
0795:                    }
0796:                }
0797:                return name;
0798:            }
0799:
0800:            /**
0801:             * Returns {@code true} if either the {@linkplain #getName() primary name} or at least
0802:             * one {@linkplain #getAlias alias} matches the specified string. This method performs
0803:             * the search in the following order, regardless of any authority:
0804:             * <ul>
0805:             *   <li>The {@linkplain #getName() primary name} of this object</li>
0806:             *   <li>The {@linkplain ScopedName fully qualified name} of an alias</li>
0807:             *   <li>The {@linkplain LocalName local name} of an alias</li>
0808:             * </ul>
0809:             *
0810:             * @param  name The name to compare.
0811:             * @return {@code true} if the primary name of at least one alias
0812:             *         matches the specified {@code name}.
0813:             */
0814:            public boolean nameMatches(final String name) {
0815:                return nameMatches(this , alias, name);
0816:            }
0817:
0818:            /**
0819:             * Returns {@code true} if either the {@linkplain #getName() primary name} or at least
0820:             * one {@linkplain #getAlias alias} matches the specified string. This method performs the
0821:             * same check than the {@linkplain #nameMatches(String) non-static method} on arbitrary
0822:             * object implementing the GeoAPI interface.
0823:             *
0824:             * @param  object The object to check.
0825:             * @param  name The name.
0826:             * @return {@code true} if the primary name of at least one alias
0827:             *         matches the specified {@code name}.
0828:             */
0829:            public static boolean nameMatches(final IdentifiedObject object,
0830:                    final String name) {
0831:                if (object instanceof  AbstractIdentifiedObject) {
0832:                    return ((AbstractIdentifiedObject) object)
0833:                            .nameMatches(name);
0834:                } else {
0835:                    return nameMatches(object, object.getAlias(), name);
0836:                }
0837:            }
0838:
0839:            /**
0840:             * Returns {@code true} if the {@linkplain #getName() primary name} of an object matches
0841:             * the primary name of one {@linkplain #getAlias alias} of the other object.
0842:             *
0843:             * @param o1 The first object to compare by name.
0844:             * @param o2 The second object to compare by name.
0845:             *
0846:             * @since 2.4
0847:             */
0848:            public static boolean nameMatches(final IdentifiedObject o1,
0849:                    final IdentifiedObject o2) {
0850:                return nameMatches(o1, o2.getName().getCode())
0851:                        || nameMatches(o2, o1.getName().getCode());
0852:            }
0853:
0854:            /**
0855:             * Implementation of {@code nameMatches} method.
0856:             *
0857:             * @param  object The object to check.
0858:             * @param  alias  The list of alias in {@code object} (may be {@code null}).
0859:             *                This method will never modify this list. Consequently, it may be a
0860:             *                direct reference to an internal array.
0861:             * @param  name The name.
0862:             * @return {@code true} if the primary name of at least one alias
0863:             *         matches the specified {@code name}.
0864:             */
0865:            private static boolean nameMatches(final IdentifiedObject object,
0866:                    final Collection/*<GenericName>*/alias, String name) {
0867:                name = name.trim();
0868:                if (name.equalsIgnoreCase(object.getName().getCode().trim())) {
0869:                    return true;
0870:                }
0871:                if (alias != null) {
0872:                    for (final Iterator it = alias.iterator(); it.hasNext();) {
0873:                        final GenericName asName = (GenericName) it.next();
0874:                        final ScopedName asScoped = asName.asScopedName();
0875:                        if (asScoped != null
0876:                                && name.equalsIgnoreCase(asScoped.toString()
0877:                                        .trim())) {
0878:                            return true;
0879:                        }
0880:                        if (name.equalsIgnoreCase(asName.asLocalName()
0881:                                .toString().trim())) {
0882:                            return true;
0883:                        }
0884:                    }
0885:                }
0886:                return false;
0887:            }
0888:
0889:            /**
0890:             * Compares the specified object with this object for equality.
0891:             *
0892:             * @param  object The other object (may be {@code null}).
0893:             * @return {@code true} if both objects are equal.
0894:             */
0895:            public final boolean equals(final Object object) {
0896:                return (object instanceof  AbstractIdentifiedObject)
0897:                        && equals((AbstractIdentifiedObject) object, true);
0898:            }
0899:
0900:            /**
0901:             * Compares this object with the specified object for equality.
0902:             *
0903:             * If {@code compareMetadata} is {@code true}, then all available properties are
0904:             * compared including {@linkplain #getName() name}, {@linkplain #getRemarks remarks},
0905:             * {@linkplain #getIdentifiers identifiers code}, etc.
0906:             *
0907:             * If {@code compareMetadata} is {@code false}, then this method compare
0908:             * only the properties needed for computing transformations. In other words,
0909:             * {@code sourceCS.equals(targetCS, false)} returns {@code true} only if
0910:             * the transformation from {@code sourceCS} to {@code targetCS} is
0911:             * the identity transform, no matter what {@link #getName()} saids.
0912:             * <P>
0913:             * Some subclasses (especially {@link org.geotools.referencing.datum.AbstractDatum}
0914:             * and {@link org.geotools.parameter.AbstractParameterDescriptor}) will test for the
0915:             * {@linkplain #getName() name}, since objects with different name have completly
0916:             * different meaning. For example nothing differentiate the {@code "semi_major"} and
0917:             * {@code "semi_minor"} parameters except the name. The name comparaison may be loose
0918:             * however, i.e. we may accept a name matching an alias.
0919:             *
0920:             * @param  object The object to compare to {@code this}.
0921:             * @param  compareMetadata {@code true} for performing a strict comparaison, or
0922:             *         {@code false} for comparing only properties relevant to transformations.
0923:             * @return {@code true} if both objects are equal.
0924:             */
0925:            public boolean equals(final AbstractIdentifiedObject object,
0926:                    final boolean compareMetadata) {
0927:                if (object != null && object.getClass().equals(getClass())) {
0928:                    if (!compareMetadata) {
0929:                        return true;
0930:                    }
0931:                    return Utilities.equals(name, object.name)
0932:                            && Utilities.equals(alias, object.alias)
0933:                            && Utilities
0934:                                    .equals(identifiers, object.identifiers)
0935:                            && Utilities.equals(remarks, object.remarks);
0936:                }
0937:                return false;
0938:            }
0939:
0940:            /**
0941:             * Compares two Geotools's {@code AbstractIdentifiedObject} objects for equality. This
0942:             * method is equivalent to {@code object1.<b>equals</b>(object2, <var>compareMetadata</var>)}
0943:             * except that one or both arguments may be null. This convenience method is provided for
0944:             * implementation of {@code equals} in subclasses.
0945:             *
0946:             * @param  object1 The first object to compare (may be {@code null}).
0947:             * @param  object2 The second object to compare (may be {@code null}).
0948:             * @param  compareMetadata {@code true} for performing a strict comparaison, or
0949:             *         {@code false} for comparing only properties relevant to transformations.
0950:             * @return {@code true} if both objects are equal.
0951:             */
0952:            static boolean equals(final AbstractIdentifiedObject object1,
0953:                    final AbstractIdentifiedObject object2,
0954:                    final boolean compareMetadata) {
0955:                return (object1 == object2)
0956:                        || (object1 != null && object1.equals(object2,
0957:                                compareMetadata));
0958:            }
0959:
0960:            /**
0961:             * Compares two OpenGIS's {@code IdentifiedObject} objects for equality. This convenience
0962:             * method is provided for implementation of {@code equals} in subclasses.
0963:             *
0964:             * @param  object1 The first object to compare (may be {@code null}).
0965:             * @param  object2 The second object to compare (may be {@code null}).
0966:             * @param  compareMetadata {@code true} for performing a strict comparaison, or
0967:             *         {@code false} for comparing only properties relevant to transformations.
0968:             * @return {@code true} if both objects are equal.
0969:             */
0970:            protected static boolean equals(final IdentifiedObject object1,
0971:                    final IdentifiedObject object2,
0972:                    final boolean compareMetadata) {
0973:                if (!(object1 instanceof  AbstractIdentifiedObject))
0974:                    return Utilities.equals(object1, object2);
0975:                if (!(object2 instanceof  AbstractIdentifiedObject))
0976:                    return Utilities.equals(object2, object1);
0977:                return equals((AbstractIdentifiedObject) object1,
0978:                        (AbstractIdentifiedObject) object2, compareMetadata);
0979:            }
0980:
0981:            /**
0982:             * Compares two arrays of OpenGIS's {@code IdentifiedObject} objects for equality. This
0983:             * convenience method is provided for implementation of {@code equals} method in subclasses.
0984:             *
0985:             * @param  array1 The first array to compare (may be {@code null}).
0986:             * @param  array2 The second array to compare (may be {@code null}).
0987:             * @param  compareMetadata {@code true} for performing a strict comparaison, or
0988:             *         {@code false} for comparing only properties relevant to transformations.
0989:             * @return {@code true} if both arrays are equal.
0990:             */
0991:            protected static boolean equals(final IdentifiedObject[] array1,
0992:                    final IdentifiedObject[] array2,
0993:                    final boolean compareMetadata) {
0994:                if (array1 != array2) {
0995:                    if (array1 == null || array2 == null
0996:                            || array1.length != array2.length) {
0997:                        return false;
0998:                    }
0999:                    for (int i = array1.length; --i >= 0;) {
1000:                        if (!equals(array1[i], array2[i], compareMetadata)) {
1001:                            return false;
1002:                        }
1003:                    }
1004:                }
1005:                return true;
1006:            }
1007:
1008:            /**
1009:             * Compares two collectionss of OpenGIS's {@code IdentifiedObject} objects for equality.
1010:             * The comparaison take order in account, which make it more appropriate for {@link List}
1011:             * or {@link LinkedHashSet} comparaisons. This convenience method is provided for
1012:             * implementation of {@code equals} method in subclasses.
1013:             *
1014:             * @param  collection1 The first collection to compare (may be {@code null}).
1015:             * @param  collection2 The second collection to compare (may be {@code null}).
1016:             * @param  compareMetadata {@code true} for performing a strict comparaison, or
1017:             *         {@code false} for comparing only properties relevant to transformations.
1018:             * @return {@code true} if both collections are equal.
1019:             */
1020:            protected static boolean equals(
1021:                    final Collection/*<? extends IdentifiedObject>*/collection1,
1022:                    final Collection/*<? extends IdentifiedObject>*/collection2,
1023:                    final boolean compareMetadata) {
1024:                if (collection1 == collection2) {
1025:                    return true;
1026:                }
1027:                if (collection1 == null || collection2 == null) {
1028:                    return false;
1029:                }
1030:                final Iterator it1 = collection1.iterator();
1031:                final Iterator it2 = collection2.iterator();
1032:                while (it1.hasNext()) {
1033:                    if (!it2.hasNext()
1034:                            || !equals((IdentifiedObject) it1.next(),
1035:                                    (IdentifiedObject) it2.next(),
1036:                                    compareMetadata)) {
1037:                        return false;
1038:                    }
1039:                }
1040:                return !it2.hasNext();
1041:            }
1042:
1043:            /**
1044:             * Compares two objects for order. Any object may be null. This method is
1045:             * used for implementation of {@link #NAME_COMPARATOR} and its friends.
1046:             */
1047:            private static int doCompare(final Comparable c1,
1048:                    final Comparable c2) {
1049:                if (c1 == null) {
1050:                    return (c2 == null) ? 0 : -1;
1051:                }
1052:                if (c2 == null) {
1053:                    return +1;
1054:                }
1055:                return c1.compareTo(c2);
1056:            }
1057:
1058:            /**
1059:             * Returns a hash value for this identified object. {@linkplain #getName() Name},
1060:             * {@linkplain #getIdentifiers identifiers} and {@linkplain #getRemarks remarks}
1061:             * are not taken in account. In other words, two identified objects will return
1062:             * the same hash value if they are equal in the sense of <code>{@linkplain
1063:             * #equals(AbstractIdentifiedObject,boolean) equals}(AbstractIdentifiedObject,
1064:             * <strong>false</strong>)</code>.
1065:             *
1066:             * @return The hash code value. This value doesn't need to be the same
1067:             *         in past or future versions of this class.
1068:             */
1069:            public int hashCode() {
1070:                // Subclasses need to overrides this!!!!
1071:                return (int) serialVersionUID ^ getClass().hashCode();
1072:            }
1073:
1074:            /**
1075:             * Returns the specified array as an immutable set, or {@code null} if the
1076:             * array is empty or null. This is a convenience method for sub-classes
1077:             * constructors.
1078:             *
1079:             * @param  array The array to copy in a set. May be {@code null}.
1080:             * @return A set containing the array elements, or {@code null} if none or empty.
1081:             */
1082:            protected static Set asSet(final Object[] array) {
1083:                if (array == null) {
1084:                    return null;
1085:                }
1086:                switch (array.length) {
1087:                case 0:
1088:                    return null;
1089:                case 1:
1090:                    return Collections.singleton(array[0]);
1091:                default:
1092:                    return Collections.unmodifiableSet(new LinkedHashSet(Arrays
1093:                            .asList(array)));
1094:                }
1095:
1096:            }
1097:
1098:            /**
1099:             * Makes sure that an argument is non-null. This is a
1100:             * convenience method for subclass constructors.
1101:             *
1102:             * @param  name   Argument name.
1103:             * @param  object User argument.
1104:             * @throws InvalidParameterValueException if {@code object} is null.
1105:             */
1106:            protected static void ensureNonNull(final String name,
1107:                    final Object object) throws IllegalArgumentException {
1108:                if (object == null) {
1109:                    throw new InvalidParameterValueException(Errors.format(
1110:                            ErrorKeys.NULL_ARGUMENT_$1, name), name, object);
1111:                }
1112:            }
1113:
1114:            /**
1115:             * Makes sure an array element is non-null. This is
1116:             * a convenience method for subclass constructors.
1117:             *
1118:             * @param  name  Argument name.
1119:             * @param  array User argument.
1120:             * @param  index Index of the element to check.
1121:             * @throws InvalidParameterValueException if {@code array[i]} is null.
1122:             */
1123:            protected static void ensureNonNull(final String name,
1124:                    final Object[] array, final int index)
1125:                    throws IllegalArgumentException {
1126:                if (array[index] == null) {
1127:                    throw new InvalidParameterValueException(Errors.format(
1128:                            ErrorKeys.NULL_ARGUMENT_$1, name + '[' + index
1129:                                    + ']'), name, array);
1130:                }
1131:            }
1132:
1133:            /**
1134:             * Makes sure that the specified unit is a temporal one.
1135:             * This is a convenience method for subclass constructors.
1136:             *
1137:             * @param  unit Unit to check.
1138:             * @throws IllegalArgumentException if {@code unit} is not a temporal unit.
1139:             */
1140:            protected static void ensureTimeUnit(final Unit unit)
1141:                    throws IllegalArgumentException {
1142:                if (!SI.SECOND.isCompatible(unit)) {
1143:                    throw new IllegalArgumentException(Errors.format(
1144:                            ErrorKeys.NON_TEMPORAL_UNIT_$1, unit));
1145:                }
1146:            }
1147:
1148:            /**
1149:             * Makes sure that the specified unit is a linear one.
1150:             * This is a convenience method for subclass constructors.
1151:             *
1152:             * @param  unit Unit to check.
1153:             * @throws IllegalArgumentException if {@code unit} is not a linear unit.
1154:             */
1155:            protected static void ensureLinearUnit(final Unit unit)
1156:                    throws IllegalArgumentException {
1157:                if (!SI.METER.isCompatible(unit)) {
1158:                    throw new IllegalArgumentException(Errors.format(
1159:                            ErrorKeys.NON_LINEAR_UNIT_$1, unit));
1160:                }
1161:            }
1162:
1163:            /**
1164:             * Makes sure that the specified unit is an angular one.
1165:             * This is a convenience method for subclass constructors.
1166:             *
1167:             * @param  unit Unit to check.
1168:             * @throws IllegalArgumentException if {@code unit} is not an angular unit.
1169:             */
1170:            protected static void ensureAngularUnit(final Unit unit)
1171:                    throws IllegalArgumentException {
1172:                if (!SI.RADIAN.isCompatible(unit) && !Unit.ONE.equals(unit)) {
1173:                    throw new IllegalArgumentException(Errors.format(
1174:                            ErrorKeys.NON_ANGULAR_UNIT_$1, unit));
1175:                }
1176:            }
1177:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.