sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1708922 - in /sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing: AbstractIdentifiedObject.java NameIterator.java
Date Fri, 16 Oct 2015 09:05:12 GMT
Author: desruisseaux
Date: Fri Oct 16 09:05:11 2015
New Revision: 1708922

URL: http://svn.apache.org/viewvc?rev=1708922&view=rev
Log:
Clarification on the use of Names at (un)marshalling time.

Modified:
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/AbstractIdentifiedObject.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/NameIterator.java

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/AbstractIdentifiedObject.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/AbstractIdentifiedObject.java?rev=1708922&r1=1708921&r2=1708922&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/AbstractIdentifiedObject.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/AbstractIdentifiedObject.java
[UTF-8] Fri Oct 16 09:05:11 2015
@@ -40,7 +40,6 @@ import org.opengis.metadata.citation.Cit
 import org.opengis.referencing.ObjectFactory;
 import org.opengis.referencing.AuthorityFactory;
 import org.opengis.referencing.IdentifiedObject;
-import org.apache.sis.internal.metadata.NameMeaning;
 import org.apache.sis.internal.jaxb.Context;
 import org.apache.sis.internal.jaxb.referencing.Code;
 import org.apache.sis.internal.util.Numerics;
@@ -48,7 +47,6 @@ import org.apache.sis.internal.util.Unmo
 import org.apache.sis.internal.metadata.NameToIdentifier;
 import org.apache.sis.internal.referencing.WKTUtilities;
 import org.apache.sis.internal.referencing.ReferencingUtilities;
-import org.apache.sis.internal.referencing.NilReferencingObject;
 import org.apache.sis.internal.system.DefaultFactories;
 import org.apache.sis.io.wkt.FormattableObject;
 import org.apache.sis.io.wkt.Formatter;
@@ -67,7 +65,6 @@ import static org.apache.sis.util.Utilit
 import static org.apache.sis.internal.util.CollectionsExt.nonNull;
 import static org.apache.sis.internal.util.CollectionsExt.nonEmpty;
 import static org.apache.sis.internal.util.CollectionsExt.immutableSet;
-import static org.apache.sis.internal.util.Utilities.appendUnicodeIdentifier;
 
 // Branch-dependent imports
 import java.util.Objects;
@@ -205,9 +202,13 @@ public class AbstractIdentifiedObject ex
 
     /**
      * Comments on or information about this object, or {@code null} if none.
+     *
+     * <p><b>Consider this field as final!</b>
+     * This field is modified only at unmarshalling time by {@link #setRemarks(InternationalString)}</p>
+     *
+     * @see #getRemarks()
      */
-    @XmlElement
-    private final InternationalString remarks;
+    private InternationalString remarks;
 
     /**
      * {@code true} if this object is deprecated.
@@ -536,7 +537,8 @@ public class AbstractIdentifiedObject ex
      * @return The remarks, or {@code null} if none.
      */
     @Override
