001/*
002 *    GeoAPI - Java interfaces for OGC/ISO standards
003 *    Copyright © 2004-2024 Open Geospatial Consortium, Inc.
004 *    http://www.geoapi.org
005 *
006 *    Licensed under the Apache License, Version 2.0 (the "License");
007 *    you may not use this file except in compliance with the License.
008 *    You may obtain a copy of the License at
009 *
010 *        http://www.apache.org/licenses/LICENSE-2.0
011 *
012 *    Unless required by applicable law or agreed to in writing, software
013 *    distributed under the License is distributed on an "AS IS" BASIS,
014 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 *    See the License for the specific language governing permissions and
016 *    limitations under the License.
017 */
018package org.opengis.util;
019
020import java.util.List;
021import org.opengis.annotation.UML;
022import org.opengis.annotation.Classifier;
023import org.opengis.annotation.Stereotype;
024
025import static org.opengis.annotation.Obligation.*;
026import static org.opengis.annotation.Specification.*;
027
028
029/**
030 * A sequence of identifiers rooted within the context of a {@linkplain NameSpace namespace}.
031 * The job of a "name" is to associate that name with an {@link java.lang.Object}.
032 * For example, {@code GenericName} instances could be keys in a {@link java.util.HashMap},
033 * in which case the namespace is materialized by the {@code HashMap}.
034 * Names are often used in the context of reading data from various formats such as XML, shapefiles or netCDF,
035 * which have different constraints for names in their namespaces. When reading data from a file,
036 * names are often used for identifying attributes in records. In such case, specialized types are used:
037 *
038 * <ul>
039 *   <li>{@link TypeName} is the name of a {@link RecordType}.</li>
040 *   <li>{@link MemberName} is the name of an attribute in a {@link Record} or {@link RecordType}.</li>
041 * </ul>
042 *
043 * Names can be {@linkplain #toFullyQualifiedName() fully qualified} (e.g. {@code "urn:ogc:def:crs:EPSG::4326"}) or
044 * relative to a {@linkplain #scope() scope} (e.g. {@code "EPSG::4326"} in the {@code "urn:ogc:def:crs"} namespace).
045 * All names have the ability to provide a {@linkplain #getParsedNames() parsed} version of themselves.
046 * In the following illustration, each line is one possible construction for {@code "urn:crs:epsg:4326"}
047 * (taken as an abridged form of above URN for this example only). For each construction:
048 *
049 * <ul>
050 *   <li>the part without colored background is the {@link #scope()} and is invisible to all other methods
051 *       except {@code toFullyQualifiedName()};</li>
052 *   <li>the first column shows the visible part of the name in a green background;</li>
053 *   <li>the second and third columns show the
054 *       ({@linkplain #head() head}:{@linkplain ScopedName#tail() tail}) and
055 *       ({@linkplain ScopedName#path() path}:{@linkplain #tip() tip}) components, respectively.</li>
056 * </ul>
057 *
058 * <blockquote>
059 * <table class="ogc" style="margin-top:21px; margin-bottom:45px; border-spacing:40px 0">
060 *   <caption>Various representations of a generic name</caption>
061 *   <tr>
062 *     <th style="background-color:inherit">scope:<span style="background:LawnGreen">name</span></th>
063 *     <th style="background-color:inherit"><span style="background:LightSkyBlue">head</span>:<span style="background:Yellow">tail</span></th>
064 *     <th style="background-color:inherit"><span style="background:LightSkyBlue">path</span>:<span style="background:Yellow">tip</span></th>
065 *     <th style="background-color:inherit">Type</th>
066 *   </tr><tr>
067 *     <td><code><span style="background:LawnGreen">urn:crs:epsg:4326</span></code></td>
068 *     <td><code><span style="background:LightSkyBlue">urn:</span><span style="background:Yellow">crs:epsg:4326</span></code></td>
069 *     <td><code><span style="background:LightSkyBlue">urn:crs:epsg:</span><span style="background:Yellow">4326</span></code></td>
070 *     <td>{@link org.opengis.util.ScopedName} with {@linkplain org.opengis.util.NameSpace#isGlobal() global namespace}</td>
071 *   </tr><tr>
072 *     <td><code>urn:<span style="background:LawnGreen">crs:epsg:4326</span></code></td>
073 *     <td><code>urn:<span style="background:LightSkyBlue">crs:</span><span style="background:Yellow">epsg:4326</span></code></td>
074 *     <td><code>urn:<span style="background:LightSkyBlue">crs:epsg:</span><span style="background:Yellow">4326</span></code></td>
075 *     <td>{@link org.opengis.util.ScopedName}</td>
076 *   </tr><tr>
077 *     <td><code>urn:crs:<span style="background:LawnGreen">epsg:4326</span></code></td>
078 *     <td><code>urn:crs:<span style="background:LightSkyBlue">epsg:</span><span style="background:Yellow">4326</span></code></td>
079 *     <td><code>urn:crs:<span style="background:LightSkyBlue">epsg:</span><span style="background:Yellow">4326</span></code></td>
080 *     <td>{@link org.opengis.util.ScopedName}</td>
081 *   </tr><tr>
082 *     <td><code>urn:crs:epsg:<span style="background:LawnGreen">4326</span></code></td>
083 *     <td><code>urn:crs:epsg:<span style="background:LightSkyBlue">4326</span></code></td>
084 *     <td><code>urn:crs:epsg:<span style="background:Yellow">4326</span></code></td>
085 *     <td>{@link org.opengis.util.LocalName}</td>
086 *   </tr>
087 * </table>
088 * </blockquote>
089 *
090 * <h2>Comparison with files in a filesystem</h2>
091 * This {@code GenericName} interface is similar to a file path in a file system relative to a default directory.
092 * It can be compared to the standard {@link java.nio.file.Path} interface in the JDK:
093 *
094 * <blockquote><table class="ogc" style="white-space: nowrap">
095 *   <caption>Equivalence between {@code GenericName} and {@code java.nio.file.Path}</caption>
096 *   <tr>
097 *     <th>GeoAPI {@code Name} method</th>
098 *     <th>Equivalent Java I/O method</th>
099 *   </tr><tr>
100 *     <td>{@link #scope()}</td>
101 *     <td>Default directory</td>
102 *   </tr><tr>
103 *     <td>{@link ScopedName#path()}</td>
104 *     <td>{@link java.nio.file.Path#getParent() Path.getParent()}</td>
105 *   </tr><tr>
106 *     <td>{@link #tip()}</td>
107 *     <td>{@link java.nio.file.Path#getFileName() Path.getFileName()}</td>
108 *   </tr><tr>
109 *     <td>{@link #toFullyQualifiedName()}</td>
110 *     <td>{@link java.nio.file.Path#toAbsolutePath() Path.toAbsolutePath()}</td>
111 *   </tr><tr>
112 *     <td>{@link #depth()}</td>
113 *     <td>{@link java.nio.file.Path#getNameCount() Path.getNameCount()}</td>
114 *   </tr><tr>
115 *     <td>{@link #getParsedNames()}</td>
116 *     <td>{@link java.nio.file.Path#iterator() Path.iterator()}</td>
117 *   </tr><tr>
118 *     <td>{@link #compareTo(GenericName)}</td>
119 *     <td>{@link java.nio.file.Path#compareTo Path.compareTo(Path)}</td>
120 *   </tr><tr>
121 *     <td>{@link #toString()}</td>
122 *     <td>{@link java.nio.file.Path#toString() Path.toString()}</td>
123 *   </tr>
124 * </table></blockquote>
125 *
126 * <h2>Comparison with Java Content Repository (JCR) names</h2>
127 * In the Java standard {@link javax.xml.namespace.QName} class and in the Java Content Repository (JCR) specification,
128 * a name is an ordered pair of (<var>Name space</var>, <var>Local part</var>) strings. A JCR name can take two lexical
129 * forms: <dfn>expanded form</dfn> and <dfn>qualified form</dfn>. Those names are defined as:
130 *
131 * <blockquote><table class="ogc" style="white-space: nowrap">
132 *   <caption>Equivalence between JCR name and {@code GenericName}</caption>
133 *   <tr>
134 *     <th>JCR name definition</th>
135 *     <th class="sep" colspan="2">GeoAPI equivalence</th>
136 *   </tr><tr>
137 *     <td><code>ExpandedName ::= '{' Namespace '}' LocalPart</code></td>
138 *     <td class="sep"><code>GenericName.{@linkplain #scope() scope()}.name().toString()</code></td>
139 *     <td>= JCR {@code Namespace}</td>
140 *   </tr><tr>
141 *     <td></td>
142 *     <td class="sep"><code>GenericName.{@linkplain #toString() toString()}</code></td>
143 *     <td>= JCR {@code LocalPart}</td>
144 *   </tr><tr>
145 *     <td class="hsep"><code>QualifiedName ::= [Prefix ':'] LocalPart</code></td>
146 *     <td class="hsep sep"><code>ScopedName.{@linkplain #scope() scope()}</code></td>
147 *     <td class="hsep">= {@linkplain NameSpace#isGlobal() global namespace}</td>
148 *   </tr><tr>
149 *     <td></td>
150 *     <td class="sep"><code>ScopedName.{@linkplain ScopedName#head() head()}.toString()</code></td>
151 *     <td>= JCR {@code Prefix}</td>
152 *   </tr><tr>
153 *     <td></td>
154 *     <td class="sep"><code>ScopedName.{@linkplain ScopedName#tail() tail()}.toString()</code></td>
155 *     <td>= JCR {@code LocalPart}</td>
156 *   </tr>
157 * </table></blockquote>
158 *
159 * @author  Martin Desruisseaux (IRD)
160 * @author  Bryce Nordgren (USDA)
161 * @version 3.0
162 * @since   1.0
163 *
164 * @see javax.naming.Name
165 * @see NameFactory#createGenericName(NameSpace, CharSequence[])
166 * @see NameFactory#parseGenericName(NameSpace, CharSequence)
167 */
168@Classifier(Stereotype.ABSTRACT)                            // This is said in the text (not the UML) of ISO 19103.
169@UML(identifier="GenericName", specification=ISO_19103)
170public interface GenericName extends Comparable<GenericName> {
171    /**
172     * Returns the scope (name space) in which this name is local.
173     * All names carry an association with their scope in which they are considered local,
174     * but the scope can be the {@linkplain NameSpace#isGlobal() global namespace}.
175     * The scope of a name determines where a name starts.
176     * The scope is set on creation and is not modifiable.
177     *
178     * <p>In the {@linkplain GenericName overview illustration},
179     * the scopes are the blue elements in the <var>scope</var>.<var>this</var> column.</p>
180     *
181     * <div class="note"><b>Example:</b>
182     * for a {@linkplain #toFullyQualifiedName() fully qualified name} {@code "org.opengis.util.Record"},
183     * if this instance is the {@code "util.Record"} name, then the scope of this instance
184     * has the {@code "org.opengis"} {@linkplain NameSpace#name() name}.
185     * </div>
186     *
187     * <div class="note"><b>Analogy:</b>
188     * this method is similar in purpose to the current directory of a file system.
189     * </div>
190     *
191     * @return the scope of this name.
192     */
193    @UML(identifier="scope", obligation=MANDATORY, specification=ISO_19103)
194    NameSpace scope();
195
196    /**
197     * Indicates the number of levels specified by this name. The depth is the {@linkplain List#size() size}
198     * of the list returned by the {@link #getParsedNames()} method. As such it is a derived parameter. For
199     * any {@link LocalName}, it is always one. For a {@link ScopedName} it is some number greater than or
200     * equal to 2.
201     *
202     * <div class="note"><b>Example:</b>
203     * if {@code this} name is {@code "urn:ogc:def:crs:EPSG:8.2:4326"} with {@code ':'} as separator,
204     * then this method shall return {@code 7}. If this name is {@code "EPSG:8.2:4326"} in the
205     * {@code "urn:ogc:def:crs"} scope, then this method shall return {@code 3}.
206     * </div>
207     *
208     * <div class="note"><b>Analogy:</b>
209     * this method is similar in purpose to:
210     * <ul>
211     *   <li>the {@link java.nio.file.Path#getNameCount() Path.getNameCount()} method in Java I/O;</li>
212     *   <li>the {@link javax.naming.Name#size() Name.size()} method from the <cite>Java Naming and Directory Interface</cite>.</li>
213     * </ul></div>
214     *
215     * @return the depth of this name.
216     */
217    @UML(identifier="depth", obligation=MANDATORY, specification=ISO_19103)
218    int depth();
219
220    /**
221     * Returns the sequence of {@linkplain LocalName local names} making this generic name.
222     * The length of this sequence is the {@linkplain #depth() depth}. It does not include
223     * the {@linkplain #scope() scope}.
224     *
225     * <p>In the {@linkplain GenericName overview illustration},
226     * the parsed names are the list of elements in yellow part of the <var>scope</var>.<var>this</var> column.</p>
227     *
228     * <div class="note"><b>Example:</b>
229     * If {@code this} name is {@code "urn:ogc:def:crs:EPSG::4326"}, then this method shall returns a list
230     * containing {@code {"urn", "ogc", "def", "crs", "EPSG", "", "4326}} elements in that iteration order.
231     * If this name is {@code "EPSG::4326"} in scope {@code "urn:ogc:def:crs"}, then this method shall
232     * returns a list containing only {@code {"EPSG", "", "4326"}} elements.
233     * </div>
234     *
235     * <div class="note"><b>Analogy:</b>
236     * this method is similar in purpose to:
237     * <ul>
238     *   <li>the {@link java.nio.file.Path#iterator() Path.iterator()} method in Java I/O;</li>
239     *   <li>the {@link javax.naming.Name#getAll() Name.getAll()} method from the <cite>Java Naming and Directory Interface</cite>.</li>
240     * </ul></div>
241     *
242     * @return the local names making this generic name, without the {@linkplain #scope() scope}.
243     *         Shall never be {@code null} neither empty.
244     */
245    @UML(identifier="parsedName", obligation=MANDATORY, specification=ISO_19103)
246    List<? extends LocalName> getParsedNames();
247
248    /**
249     * Returns the first element in the sequence of {@linkplain #getParsedNames() parsed names}.
250     * For any {@link LocalName}, this is always {@code this}.
251     *
252     * <p>In the {@linkplain GenericName overview illustration},
253     * the heads are the blue elements in the <var>head</var>.<var>tail</var> column.</p>
254     *
255     * <div class="note"><b>Example:</b>
256     * if {@code this} name is {@code "urn:ogc:def:crs:EPSG::4326"}, then this method shall returns {@code "urn"}.
257     * </div>
258     *
259     * <div class="note"><b>Analogy:</b>
260     * this method is similar in purpose to:
261     * <ul>
262     *   <li><code>{@linkplain java.nio.file.Path#getName(int) Path.getName}(0)</code> from Java I/O;</li>
263     *   <li><code>{@linkplain javax.naming.Name#get(int) Name.get}(0)</code>
264     *       from the <cite>Java Naming and Directory Interface</cite>.</li>
265     * </ul></div>
266     *
267     * @return the first element in the list of {@linkplain #getParsedNames() parsed names}.
268     *
269     * @departure generalization
270     *   ISO defines this method in <code>ScopedName</code> only. GeoAPI defines it in the base
271     *   class since <code>LocalName</code> can return a sensible value for it. This reduces the
272     *   need for casts.
273     */
274    @UML(identifier="ScopedName.head", obligation=MANDATORY, specification=ISO_19103)
275    LocalName head();
276
277    /**
278     * Returns the last element in the sequence of {@linkplain #getParsedNames() parsed names}.
279     * For any {@link LocalName}, this is always {@code this}.
280     *
281     * <p>In the {@linkplain GenericName overview illustration},
282     * the tips are the yellow elements in the <var>head</var>.<var>tail</var> column.</p>
283     *
284     * <div class="note"><b>Example:</b>
285     * if {@code this} name is {@code "urn:ogc:def:crs:EPSG::4326"} (no matter its
286     * {@linkplain #scope scope}), then this method shall returns {@code "4326"}.
287     * </div>
288     *
289     * <div class="note"><b>Analogy:</b>
290     * this method is similar in purpose to:
291     * <ul>
292     *   <li>the {@link java.io.File#getName() File.getName()} or
293     *       {@link java.nio.file.Path#getFileName() Path.getFileName()} method in Java I/O;</li>
294     *   <li><code>{@linkplain javax.naming.Name#get(int) Name.get}(size-1)</code>
295     *       from the <cite>Java Naming and Directory Interface</cite>.</li>
296     * </ul></div>
297     *
298     * @return the last element in the list of {@linkplain #getParsedNames() parsed names}.
299     *
300     * @departure easeOfUse
301     *   This method is not part of ISO specification. It does not provide any additional
302     *   information compared to that accessible though the standard methods defined by
303     *   ISO, but provides easier to access frequently requested information.
304     */
305    LocalName tip();
306
307    /**
308     * Returns a view of this name as a fully-qualified name. The {@linkplain #scope() scope}
309     * of a fully qualified name must be {@linkplain NameSpace#isGlobal() global}. If the scope
310     * of this name is already global, then this method shall returns {@code this}.
311     *
312     * <div class="note"><b>Example:</b>
313     * if {@code this} name is {@code "EPSG::4326"} ({@linkplain #depth() depth} of 3) and its
314     * {@linkplain #scope() scope} is {@code "urn:ogc:def:crs"}, then the fully qualified name
315     * is {@code "urn:ogc:def:crs:EPSG::4326"}.
316     * </div>
317     *
318     * <div class="note"><b>Analogy:</b>
319     * this method is similar in purpose to the {@link java.io.File#getAbsoluteFile() File.getAbsoluteFile()}
320     * or {@link java.nio.file.Path#toAbsolutePath() Path.toAbsolutePath()} methods in Java I/O.
321     * </div>
322     *
323     * @return the fully-qualified name (never {@code null}).
324     *
325     * @departure easeOfUse
326     *   This method is not part of ISO specification. It does not provide any additional
327     *   information compared to that accessible though the standard methods defined by
328     *   ISO, but makes easier to access frequently requested information.
329     */
330    GenericName toFullyQualifiedName();
331
332    /**
333     * Returns this name expanded with the specified scope. One may represent this operation
334     * as a concatenation of the specified {@code scope} with {@code this}. In pseudo-code,
335     * the following relationships must hold (the last one is specific to {@link ScopedName}):
336     *
337     * <ul>
338     *   <li><code>push(</code><var>foo</var><code> : LocalName).{@linkplain #head()}</code>
339     *       &nbsp;&nbsp; = &nbsp;&nbsp; <var>foo</var></li>
340     *
341     *   <li><code>push(</code><var>foo</var><code> : LocalName).{@linkplain ScopedName#tail() tail()}</code>
342     *       &nbsp;&nbsp; = &nbsp;&nbsp; <var>this</var></li>
343     *
344     *   <li><code>push(</code><var>foo</var><code> : GenericName).{@linkplain #scope()}</code>
345     *       &nbsp;&nbsp; = &nbsp;&nbsp; <var>foo</var>.{@link #scope()}</li>
346     *
347     *   <li><code>push(</code><var>foo</var><code> : GenericName).{@linkplain #getParsedNames()}</code>
348     *       &nbsp;&nbsp; = &nbsp;&nbsp; <var>foo</var>.<code>getParsedNames().addAll(</code><var>this</var>.<code>getParsedNames())</code></li>
349     * </ul>
350     *
351     * <div class="note"><b>Example:</b>
352     * if {@code this} name is {@code "EPSG::4326"} and the given {@code scope} argument is {@code "urn:ogc:def:crs"},
353     * then {@code this.push(scope)} shall returns {@code "urn:ogc:def:crs:EPSG::4326"}.
354     * </div>
355     *
356     * <div class="note"><b>Analogy:</b>
357     * this method is similar in purpose to
358     * <code>{@linkplain javax.naming.Name#addAll(int,javax.naming.Name) Name.addAll}(0, name)</code>
359     * from the <cite>Java Naming and Directory Interface</cite>.
360     * </div>
361     *
362     * @param  scope  the name to use as prefix.
363     * @return a concatenation of the given scope with this name.
364     */
365    @UML(identifier="push", obligation=MANDATORY, specification=ISO_19103)
366    ScopedName push(GenericName scope);
367
368    /**
369     * Compares this name with another name for order.
370     * The recommended ordering for generic names is to {@linkplain String#compareTo(String) compare lexicographically}
371     * each element in the {@linkplain #getParsedNames() list of parsed names}.
372     * Specific attributes of the name, such as how it treats case, may affect the ordering.
373     *
374     * <div class="note"><b>Analogy:</b>
375     * this method is similar in purpose to the {@link java.io.File#compareTo File.compareTo(File)} or
376     * {@link java.nio.file.Path#compareTo Path.compareTo(Path)} methods in Java I/O.
377     * </div>
378     *
379     * @param  other  the other object to be compared to this name.
380     * @return a negative integer, zero, or a positive integer as this name is lexicographically
381     *         less than, equal to, or greater than the specified name.
382     */
383    @Override
384    int compareTo(GenericName other);
385
386    /**
387     * Returns a string representation of this generic name. This string representation is local-independent.
388     * It contains all elements listed by {@link #getParsedNames()} separated by a namespace-dependent character
389     * (usually {@code '.'}, {@code ':'} or {@code '/'}).
390     * This rule implies that the result may or may not be fully qualified.
391     *
392     * <p>Special cases:</p>
393     * <ul>
394     *   <li><code>{@linkplain #toFullyQualifiedName()}.toString()</code> is guaranteed to
395     *       formats the {@linkplain #scope() scope} (if any) before this name.</li>
396     *   <li><code>{@linkplain #tip()}.toString()</code> is guaranteed to <strong>not</strong>
397     *       formats any scope.</li>
398     * </ul>
399     *
400     * <p>In the {@link LocalName} sub-type, this method maps to the {@code aName} ISO 19103 attribute.
401     * In the {@link ScopedName} sub-type, this method maps to the {@code scopedName} ISO 19103 attribute.</p>
402     *
403     * <div class="note"><b>Analogy:</b>
404     * this method is similar in purpose to the {@link java.io.File#toString() File.toString()} or
405     * {@link java.nio.file.Path#toString() Path.toString()} methods in Java I/O.
406     * </div>
407     *
408     * @return the local-independent string representation of this name.
409     */
410    @Override
411    String toString();
412
413    /**
414     * Returns a local-dependent string representation of this generic name. This string
415     * is similar to the one returned by {@link #toString()} except that each element has
416     * been localized in the {@linkplain InternationalString#toString(java.util.Locale)
417     * specified locale}. If no international string is available, then this method shall
418     * returns an implementation mapping to {@link #toString()} for all locales.
419     *
420     * <div class="note"><b>Example:</b>
421     * an implementation may want to localize the {@code "My Documents"} directory name
422     * into {@code "Mes Documents"} on French installation of Windows operating system.
423     * </div>
424     *
425     * @return a localizable string representation of this name.
426     *
427     * @departure extension
428     *   This method is not part of the ISO specification. It has been added to provide
429     *   a way to localize the name.
430     */
431    InternationalString toInternationalString();
432}