| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.apache.sis.util.iso; |
| |
| import javax.xml.bind.annotation.XmlType; |
| import javax.xml.bind.annotation.XmlRootElement; |
| import org.opengis.util.TypeName; |
| import org.opengis.util.NameSpace; |
| import org.apache.sis.util.UnknownNameException; |
| |
| |
| /** |
| * The name of an attribute type associated to a {@linkplain DefaultMemberName member name}. |
| * {@code DefaultTypeName} can be instantiated by any of the following methods: |
| * |
| * <ul> |
| * <li>{@link DefaultNameFactory#createTypeName(NameSpace, CharSequence)}</li> |
| * <li>{@link DefaultNameFactory#toTypeName(Class)}</li> |
| * </ul> |
| * |
| * <div class="section">Mapping Java classes to type names</div> |
| * It is sometime useful to establish a mapping between {@link Class} and {@code TypeName}. |
| * When an UML identifier from an OGC standard exists for a given {@code Class}, Apache SIS |
| * uses that identifier prefixed by the {@code "OGC"} namespace. |
| * Note that this is <strong>not</strong> a standard practice. |
| * A more standard practice would be to use the <cite>definition identifiers in OGC namespace</cite> |
| * (third column in the table below), but the set of data type identifiers defined by OGC is currently |
| * small and is sometime not an exact match. |
| * |
| * <table class="sis"> |
| * <caption>Mapping from Java classes to type names (non-exhaustive list)</caption> |
| * <tr> |
| * <th>Java class</th> |
| * <th>Type name (unofficial)</th> |
| * <th>Definition identifier in OGC namespace</th> |
| * <th>Recommended URL in Web Processing Services</th> |
| * </tr><tr> |
| * <td>{@link org.opengis.util.InternationalString}</td> |
| * <td>{@code OGC:FreeText}</td> |
| * <td></td> |
| * <td></td> |
| * </tr><tr> |
| * <td>{@link java.lang.String}</td> |
| * <td>{@code OGC:CharacterString}</td> |
| * <td>{@code urn:ogc:def:dataType:OGC::string}</td> |
| * <td>{@code http://www.w3.org/2001/XMLSchema#string}</td> |
| * </tr><tr> |
| * <td>{@link java.net.URI}</td> |
| * <td>{@code OGC:URI}</td> |
| * <td>{@code urn:ogc:def:dataType:OGC::anyURI}</td> |
| * <td></td> |
| * </tr><tr> |
| * <td>{@link java.lang.Boolean}</td> |
| * <td>{@code OGC:Boolean}</td> |
| * <td>{@code urn:ogc:def:dataType:OGC::boolean}</td> |
| * <td>{@code http://www.w3.org/2001/XMLSchema#boolean}</td> |
| * </tr><tr> |
| * <td>{@link java.lang.Integer}</td> |
| * <td>{@code OGC:Integer}</td> |
| * <td>{@code urn:ogc:def:dataType:OGC::nonNegativeInteger}</td> |
| * <td>{@code http://www.w3.org/2001/XMLSchema#integer}</td> |
| * </tr><tr> |
| * <td>{@link java.math.BigDecimal}</td> |
| * <td>{@code OGC:Decimal}</td> |
| * <td></td> |
| * <td>{@code http://www.w3.org/2001/XMLSchema#decimal}</td> |
| * </tr><tr> |
| * <td>{@link java.lang.Double}</td> |
| * <td>{@code OGC:Real}</td> |
| * <td></td> |
| * <td>{@code http://www.w3.org/2001/XMLSchema#double}</td> |
| * </tr><tr> |
| * <td>{@link java.lang.Float}</td> |
| * <td>{@code OGC:Real}</td> |
| * <td></td> |
| * <td>{@code http://www.w3.org/2001/XMLSchema#float}</td> |
| * </tr><tr> |
| * <td>{@link java.util.Date}</td> |
| * <td>{@code OGC:DateTime}</td> |
| * <td></td> |
| * <td></td> |
| * </tr><tr> |
| * <td>{@link java.util.Locale}</td> |
| * <td>{@code OGC:PT_Locale}</td> |
| * <td></td> |
| * <td></td> |
| * </tr><tr> |
| * <td>{@link org.opengis.metadata.Metadata}</td> |
| * <td>{@code OGC:MD_Metadata}</td> |
| * <td></td> |
| * <td></td> |
| * </tr><tr> |
| * <td>Unknown Java class</td> |
| * <td>{@code class:}<the class name></td> |
| * <td></td> |
| * <td></td> |
| * </tr> |
| * </table> |
| * |
| * The mapping defined by Apache SIS may change in any future version depending on standardization progress. |
| * To protect against such changes, users are encouraged to rely on methods or constructors like |
| * {@link DefaultNameFactory#toTypeName(Class)} or {@link #toClass()} instead than parsing the name. |
| * |
| * |
| * <div class="section">Immutability and thread safety</div> |
| * This class is immutable and thus inherently thread-safe if the {@link NameSpace} and {@link CharSequence} |
| * arguments given to the constructor are also immutable. Subclasses shall make sure that any overridden methods |
| * remain safe to call from multiple threads and do not change any public {@code TypeName} state. |
| * |
| * @author Guilhem Legal (Geomatys) |
| * @author Cédric Briançon (Geomatys) |
| * @author Martin Desruisseaux (Geomatys) |
| * @version 0.5 |
| * |
| * @see DefaultMemberName |
| * @see DefaultNameFactory |
| * |
| * @since 0.3 |
| * @module |
| */ |
| @XmlType(name = "TypeName_Type") |
| @XmlRootElement(name = "TypeName") |
| public class DefaultTypeName extends DefaultLocalName implements TypeName { |
| /** |
| * Serial number for inter-operability with different versions. |
| */ |
| private static final long serialVersionUID = 7182126541436753582L; |
| |
| /** |
| * The value class to be returned by {@link #toClass()}, or {@code null} if not yet computed. |
| * {@link Void#TYPE} is used as a sentinel value meaning explicit {@code null}. |
| * |
| * <p>This value is only computed. We do not allow the user to explicitly specify it, because we |
| * need that {@code DefaultTypeName}s having identical name also have the same {@code valueClass}. |
| * This is necessary {@link DefaultNameFactory#pool} cache integrity. Users who want to explicitly |
| * specify their own value class can override {@link #toClass()} instead.</p> |
| * |
| * @see #setValueClass(NameSpace, String, Class) |
| * @see #toClass() |
| */ |
| private transient Class<?> valueClass; |
| |
| /** |
| * Constructs a type name from the given character sequence. The argument are given unchanged to the |
| * {@linkplain DefaultLocalName#DefaultLocalName(NameSpace,CharSequence) super-class constructor}. |
| * |
| * @param scope the scope of this name, or {@code null} for a global scope. |
| * @param name the local name (never {@code null}). |
| * |
| * @see DefaultNameFactory#createTypeName(NameSpace, CharSequence) |
| */ |
| protected DefaultTypeName(final NameSpace scope, final CharSequence name) { |
| super(scope, name); |
| } |
| |
| /** |
| * Returns a SIS type name implementation with the values of the given arbitrary implementation. |
| * This method performs the first applicable action in the following choices: |
| * |
| * <ul> |
| * <li>If the given object is {@code null}, then this method returns {@code null}.</li> |
| * <li>Otherwise if the given object is already an instance of {@code DefaultTypeName}, |
| * then it is returned unchanged.</li> |
| * <li>Otherwise a new {@code DefaultTypeName} instance is created |
| * with the same values than the given name.</li> |
| * </ul> |
| * |
| * @param object the object to get as a SIS implementation, or {@code null} if none. |
| * @return a SIS implementation containing the values of the given object (may be the |
| * given object itself), or {@code null} if the argument was null. |
| * |
| * @since 0.5 |
| */ |
| public static DefaultTypeName castOrCopy(final TypeName object) { |
| if (object == null || object instanceof DefaultTypeName) { |
| return (DefaultTypeName) object; |
| } |
| return new DefaultTypeName(object.scope(), object.toInternationalString()); |
| } |
| |
| /** |
| * Sets {@link #valueClass} to the given value, only if the scope and the name of this {@code TypeName} |
| * are equal to the given values. The check for scope and name is a protection against renaming that user |
| * could apply if they subclass {@link DefaultNameFactory}. If the user performed such renaming, then the |
| * value class may be wrong, so we will ignore the given value class and let {@link #toClass()} computes |
| * the class itself. |
| */ |
| final void setValueClass(final NameSpace scope, final String name, final Class<?> valueClass) { |
| if (scope == super.scope() && name.equals(super.toString())) { |
| this.valueClass = valueClass; |
| } |
| } |
| |
| /** |
| * Returns the Java class associated to this type name. |
| * The default implementation parses this name in different ways depending on the {@linkplain #scope() scope}: |
| * |
| * <ul> |
| * <li>If the scope is {@code "OGC"}, then: |
| * <ul> |
| * <li>If the name is {@code "CharacterString"}, {@code "Integer"}, {@code "Real"} or other recognized names |
| * (see {@linkplain DefaultTypeName class javadoc}), then the corresponding class is returned.</li> |
| * <li>Otherwise {@link UnknownNameException} is thrown.</li> |
| * </ul> |
| * </li> |
| * <li>Else if the scope is {@code "class"}, then: |
| * <ul> |
| * <li>If the name is accepted by {@link Class#forName(String)}, then that class is returned.</li> |
| * <li>Otherwise {@link UnknownNameException} is thrown.</li> |
| * </ul> |
| * </li> |
| * <li>Else if the scope {@linkplain DefaultNameSpace#isGlobal() is global}, then: |
| * <ul> |
| * <li>If the name is one of the names recognized in {@code "OGC"} scope (see above), |
| * then the corresponding class is returned.</li> |
| * <li>Otherwise {@code null} is returned. No exception is thrown because names in the global namespace |
| * could be anything, so we can not be sure that the given name was wrong.</li> |
| * </ul> |
| * </li> |
| * <li>Otherwise {@code null} is returned, since this method can not check the validity of names in other |
| * namespaces.</li> |
| * </ul> |
| * |
| * @return the Java class associated to this {@code TypeName}, |
| * or {@code null} if there is no mapping from this name to a Java class. |
| * @throws UnknownNameException if a mapping from this name to a Java class was expected to exist |
| * (typically because of the {@linkplain #scope() scope}) but the operation failed. |
| * |
| * @see Names#toClass(TypeName) |
| * @see DefaultNameFactory#toTypeName(Class) |
| * |
| * @since 0.5 |
| */ |
| public Class<?> toClass() throws UnknownNameException { |
| /* |
| * No synchronization, because it is not a problem if two threads compute the same value concurrently. |
| * No volatile field neither, because instances of Class are safely published (well, I presume...). |
| */ |
| Class<?> c = valueClass; |
| if (c == Void.TYPE) { |
| return null; |
| } |
| if (c == null) { |
| /* |
| * Invoke super.foo() instead than this.foo() because we do not want to invoke any overridden method. |
| * This is for ensuring that two TypeNames constructed with the same name will map to the same class. |
| * See 'valueClass' javadoc for more information. |
| */ |
| try { |
| c = TypeNames.toClass(TypeNames.namespace(super.scope()), super.toString()); |
| } catch (ClassNotFoundException e) { |
| throw new UnknownNameException(TypeNames.unknown(super.toFullyQualifiedName()), e); |
| } |
| if (c == null) { |
| throw new UnknownNameException(TypeNames.unknown(super.toFullyQualifiedName())); |
| } |
| valueClass = c; |
| } |
| return (c != Void.TYPE) ? c : null; |
| } |
| |
| |
| |
| |
| ////////////////////////////////////////////////////////////////////////////////////////////////// |
| //////// //////// |
| //////// XML support with JAXB //////// |
| //////// //////// |
| //////// The following methods are invoked by JAXB using reflection (even if //////// |
| //////// they are private) or are helpers for other methods invoked by JAXB. //////// |
| //////// Those methods can be safely removed if Geographic Markup Language //////// |
| //////// (GML) support is not needed. //////// |
| //////// //////// |
| ////////////////////////////////////////////////////////////////////////////////////////////////// |
| |
| /** |
| * Empty constructor to be used by JAXB only. Despite its "final" declaration, |
| * the {@link #name} field will be set by JAXB during unmarshalling. |
| */ |
| private DefaultTypeName() { |
| } |
| } |