-    public InternationalString getRemarks(){
+    @XmlElement
+    public InternationalString getRemarks() {
         return remarks;
     }
 
@@ -890,17 +892,16 @@ public class AbstractIdentifiedObject ex
      * reserved to JAXB, which will assign values to the fields using reflexion.
      */
     AbstractIdentifiedObject() {
-        remarks = null;
         deprecated = false;
     }
 
     /**
      * The {@code gml:id}, which is mandatory. The current implementation searches for the
first identifier,
-     * regardless its authority. If no identifier is found, then the name is used.
-     * If no name is found (which should not occur for valid objects), then this method returns
{@code null}.
+     * regardless its authority. If no identifier is found, then the name or aliases are
used. If none of the
+     * above is found (which should not occur for valid objects), then this method returns
{@code null}.
      *
-     * <p>If an identifier has been found, this method returns the concatenation of
the following elements
-     * separated by hyphens:</p>
+     * <p>If an identifier or a name has been found, this method returns the concatenation
of the following
+     * elements separated by hyphens:</p>
      * <ul>
      *   <li>The code space in lower case, retaining only characters that are valid
for Unicode identifiers.</li>
      *   <li>The object type as defined in OGC's URN (see {@link org.apache.sis.internal.util.DefinitionURI})</li>
@@ -918,59 +919,9 @@ public class AbstractIdentifiedObject ex
     @XmlAttribute(name = "id", namespace = Namespaces.GML, required = true)
     @XmlJavaTypeAdapter(CollapsedStringAdapter.class)
     final String getID() {
-        final Context context = Context.current();
-        String candidate = Context.getObjectID(context, this);
-        if (candidate == null) {
-            final StringBuilder id = new StringBuilder();
-            /*
-             * We will iterate over the identifiers first. Only after the iteration is over,
-             * if we found no suitable ID, then we will use the primary name as a last resort.
-             */
-            if (identifiers != null) {
-                for (final Identifier identifier : identifiers) {
-                    if (appendUnicodeIdentifier(id, '-', identifier.getCodeSpace(), ":",
true) | // Really |, not ||
-                        appendUnicodeIdentifier(id, '-', NameMeaning.toObjectType(getClass()),
":", false) |
-                        appendUnicodeIdentifier(id, '-', identifier.getCode(), ":", true))
-                    {
-                        /*
-                         * Check for ID uniqueness. If the ID is rejected, then we just need
to clear
-                         * the buffer and let the iteration continue the search for another
ID.
-                         */
-                        candidate = id.toString();
-                        if (Context.setObjectForID(context, this, candidate)) {
-                            return candidate;
-                        }
-                    }
-                    id.setLength(0);    // Clear the buffer for another try.
-                }
-            }
-            /*
-             * In last ressort, use the name or an alias. The name will be used without codespace
since
-             * names are often verbose. If that name is also used, append a number until
we find a free ID.
-             */
-            if (name == null || !appendUnicodeIdentifier(id, '-', name.getCode(), ":", false))
{
-                if (alias != null) {
-                    for (final GenericName a : alias) {
-                        if (appendUnicodeIdentifier(id, '-', a.toString(), ":", false)) {
-                            break;
-                        }
-                    }
-                }
-            }
-            if (id.length() != 0) {
-                candidate = id.toString();
-                if (!Context.setObjectForID(context, this, candidate)) {
-                    final int s = id.append('-').length();
-                    int n = 0;
-                    do {
-                        if (++n == 100) return null;    //  Arbitrary limit.
-                        candidate = id.append(n).toString();
-                        id.setLength(s);
-                    } while (!Context.setObjectForID(context, this, candidate));
-                }
-            }
-        }
-        return candidate;
+        // Implementation is provided in the NameIterator class for reducing the size of
+        // AbstractIdentifiedObject.class file in the common case where XML is not needed.
+        return NameIterator.getID(Context.current(), this, name, alias, identifiers);
     }
 
     /**
@@ -999,7 +950,7 @@ public class AbstractIdentifiedObject ex
      *   <li>The first identifier, converted to the {@code "urn:} syntax if possible.</li>
      * </ul>
      */
-    @XmlElement(name = "identifier")
+    @XmlElement(required = true)
     final Code getIdentifier() {
         return Code.forIdentifiedObject(getClass(), identifiers);
     }
