/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2004-2008, Open Source Geospatial Foundation (OSGeo) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * This package contains documentation from OpenGIS specifications. * OpenGIS consortium's work is fully acknowledged here. */ package org.geotools.util; import java.util.Arrays; import java.util.List; import java.util.Locale; // For javadoc import org.opengis.util.GenericName; import org.opengis.util.InternationalString; // For javadoc import org.opengis.util.LocalName; import org.opengis.util.NameSpace; /** * Fully qualified identifier for an object. * A {@code ScopedName} contains a {@link LocalName} as * {@linkplain #asLocalName head} and a {@linkplain GenericName}, * which may be a {@link LocalName} or an other {@link org.opengis.util.ScopedName}, * as {@linkplain #getScope tail}. * * @since 2.1 * * @source $URL$ * @version $Id$ * @author Martin Desruisseaux (IRD) * * @see NameFactory */ public class ScopedName extends org.geotools.util.GenericName implements org.opengis.util.ScopedName { /** * Serial number for interoperability with different versions. */ private static final long serialVersionUID = -7664125655784137729L; /** * The scope of this variable (also know as the "tail"). */ private final GenericName scope; /** * The separator character. */ private final char separator; /** * The head as a local name. */ private final LocalName name; /** * The list of parsed names. Will be constructed only when first needed. */ private transient List<LocalName> parsedNames; /** * Constructs a scoped name from the specified international string. * If the specified name is an {@link InternationalString}, then the * <code>{@linkplain InternationalString#toString(Locale) toString}(null)</code> * method will be used in order to fetch an unlocalized name. Otherwise, the * <code>{@linkplain CharSequence#toString toString}()</code> method will be used. * * @param scope The scope (or "tail") of the variable. * @param name The head (never {@code null}). */ public ScopedName(final GenericName scope, final CharSequence name) { this(scope, DEFAULT_SEPARATOR, name); } /** * Constructs a scoped name from the specified international string. * If the specified name is an {@link InternationalString}, then the * <code>{@linkplain InternationalString#toString(Locale) toString}(null)</code> * method will be used in order to fetch an unlocalized name. Otherwise, the * <code>{@linkplain CharSequence#toString toString}()</code> method will be used. * * @param scope The scope (or "tail") of the variable. * @param separator The separator character (usually <code>':'</code> or <code>'/'</code>). * @param name The head (never {@code null}). */ public ScopedName(final GenericName scope, final char separator, final CharSequence name) { AbstractInternationalString.ensureNonNull("scope", scope); AbstractInternationalString.ensureNonNull("name", name); this.scope = scope; this.separator = separator; this.name = new org.geotools.util.LocalName(this, name); } /** * Returns the head of this scoped name. This is the first elements in the sequence of * {@linkplain #getParsedNames parsed names}. The head element must exists in the same * {@linkplain NameSpace name space} than this scoped name. In other words, the following * relationship must holds: * <p> * <ul> * <li><code>head().scope() == this.{@linkplain #scope scope()}</code></li> * </ul> * * @since 2.3 * * @todo Not yet implemented. */ @Override public LocalName head() { throw new UnsupportedOperationException("Not yet implemented."); } /** * Returns the tail of this scoped name. The returned name contains every elements of the * {@linkplain #getParsedNames parsed names list} except for the first one, which is the * {@linkplain #head head}. In other words, the following relationship must holds: * <p> * <ul> * <li><code>tail().getParsedNames() == this.{@linkplain #getParsedNames getParsedNames()}.sublist(1,end)</code></li> * </ul> * <p> * <strong>Note:</strong> This condition can be understood in terms of the Java * {@link java.util.List#equals equals} method instead of the Java identity * comparator {@code ==}. * * @since 2.3 * * @todo Not yet implemented. */ public GenericName tail() { throw new UnsupportedOperationException("Not yet implemented."); } /** * Returns a name which contains every element of the * {@linkplain #getParsedNames parsed names list} except for the last element. * * @see java.io.File#getPath * * @since 2.3 * * @todo Not yet implemented. */ public GenericName path() { throw new UnsupportedOperationException("Not yet implemented."); } /** * Returns the scope of this name. * * @deprecated Replaced by {@link #scope()}. */ @Deprecated public GenericName getScope() { return scope; } /** * Returns the separator character. */ @Override public char getSeparator() { return separator; } /** * Returns a view of this object as a scoped name. Since this object is already * a scoped name, this method always returns {@code this}. * * @deprecated Replaced by {@link #toFullyQualifiedName}. */ @Deprecated public org.opengis.util.ScopedName asScopedName() { return this; } /** * Returns a view of this object as a local name. This is the last element in the * sequence of {@linkplain #getParsedNames parsed names}. The local name returned * by this method will still have the same {@linkplain LocalName#getScope scope} * than this scoped name. Note however that the string returned by * {@link LocalName#toString} will differs. */ @Override public LocalName tip() { return name; } /** * Returns the sequence of local name for this {@linkplain GenericName generic name}. */ public List<LocalName> getParsedNames() { if (parsedNames == null) { final List<? extends LocalName> parents = scope.getParsedNames(); final int size = parents.size(); LocalName[] names = new LocalName[size + 1]; names = parents.toArray(names); names[size] = name; parsedNames = Arrays.asList(names); } return parsedNames; } /** * Returns a view of this name as a fully-qualified name. The {@linkplain #scope scope} * of a fully qualified name must be {@linkplain NameSpace#isGlobal global}. This method * never returns {@code null}. * * @since 2.3 */ public GenericName toFullyQualifiedName() { return this; } /** * Returns this name expanded with the specified scope. One may represent this operation * as a concatenation of the specified {@code name} with {@code this}. In pseudo-code, * the following relationships must hold: * <p> * <ul> * <li><code>push(<var>name</var>).getParsedList() == * <var>name</var>.getParsedList().addAll({@linkplain #getParsedNames()})</code></li> * <li><code>push(<var>name</var>).scope() == <var>name</var>.{@linkplain #scope()}</code></li> * <li><code>push({@linkplain ScopedName#head head()}).{@linkplain ScopedName#tail tail()} == this</code></li> * </ul> * <p> * <strong>Note:</strong> Those conditions can be understood in terms of the Java * {@link Object#equals equals} method instead of the Java identity comparator {@code ==}. * * @since 2.3 * * @todo Not yet implemented. */ public org.opengis.util.ScopedName push(GenericName scope) { throw new UnsupportedOperationException("Not yet implemented."); } /** * Compares this scoped name with the specified object for equality. */ @Override public boolean equals(final Object object) { if (object == this) { return true; } if (object!=null && object.getClass().equals(getClass())) { final ScopedName that = (ScopedName) object; return Utilities.equals(this.name, that.name); // No need to checks the scope, since the LocalName implementation // should checks it. } return false; } /** * Returns a hash code value for this generic name. */ @Override public int hashCode() { return (int)serialVersionUID ^ name.hashCode() ^ scope.hashCode(); } }