@@ -1047,6 +998,13 @@ public class AbstractIdentifiedObject ex
      * by all {@linkplain AbstractIdentifiedObject#getAlias() aliases} which are instance
of {@link Identifier}.
      * Used by JAXB only at (un)marshalling time because GML merges the name and aliases
in a single {@code <gml:name>}
      * property.
+     *
+     * <div class="section">Why we do not use {@code Identifier[]} array instead</div>
+     * It would be easier to define a {@code getNames()} method returning all identifiers
in an array, and let JAXB
+     * invoke {@code setNames(Identifier[])} at unmarshalling time.  But methods expecting
an array in argument are
+     * invoked by JAXB only after the full element has been unmarshalled. For some {@code
AbstractIdentifiedObject}
+     * subclasses, this is too late. For example {@code DefaultOperationMethod} may need
to know the operation name
+     * before to parse the parameters.
      */
     private final class Names extends AbstractCollection<Identifier> {
         /**
@@ -1084,46 +1042,47 @@ public class AbstractIdentifiedObject ex
          */
         @Override
         public boolean add(final Identifier id) {
-            addName(id);
+            if (NameIterator.isUnnamed(name)) {
+                name = id;
+            } else {
+                /*
+                 * Our Code and RS_Identifier implementations should always create NamedIdentifier
instance,
+                 * so the 'instanceof' check should not be necessary. But we do a paranoiac
check anyway.
+                 */
+                final GenericName n = id instanceof GenericName ? (GenericName) id : new
NamedIdentifier(id);
+                if (alias == null) {
+                    alias = Collections.singleton(n);
+                } else {
+                    /*
+                     * This implementation is inefficient since each addition copies the
array, but we rarely
+                     * have more than two aliases.  This implementation is okay for a small
number of aliases
+                     * and ensures that the enclosing AbstractIdentifiedObject is unmodifiable
except by this
+                     * add(…) method.
+                     *
+                     * Note about alternative approaches
+                     * ---------------------------------
+                     * An alternative approach could be to use an ArrayList and replace it
by an unmodifiable
+                     * list only after unmarshalling (using an afterUnmarshal(Unmarshaller,
Object) method),
+                     * but we want to avoid Unmarshaller dependency (for reducing classes
loading for users
+                     * who are not interrested in XML) and it may actually be less efficient
for the vast
+                     * majority of cases where there is less than 3 aliases.
+                     */
+                    final int size = alias.size();
+                    final GenericName[] names = alias.toArray(new GenericName[size + 1]);
+                    names[size] = n;
+                    alias = UnmodifiableArrayList.wrap(names);
+                }
+            }
             return true;
         }
     }
 
     /**
-     * Implementation of {@link Names#add(Identifier)}, defined in the enclosing class
-     * for access to private fields without compiler-generated bridge methods.
+     * Invoked by JAXB for setting the remarks.
+     *
+     * @see #getRemarks()
      */
-    final void addName(final Identifier id) {
-        if (name == NilReferencingObject.UNNAMED) {
-            name = id;
-        } else {
-            /*
-             * Our Code and RS_Identifier implementations should always create NamedIdentifier
instance,
-             * so the 'instanceof' check should not be necessary. But we do a paranoiac check
anyway.
-             */
-            final GenericName n = id instanceof GenericName ? (GenericName) id : new NamedIdentifier(id);
-            if (alias == null) {
-                alias = Collections.singleton(n);
-            } else {
-                /*
-                 * This implementation is inefficient since each addition copies the array,
but we rarely
-                 * have more than two aliases.  This implementation is okay for a small number
of aliases
-                 * and ensures that the enclosing AbstractIdentifiedObject is unmodifiable
except by this
-                 * add(…) method.
-                 *
-                 * Note about alternative approaches
-                 * ---------------------------------
-                 * An alternative approach could be to use an ArrayList and replace it by
an unmodifiable
-                 * list only after unmarshalling (using an afterUnmarshal(Unmarshaller, Object)
method),
-                 * but we want to avoid Unmarshaller dependency (for reducing classes loading
for users
-                 * who are not interrested in XML) and it may actually be less efficient
for the vast
-                 * majority of cases where there is less than 3 aliases.
-                 */
-                final int size = alias.size();
-                final GenericName[] names = alias.toArray(new GenericName[size + 1]);
-                names[size] = n;
-                alias = UnmodifiableArrayList.wrap(names);
-            }
-        }
+    private void setRemarks(final InternationalString remarks) {
+        this.remarks = remarks;
     }
 }

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/NameIterator.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/NameIterator.java?rev=1708922&r1=1708921&r2=1708922&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/NameIterator.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/NameIterator.java
[UTF-8] Fri Oct 16 09:05:11 2015
@@ -17,24 +17,29 @@
 package org.apache.sis.referencing;
 
 import java.util.Iterator;
+import java.util.Collection;
 import org.opengis.util.GenericName;
 import org.opengis.metadata.Identifier;
 import org.opengis.referencing.IdentifiedObject;
+import org.apache.sis.internal.jaxb.Context;
+import org.apache.sis.internal.metadata.NameMeaning;
 import org.apache.sis.internal.referencing.NilReferencingObject;
 
+import static org.apache.sis.internal.util.Utilities.appendUnicodeIdentifier;
+
 
 /**
  * An iterator over the {@linkplain IdentifiedObject#getName() name} of an identified object
followed by
  * {@linkplain IdentifiedObject#getAlias() aliases} which are instance of {@link Identifier}.
- * This iterator is used for {@link AbstractIdentifiedObject} marshalling because GML merges
the name and
- * aliases in a single {@code <gml:name>} property.
+ * This iterator is used for {@link AbstractIdentifiedObject} XML marshalling because GML
merges the name
+ * and aliases in a single {@code <gml:name>} property. However this iterator is useful
only if the aliases
+ * are instances of {@link NamedIdentifier}, or any other implementation which is both a
name and an identifier.
  *
- * <p>Note that this iterator is useful only if the aliases are instances of {@link
NamedIdentifier},
- * or any other implementation which is both a name and an identifier.</p>
+ * <p>This class also opportunistically provide helper methods for {@link AbstractIdentifiedObject}
marshalling.</p>
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.4
- * @version 0.5
+ * @version 0.7
  * @module
  */
 final class NameIterator implements Iterator<Identifier> {
@@ -55,12 +60,19 @@ final class NameIterator implements Iter
         alias = object.getAlias().iterator();
         next = object.getName();
         // Should never be null in a well-formed IdentifiedObject, but let be safe.
-        if (next == null || next == NilReferencingObject.UNNAMED) {
+        if (isUnnamed(next)) {
             next();
         }
     }
 
     /**
+     * Returns {@code true} if the given identifier is null or the {@link NilReferencingObject#UNNAMED}
instance.
+     */
+    static boolean isUnnamed(final Identifier name) {
+        return (name == null) || (name == NilReferencingObject.UNNAMED);
+    }
+
+    /**
      * Returns {@code true} if there is an other name or alias to return.
      */
     @Override
@@ -105,4 +117,87 @@ final class NameIterator implements Iter
         }
         return c;
     }
+
+    /**
+     * Implementation of {@link AbstractIdentifiedObject#getID()}, provided here for reducing
the amount of code
+     * to load in the common case where XML support is not needed.
+     *
+     * <p>The current implementation searches for the first identifier, regardless
its authority.
+     * If no identifier is found, then the name and aliases are used.
+     * Then, this method returns the concatenation of the following elements separated by
hyphens:</p>
+     * <ul>
+     *   <li>The code space in lower case, retaining only characters that are valid
for Unicode identifiers.</li>
+     *   <li>The object type as defined in OGC's URN (see {@link org.apache.sis.internal.util.DefinitionURI})</li>
+     *   <li>The object code, retaining only characters that are valid for Unicode
identifiers.</li>
+     * </ul>
+     *
+     * Example: {@code "epsg-crs-4326"}.
+     *
+     * <p>The returned ID needs to be unique only in the XML document being marshalled.
+     * Consecutive invocations of this method do not need to return the same value,
+     * since it may depends on the marshalling context.</p>
+     *
+     * @param  context     The (un)marshalling context.
+     * @param  object      The object for which to get a {@code gml:id}.
+     * @param  name        The identified object name, or {@code null} if none.
+     * @param  alias       The identified object aliases, or {@code null} if none.
+     * @param  identifiers The identifiers, or {@code null} if none.
+     * @return Proposed value for {@code gml:id} attribute, or {@code null} if none.
+     */
+    static String getID(final Context context, final IdentifiedObject object, final Identifier
name,
+            final Collection<? extends GenericName> alias, final Collection<? extends
Identifier> identifiers)
+    {
+        String candidate = Context.getObjectID(context, object);
+        if (candidate == null) {
+            final StringBuilder id = new StringBuilder();
+            /*
+             * We will iterate over the identifiers first. Only after the iteration is over,
+             * if we found no suitable ID, then we will use the primary name as a last resort.
+             */
+            if (identifiers != null) {
+                for (final Identifier identifier : identifiers) {
+                    if (appendUnicodeIdentifier(id, '-', identifier.getCodeSpace(), ":",
true) |    // Really |, not ||
+                        appendUnicodeIdentifier(id, '-', NameMeaning.toObjectType(object.getClass()),
":", false) |
+                        appendUnicodeIdentifier(id, '-', identifier.getCode(), ":", true))
+                    {
+                        /*
+                         * Check for ID uniqueness. If the ID is rejected, then we just need
to clear
+                         * the buffer and let the iteration continue the search for another
ID.
+                         */
+                        candidate = id.toString();
+                        if (Context.setObjectForID(context, object, candidate)) {
+                            return candidate;
+                        }
+                    }
+                    id.setLength(0);    // Clear the buffer for another try.
+                }
+            }
+            /*
+             * In last ressort, use the name or an alias. The name will be used without codespace
since
+             * names are often verbose. If that name is also used, append a number until
we find a free ID.
+             */
+            if (isUnnamed(name) || !appendUnicodeIdentifier(id, '-', name.getCode(), ":",
false)) {
+                if (alias != null) {
+                    for (final GenericName a : alias) {
+                        if (appendUnicodeIdentifier(id, '-', a.toString(), ":", false)) {
+                            break;
+                        }
+                    }
+                }
+            }
+            if (id.length() != 0) {
+                candidate = id.toString();
+                if (!Context.setObjectForID(context, object, candidate)) {
+                    final int s = id.append('-').length();
+                    int n = 0;
+                    do {
+                        if (++n == 100) return null;    //  Arbitrary limit.
+                        candidate = id.append(n).toString();
+                        id.setLength(s);
+                    } while (!Context.setObjectForID(context, object, candidate));
+                }
+            }
+        }
+        return candidate;
+    }
 }



Mime
View raw message