sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1546824 - in /sis/branches/JDK7/core: sis-referencing/src/main/java/org/apache/sis/internal/jaxb/referencing/ sis-referencing/src/main/java/org/apache/sis/referencing/datum/ sis-referencing/src/test/java/org/apache/sis/referencing/datum/ s...
Date Sun, 01 Dec 2013 17:09:27 GMT
Author: desruisseaux
Date: Sun Dec  1 17:09:26 2013
New Revision: 1546824

URL: http://svn.apache.org/r1546824
Log:
Consolidation of the way we are handling units of measurement in XML (un)marshalling:
- Units.valueOf(String) accepts URI with #xpointer(//*[@gml:id='m']) syntax as found in ISO 19115.
- Consolidated the parsing of above URI and other syntax in a URIParser internal class.
- Remove some unit checks from internal classes, to be moved as checks done by public classes
  in the hope to produce better error messages in case of wrong or missing units.
- Unmarshall and test the unit of PrimeMeridian as a proof of concept.

Added:
    sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/util/URIParser.java   (with props)
    sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/internal/util/URIParserTest.java   (with props)
Modified:
    sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/jaxb/referencing/SecondDefiningParameter.java
    sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultEllipsoid.java
    sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultPrimeMeridian.java
    sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/datum/DefaultPrimeMeridianTest.java
    sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/Context.java
    sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gco/GO_Distance.java
    sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gco/GO_Measure.java
    sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gco/Measure.java
    sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/measure/Units.java
    sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/internal/jaxb/gco/MeasureTest.java
    sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/measure/UnitsTest.java
    sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/test/suite/UtilityTestSuite.java

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/jaxb/referencing/SecondDefiningParameter.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/jaxb/referencing/SecondDefiningParameter.java?rev=1546824&r1=1546823&r2=1546824&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/jaxb/referencing/SecondDefiningParameter.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/jaxb/referencing/SecondDefiningParameter.java [UTF-8] Sun Dec  1 17:09:26 2013
@@ -20,7 +20,6 @@ import javax.xml.bind.annotation.XmlElem
 import javax.xml.bind.annotation.XmlRootElement;
 import javax.measure.unit.Unit;
 import org.opengis.referencing.datum.Ellipsoid;
-import org.apache.sis.measure.Units;
 import org.apache.sis.xml.Namespaces;
 import org.apache.sis.internal.jaxb.gco.Measure;
 
@@ -74,7 +73,6 @@ public final class SecondDefiningParamet
                 measure = new Measure(ellipsoid.getInverseFlattening(), Unit.ONE);
             } else {
                 measure = new Measure(ellipsoid.getSemiMinorAxis(), ellipsoid.getAxisUnit());
-                Units.ensureLinear(measure.unit);
             }
         }
     }
@@ -100,12 +98,13 @@ public final class SecondDefiningParamet
 
     /**
      * Sets the semi-minor axis value. This is invoked by JAXB for unmarshalling.
+     * The unit of measurement (if any) shall be linear, but we do not verify that now.
+     * This will be verified by {@code DefaultEllipsoid.setSecondDefiningParameter(…)}.
      *
      * @param measure The semi-minor axis value.
      */
     public void setSemiMinorAxis(final Measure measure) {
         this.measure = measure;
-        Units.ensureLinear(measure.unit);
     }
 
     /**

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultEllipsoid.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultEllipsoid.java?rev=1546824&r1=1546823&r2=1546824&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultEllipsoid.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultEllipsoid.java [UTF-8] Sun Dec  1 17:09:26 2013
@@ -401,15 +401,20 @@ public class DefaultEllipsoid extends Ab
      * Sets the semi-major axis value.
      * This method is invoked by JAXB at unmarshalling time only.
      *
+     * @throws ConversionException If semi-major and semi-minor axes use inconsistent units
+     *         and we can not convert from one to the other.
+     *
      * @see #setSecondDefiningParameter(SecondDefiningParameter)
      * @see #afterUnmarshal(Object, Object)
      */
-    private void setSemiMajorAxisMeasure(final Measure uom) {
+    private void setSemiMajorAxisMeasure(final Measure measure) throws ConversionException {
         if (semiMajorAxis != 0) {
             warnDuplicated("semiMajorAxis");
         } else {
-            semiMajorAxis = uom.value;
-            unit = uom.unit.asType(Length.class);
+            final Unit<Length> uom = unit; // In case semi-minor were defined before semi-major.
+            semiMajorAxis = measure.value;
+            unit = measure.getUnit(Length.class);
+            harmonizeAxisUnits(uom);
         }
     }
 
@@ -496,6 +501,9 @@ public class DefaultEllipsoid extends Ab
      * value or the semi minor axis value, according to what have been defined in the
      * second defining parameter given. This is for JAXB unmarshalling process only.
      *
+     * @throws ConversionException If semi-major and semi-minor axes use inconsistent units
+     *         and we can not convert from one to the other.
+     *
      * @see #setSemiMajorAxisMeasure(Measure)
      * @see #afterUnmarshal(Object, Object)
      */
@@ -512,26 +520,33 @@ public class DefaultEllipsoid extends Ab
                     ivfDefinitive = true;
                     return;
                 }
-            } else {
-                final Unit<?> uom = measure.unit;
-                if (uom != null) {
-                    if (unit != null) {
-                        value = uom.getConverterToAny(unit).convert(value);
-                    } else {
-                        unit = uom.asType(Length.class);
-                    }
-                }
-                if (semiMinorAxis == 0) {
-                    semiMinorAxis = value;
-                    ivfDefinitive = false;
-                    return;
+            } else if (semiMinorAxis == 0) {
+                semiMinorAxis = value;
+                ivfDefinitive = false;
+                if (unit == null) {
+                    unit = measure.getUnit(Length.class);
+                } else {
+                    harmonizeAxisUnits(measure.unit);
                 }
+                return;
             }
             warnDuplicated("secondDefiningParameter");
         }
     }
 
     /**
+     * Ensures that the semi-minor axis uses the same unit than the semi-major one.
+     *
+     * @throws ConversionException If semi-major and semi-minor axes use inconsistent units
+     *         and we can not convert from one to the other.
+     */
+    private void harmonizeAxisUnits(final Unit<?> uom) throws ConversionException {
+        if (uom != null && uom != unit) {
+            semiMinorAxis = uom.getConverterToAny(unit).convert(semiMinorAxis);
+        }
+    }
+
+    /**
      * Emits a warning telling that the given element is repeated twice.
      */
     private void warnDuplicated(final String element) {

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultPrimeMeridian.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultPrimeMeridian.java?rev=1546824&r1=1546823&r2=1546824&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultPrimeMeridian.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultPrimeMeridian.java [UTF-8] Sun Dec  1 17:09:26 2013
@@ -28,6 +28,7 @@ import org.opengis.util.InternationalStr
 import org.opengis.referencing.ReferenceIdentifier;
 import org.opengis.referencing.datum.PrimeMeridian;
 import org.apache.sis.referencing.AbstractIdentifiedObject;
+import org.apache.sis.internal.jaxb.gco.Measure;
 import org.apache.sis.internal.util.Numerics;
 import org.apache.sis.io.wkt.Formatter;
 import org.apache.sis.util.ComparisonMode;
@@ -89,14 +90,17 @@ public class DefaultPrimeMeridian extend
 
     /**
      * Longitude of the prime meridian measured from the Greenwich meridian, positive eastward.
+     *
+     * <p>Consider this field as final. It is declared non-final only for JAXB unmarshalling.</p>
      */
-    @XmlElement(required = true)
-    private final double greenwichLongitude;
+    private double greenwichLongitude;
 
     /**
      * The angular unit of the {@linkplain #getGreenwichLongitude() Greenwich longitude}.
+     *
+     * <p>Consider this field as final. It is declared non-final only for JAXB unmarshalling.</p>
      */
-    private final Unit<Angle> angularUnit;
+    private Unit<Angle> angularUnit;
 
     /**
      * Constructs a new object in which every attributes are set to a null value.
@@ -105,8 +109,6 @@ public class DefaultPrimeMeridian extend
      */
     private DefaultPrimeMeridian() {
         super(org.apache.sis.internal.referencing.NilReferencingObject.INSTANCE);
-        greenwichLongitude = Double.NaN;
-        angularUnit = null;
     }
 
     /**
@@ -225,6 +227,22 @@ public class DefaultPrimeMeridian extend
     }
 
     /**
+     * Invoked by JAXB for obtaining the Greenwich longitude to marshall together with its {@code "uom"} attribute.
+     */
+    @XmlElement(name = "greenwichLongitude", required = true)
+    private Measure getGreenwichMeasure() {
+        return new Measure(greenwichLongitude, angularUnit);
+    }
+
+    /**
+     * Invoked by JAXB for setting the Greenwich longitude and its unit of measurement.
+     */
+    private void setGreenwichMeasure(final Measure measure) {
+        greenwichLongitude = measure.value;
+        angularUnit = measure.getUnit(Angle.class);
+    }
+
+    /**
      * Compares this prime meridian with the specified object for equality.
      *
      * @param  object The object to compare to {@code this}.

Modified: sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/datum/DefaultPrimeMeridianTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/datum/DefaultPrimeMeridianTest.java?rev=1546824&r1=1546823&r2=1546824&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/datum/DefaultPrimeMeridianTest.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/datum/DefaultPrimeMeridianTest.java [UTF-8] Sun Dec  1 17:09:26 2013
@@ -46,11 +46,13 @@ public final strictfp class DefaultPrime
      * Tests unmarshalling.
      *
      * @throws JAXBException If an error occurred during unmarshalling.
+     *
+     * @see <a href="http://epsg-registry.org/export.htm?gml=urn:ogc:def:meridian:EPSG::8901">GML export of EPSG:8901</a>
      */
     @Test
     public void testUnmarshall() throws JAXBException {
         DefaultPrimeMeridian pm = unmarshall(DefaultPrimeMeridian.class, "Greenwich.xml");
         assertEquals("greenwichLongitude", pm.getGreenwichLongitude(), 0, 0);
-//      assertEquals("angularUnit", NonSI.DEGREE_ANGLE, pm.getAngularUnit());
+        assertEquals("angularUnit", NonSI.DEGREE_ANGLE, pm.getAngularUnit());
     }
 }

Modified: sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/Context.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/Context.java?rev=1546824&r1=1546823&r2=1546824&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/Context.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/Context.java [UTF-8] Sun Dec  1 17:09:26 2013
@@ -204,8 +204,9 @@ public final class Context extends Marsh
     }
 
     /**
-     * Returns the locale to use for marshalling, or {@code null} if no locale were explicitly
-     * specified.
+     * Returns the locale to use for marshalling, or {@code null} if no locale were explicitly specified.
+     *
+     * @return The locale in the context of current (un)marshalling process.
      */
     @Override
     public final Locale getLocale() {
@@ -213,8 +214,9 @@ public final class Context extends Marsh
     }
 
     /**
-     * Returns the timezone to use for marshalling, or {@code null} if none were explicitely
-     * specified.
+     * Returns the timezone to use for marshalling, or {@code null} if none were explicitely specified.
+     *
+     * @return The timezone in the context of current (un)marshalling process.
      */
     @Override
     public final TimeZone getTimeZone() {
@@ -224,6 +226,8 @@ public final class Context extends Marsh
     /**
      * Returns the schema version of the XML document being (un)marshalled.
      * See the super-class javadoc for the list of prefix that we shall support.
+     *
+     * @return The version in the context of current (un)marshalling process.
      */
     @Override
     public final Version getVersion(final String prefix) {

Modified: sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gco/GO_Distance.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gco/GO_Distance.java?rev=1546824&r1=1546823&r2=1546824&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gco/GO_Distance.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gco/GO_Distance.java [UTF-8] Sun Dec  1 17:09:26 2013
@@ -48,9 +48,13 @@ public final class GO_Distance extends X
     }
 
     /**
-     * Constructs an adapter for the given value.
+     * Constructs an adapter for the given value before marshalling.
      *
      * @param value The value.
+     *
+     * @todo The unit of measurement is fixed to metres for now because we do not have this information
+     *       in current metadata interface. This will need to be revisited in a future SIS version if we
+     *       replace the Double type by some quantity type.
      */
     private GO_Distance(final Double value) {
         distance = new Measure(value, SI.METRE);

Modified: sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gco/GO_Measure.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gco/GO_Measure.java?rev=1546824&r1=1546823&r2=1546824&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gco/GO_Measure.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gco/GO_Measure.java [UTF-8] Sun Dec  1 17:09:26 2013
@@ -48,9 +48,13 @@ public final class GO_Measure extends Xm
     }
 
     /**
-     * Constructs an adapter for the given value.
+     * Constructs an adapter for the given value before marshalling.
      *
      * @param value The value.
+     *
+     * @todo The unit of measurement is fixed to metres for now because we do not have this information
+     *       in current metadata interface. This will need to be revisited in a future SIS version if we
+     *       replace the Double type by some quantity type.
      */
     private GO_Measure(final Double value) {
         measure = new Measure(value, SI.METRE);

Modified: sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gco/Measure.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gco/Measure.java?rev=1546824&r1=1546823&r2=1546824&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gco/Measure.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gco/Measure.java [UTF-8] Sun Dec  1 17:09:26 2013
@@ -16,17 +16,14 @@
  */
 package org.apache.sis.internal.jaxb.gco;
 
-import java.io.File;
-import java.net.URI;
 import java.net.URISyntaxException;
 import javax.measure.unit.Unit;
 import javax.measure.unit.NonSI;
+import javax.measure.quantity.Quantity;
 import javax.xml.bind.annotation.XmlValue;
 import javax.xml.bind.annotation.XmlAttribute;
 import org.apache.sis.internal.jaxb.gmd.CodeListProxy;
 import org.apache.sis.internal.jaxb.Context;
-import org.apache.sis.xml.ValueConverter;
-import org.apache.sis.util.CharSequences;
 import org.apache.sis.util.resources.Errors;
 
 
@@ -38,10 +35,30 @@ import org.apache.sis.util.resources.Err
  * because that{@code Measure} extends {@link Number} and we are not allowed to use the
  * {@code @XmlValue} annotation on a class that extends an other class.</p>
  *
+ * {@section XML marshalling}
+ * Measures are used in different ways by the ISO 19115 (Metadata) and GML standards.
+ * The former expresses some measurements with an object of XML type {@code gco:Distance}
+ * (as a substitution for XML type {@code gco:Measure}):
+ *
+ * {@preformat xml
+ *   <gmd:distance>
+ *     <gco:Distance uom=\"http://schemas.opengis.net/iso/19139/20070417/resources/uom/gmxUom.xml#xpointer(//*[@gml:id='m'])\">1000.0</gco:Distance>
+ *   </gmd:distance>
+ * }
+ *
+ * while GML will rather use a a syntax like below:
+ *
+ * {@preformat xml
+ *   <gml:semiMajorAxis uom="urn:ogc:def:uom:EPSG::9001">6378137</gml:semiMajorAxis>
+ * }
+ *
+ * Both have a value of type {@code xsd:double} and a {@code uom} attribute (without namespace)
+ * of type {@code gml:UomIdentifier}. Those two informations are represented by this class.
+ *
  * @author  Cédric Briançon (Geomatys)
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.3 (derived from geotk-2.5)
- * @version 0.3
+ * @version 0.4
  * @module
  *
  * @see org.apache.sis.measure.Measure
@@ -91,6 +108,13 @@ public final class Measure {
      * }
      *
      * @return The string representation of the unit of measure.
+     *
+     * @todo The file on schemas.opengis.net is <code>gmxUom.xml</code>, but the file on standards.iso.org
+     *       and eden.ign.fr is <code>ML_gmxUom.xml</code>. Is there some rule allowing us to know which
+     *       filename to use?
+     *
+     * @todo Strictly speaking, the above URL should be used only for "m", "deg" and "rad" units because they
+     *       are the only ones defined in the <code>gmxUom.xml</code> file. What should we do for other units?
      */
     @XmlAttribute(required = true)
     public String getUOM() {
@@ -108,55 +132,36 @@ public final class Measure {
     }
 
     /**
-     * Sets the unit of measure. This method is invoked by JAXB at unmarshalling time,
-     * and can be invoked only once.
+     * Sets the unit of measure. This method is invoked by JAXB at unmarshalling time.
      *
      * @param uom The unit of measure as a string.
      * @throws URISyntaxException If the {@code uom} looks like a URI, but can not be parsed.
      */
     public void setUOM(String uom) throws URISyntaxException {
-        if (uom == null || (uom = CharSequences.trimWhitespaces(uom)).isEmpty()) {
-            unit = null;
-            return;
-        }
-        /*
-         * Try to guess if the UOM is a URN or URL. We looks for character that are usually
-         * part of URI but not part of unit symbols, for example ':'. We can not search for
-         * '/' and '.' since they are part of UCUM representation.
-         */
         final Context context = Context.current();
-        final ValueConverter converter = Context.converter(context);
-        if (uom.indexOf(':') >= 0) {
-            final URI uri = converter.toURI(context, uom);
-            String part = uri.getFragment();
-            if (part != null) {
-                uom = part;
-                int i = uom.lastIndexOf("@gml:id=");
-                if (i >= 0) {
-                    i += 8; // 8 is the length of "@gml:id="
-                    for (final int length=uom.length(); i<length;) {
-                        final int c = uom.codePointAt(i);
-                        if (!Character.isWhitespace(c)) {
-                            if (c == '\'') i++;
-                            break;
-                        }
-                        i += Character.charCount(c);
-                    }
-                    final int stop = uom.lastIndexOf('\'');
-                    uom = CharSequences.trimWhitespaces((stop > i) ? uom.substring(i, stop) : uom.substring(i));
-                }
-            } else if ((part = uri.getPath()) != null) {
-                uom = new File(part).getName();
-            }
-        }
-        unit = converter.toUnit(context, uom);
+        unit = Context.converter(context).toUnit(context, uom);
+    }
+
+    /**
+     * Returns {@link #unit} as a unit compatible with the given quantity.
+     *
+     * @todo For now, this method does not format useful error message in case of missing unit or wrong unit type.
+     *       We define this method merely as a placeholder for future improvement in error handling.
+     *
+     * @param  <Q>  Compile-time type of the {@code type} argument.
+     * @param  type The quantity for the desired unit.
+     * @return A unit compatible with the given type.
+     */
+    public <Q extends Quantity> Unit<Q> getUnit(final Class<Q> type) {
+        return unit.asType(type);
     }
 
     /**
-     * Sets the unit to the given value, with a warning logged if the user specified an other unit.
+     * Sets the unit to the given value, with a warning logged if the user specified a unit
+     * different than the previous {@link #unit} value.
      *
      * {@example Some users wrongly assign the "m" unit to <code>Ellipsoid.inverseFlattening</code>.
-     *           The SIS adapter force the unit to <code>Unit.ONE</code>, but we want to let the user
+     *           The SIS adapter forces the unit to <code>Unit.ONE</code>, but we want to let the user
      *           know that he probably did something wrong.}
      *
      * @param newUnit The new unit (can not be null).

Added: sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/util/URIParser.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/util/URIParser.java?rev=1546824&view=auto
==============================================================================
--- sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/util/URIParser.java (added)
+++ sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/util/URIParser.java [UTF-8] Sun Dec  1 17:09:26 2013
@@ -0,0 +1,334 @@
+/*
+ * 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.internal.util;
+
+import static org.apache.sis.util.CharSequences.*;
+
+
+/**
+ * Utility methods for parsing OGC's URI (URN or URL). This is not a general-purpose parser.
+ *
+ * <p>For example, all the following URIs are for the same object:</p>
+ * <ul>
+ *   <li>{@code "4326"} (codespace inferred by the caller)</li>
+ *   <li>{@code "EPSG:4326"} (older format)</li>
+ *   <li>{@code "EPSG::4326"} (often seen for similarity with URN below)</li>
+ *   <li>{@code "urn:ogc:def:crs:EPSG::4326"} (version number is omitted)</li>
+ *   <li>{@code "urn:ogc:def:crs:EPSG:8.2:4326"} (explicit version number, here 8.2)</li>
+ *   <li>{@code "urn:x-ogc:def:crs:EPSG::4326"} (prior registration of {@code "ogc"} to IANA)</li>
+ *   <li>{@code "http://www.opengis.net/gml/srs/epsg.xml#4326"}</li>
+ * </ul>
+ *
+ * {@section Components or URN}
+ * URN begins with {@code "urn:ogc:def:"} (formerly {@code "urn:x-ogc:def:"}) followed by:
+ * <ul>
+ *   <li>an <cite>object type</cite></li>
+ *   <li>an <cite>authority</cite></li>
+ *   <li>an optional version number (often omitted)</li>
+ *   <li>the code</li>
+ *   <li>an arbitrary amount of parameters</li>
+ * </ul>
+ *
+ * The <cite>object type</cite> can be:
+ * <table class="sis">
+ *   <tr><th>Object type</th>         <th>Meaning</th></tr>
+ *   <tr><td>axis</td>                <td>Coordinate system axe definition</td></tr>
+ *   <tr><td>axisDirection</td>       <td>Axis direction code definition</td></tr>
+ *   <tr><td>coordinateOperation</td> <td>Coordinate operation definition</td></tr>
+ *   <tr><td>crs</td>                 <td>Coordinate reference system definition</td></tr>
+ *   <tr><td>cs</td>                  <td>Coordinate system definition</td></tr>
+ *   <tr><td>datum</td>               <td>Datum definition</td></tr>
+ *   <tr><td>dataType</td>            <td>Data type definition</td></tr>
+ *   <tr><td>derivedCRSType</td>      <td>Derived CRS type code definition</td></tr>
+ *   <tr><td>documentType</td>        <td>Document type definition</td></tr>
+ *   <tr><td>ellipsoid</td>           <td>Ellipsoid definition</td></tr>
+ *   <tr><td>featureType</td>         <td>Feature type definition</td></tr>
+ *   <tr><td>group</td>               <td>Operation parameter group definition</td></tr>
+ *   <tr><td>meaning</td>             <td>Parameter meaning definition</td></tr>
+ *   <tr><td>meridian</td>            <td>Prime meridian definition</td></tr>
+ *   <tr><td>method</td>              <td>Operation method definition</td></tr>
+ *   <tr><td>nil</td>                 <td>Explanations for missing information</td></tr>
+ *   <tr><td>parameter</td>           <td>Operation parameter definition</td></tr>
+ *   <tr><td>phenomenon</td>          <td>Observable property definition</td></tr>
+ *   <tr><td>pixelInCell</td>         <td>Pixel in cell code definition</td></tr>
+ *   <tr><td>rangeMeaning</td>        <td>Range meaning code definition</td></tr>
+ *   <tr><td>referenceSystem</td>     <td>Value reference system definition</td></tr>
+ *   <tr><td>uom</td>                 <td>Unit of measure definition</td></tr>
+ *   <tr><td>verticalDatumType</td>   <td>Vertical datum type code definition</td></tr>
+ * </table>
+ *
+ * Some example of <cite>authorities</cite> are:
+ * <table class="sis">
+ *   <tr><th>Authority</th>      <th>Purpose</th></tr>
+ *   <tr><td>{@code "OGC"}</td>  <td>Objects defined by the Open Geospatial Consortium.</td></tr>
+ *   <tr><td>{@code "EPSG"}</td> <td>Referencing objects defined in the EPSG database.</td></tr>
+ *   <tr><td>{@code "EDCS"}</td> <td>Environmental Data Coding Specification.</td></tr>
+ *   <tr><td>{@code "SI"}</td>   <td>International System of Units.</td></tr>
+ *   <tr><td>{@code "UCUM"}</td> <td>Unified Code for Units of Measure.</td></tr>
+ * </table>
+ *
+ * {@section Combined URNs}
+ * This implementation does not handle combined URNs. An example of combined URN would be
+ * {@code "urn:ogc:def:crs,crs:EPSG:6.3:27700,crs:EPSG:6.3:5701"}.
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @since   0.4
+ * @version 0.4
+ * @module
+ *
+ * @see <a href="http://portal.opengeospatial.org/files/?artifact_id=24045">Definition identifier URNs in OGC namespace</a>
+ * @see <a href="http://www.opengeospatial.org/ogcna">OGC Naming Authority</a>
+ */
+public final class URIParser {
+    /**
+     * The URN separator.
+     */
+    private static final char SEPARATOR = ':';
+
+    /**
+     * A URL portion of HTTP URL for Coordinate Reference System identifiers.
+     * Portion starts after the protocol part, and finishes before the authority
+     */
+    private static final String SRS_PATH = "//www.opengis.net/gml/srs/";
+
+    /*
+     * Current version contains only static methods. However a future version may contain
+     * some fields like 'type', 'version' and 'authority' for storing the parsing result.
+     */
+
+    /**
+     * Do not allow instantiation of this class.
+     */
+    private URIParser() {
+    }
+
+    /**
+     * Returns {@code true} if a sub-region of {@code urn} matches the given {@code component},
+     * ignoring case, leading and trailing whitespaces.
+     *
+     * @param  component The expected component ({@code "urn"}, {@code "ogc"}, {@code "def"}, <i>etc.</i>)
+     * @param  urn       The URN for which to test a subregion.
+     * @param  lower     Index of the first character in {@code urn} to compare, after skipping whitespaces.
+     * @param  upper     Index after the last character in {@code urn} to compare, ignoring whitespaces.
+     * @return {@code true} if the given sub-region of {@code urn} match the given component.
+     */
+    private static boolean regionMatches(final String component, final String urn, int lower, int upper) {
+        lower = skipLeadingWhitespaces (urn, lower, upper);
+        upper = skipTrailingWhitespaces(urn, lower, upper);
+        final int length = upper - lower;
+        return (length == component.length()) && urn.regionMatches(true, lower, component, 0, length);
+    }
+
+    /**
+     * Returns the substring of the given URN, ignoring whitespaces and version number if present.
+     * The substring is expected to contains at most one {@code ':'} character. If such separator
+     * character is present, then that character and everything before it are ignored. The ignored
+     * part should be the version number, but this is not verified.
+     *
+     * <p>If the remaining substring is empty or contains more {@code ':'} characters, then this method
+     * returns {@code null}. The presence of more {@code ':'} characters means that the code has parameters,
+     * (e.g. {@code "urn:ogc:def:crs:OGC:1.3:AUTO42003:1:-100:45"}) which are not handled by this method.</p>
+     *
+     * @param  urn The URN from which to get the code.
+     * @param  fromIndex Index of the first character in {@code urn} to check.
+     * @return The code part of the URN, or {@code null} if empty or invalid.
+     */
+    private static String codeIgnoreVersion(final String urn, int fromIndex) {
+        final int length = urn.length();
+        fromIndex = skipLeadingWhitespaces(urn, fromIndex, length);
+        if (fromIndex >= length) {
+            return null; // Empty code.
+        }
+        final int s = urn.indexOf(SEPARATOR, fromIndex);
+        if (s >= 0) {
+            // Ignore the version number (actually everything up to the first ':').
+            fromIndex = skipLeadingWhitespaces(urn, s+1, length);
+            if (fromIndex >= length || urn.indexOf(SEPARATOR, fromIndex) >= 0) {
+                return null; // Empty code, or the code is followed by parameters.
+            }
+        }
+        return urn.substring(fromIndex, skipTrailingWhitespaces(urn, fromIndex, length));
+    }
+
+    /**
+     * Returns the code part of the given URI, provided that it matches the given object type and authority.
+     * This lightweight method is useful when:
+     *
+     * <ul>
+     *   <li>the URI is expected to have a specific <cite>object type</cite> and <cite>authority</cite>;</li>
+     *   <li>the version number is considered irrelevant;</li>
+     *   <li>the code is expected to have no parameters.</li>
+     * </ul>
+     *
+     * This method accepts the following URI representations:
+     *
+     * <ul>
+     *   <li>Code alone, without any {@code ':'} character (e.g. {@code "4326"}).</li>
+     *   <li>The given authority followed by the code (e.g. {@code "EPSG:4326"}).</li>
+     *   <li>The URN form (e.g. {@code "urn:ogc:def:crs:EPSG::4326"}), ignoring version number.
+     *       This method accepts also the former {@code "x-ogc"} in place of {@code "ogc"}.</li>
+     *   <li>The HTTP form (e.g. {@code "http://www.opengis.net/gml/srs/epsg.xml#4326"}).</li>
+     * </ul>
+     *
+     * @param  type      The expected object type (e.g. {@code "crs"}). See class javadoc for a list of types.
+     * @param  authority The expected authority, typically {@code "epsg"}. See class javadoc for a list of authorities.
+     * @param  uri       The URI to parse.
+     * @return The code part of the given URI, or {@code null} if the codespace does not match the given type
+     *         and authority, the code is empty, or the code is followed by parameters.
+     */
+    public static String codeOf(final String type, final String authority, final String uri) {
+        /*
+         * Get the part before the first ':' character. If none, assume that the given URI is already the code.
+         * Otherwise the part may be either "http" or "urn" protocol, or the given authority (typically "EPSG").
+         * In the later case, we return immediately the code after the authority part.
+         */
+        int upper = uri.indexOf(SEPARATOR);
+        if (upper < 0) {
+            return trimWhitespaces(uri);
+        }
+        int lower  = skipLeadingWhitespaces(uri, 0, upper);
+        int length = skipTrailingWhitespaces(uri, lower, upper) - lower;
+        if (length == authority.length() && uri.regionMatches(true, lower, authority, 0, length)) {
+            return codeIgnoreVersion(uri, upper+1);
+        }
+        /*
+         * Check for supported protocols: only "urn" and "http" at this time.
+         * All other protocols are rejected as unrecognized.
+         */
+        String component;
+        switch (length) {
+            case 3:  component = "urn";  break;
+            case 4:  component = "http"; break;
+            default: return null;
+        }
+        if (!uri.regionMatches(true, lower, component, 0, length)) {
+            return null;
+        }
+        if (length == 4) {
+            return codeForHTTP(type, authority, uri, upper+1);
+        }
+        /*
+         * At this point we have determined that the protocol is URN. The next components after "urn"
+         * shall be "ogc" or "x-ogc", then "def", then the type and authority given in arguments.
+         */
+        for (int p=0; p!=4; p++) {
+            lower = upper + 1;
+            upper = uri.indexOf(SEPARATOR, lower);
+            if (upper < 0) {
+                return null; // No more components.
+            }
+            switch (p) {
+                case 0: if (regionMatches("ogc", uri, lower, upper)) {
+                            continue; // "ogc" is tested before "x-ogc" because more common.
+                        }
+                        component = "x-ogc";   break; // Fallback if the component is not "ogc".
+                case 1: component = "def";     break;
+                case 2: component = type;      break;
+                case 3: component = authority; break;
+                default: throw new AssertionError(p);
+            }
+            if (!regionMatches(component, uri, lower, upper)) {
+                return null;
+            }
+        }
+        return codeIgnoreVersion(uri, upper+1);
+    }
+
+    /**
+     * Implementation of URI parser for the HTTP forms.
+     * The current implementation recognizes the following types:
+     *
+     * <ul>
+     *   <li>{@code crs} for Coordinate Reference System objects
+     *       (example: {@code "http://www.opengis.net/gml/srs/epsg.xml#4326"})</li>
+     * </ul>
+     */
+    private static String codeForHTTP(final String type, final String authority, final String url, int lower) {
+        if (type.equals("crs")) {
+            if (url.regionMatches(true, lower, SRS_PATH, 0, SRS_PATH.length())) {
+                lower += SRS_PATH.length();
+                if (url.regionMatches(true, lower, authority, 0, authority.length())) {
+                    lower += authority.length();
+                    int upper = url.length();
+                    if (lower < upper && url.charAt(lower) == '.') {
+                        // Ignore the extension (typically ".xml", but we accept anything).
+                        if ((lower = url.indexOf('#', lower+1)) >= 0) {
+                            lower = skipLeadingWhitespaces(url, lower+1, upper);
+                            upper = skipTrailingWhitespaces(url, lower, upper);
+                            if (lower < upper) {
+                                return url.substring(lower, upper);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Parses a URL which contains a pointer to a XML fragment.
+     * The current implementation recognizes the following types:
+     *
+     * <ul>
+     *   <li>{@code uom} for Unit Of Measurement (example:
+     *       {@code "http://schemas.opengis.net/iso/19139/20070417/resources/uom/gmxUom.xml#xpointer(//*[@gml:id='m'])"})</li>
+     * </ul>
+     *
+     * @param  type The object type.
+     * @param  url  The URL to parse.
+     * @return The reference, or {@code null} if none.
+     */
+    public static String xpointer(final String type, final String url) {
+        if (type.equals("uom")) {
+            final int f = url.indexOf('#');
+            if (f >= 1) {
+                /*
+                 * For now we accept any path as long as it ends with the "gmxUom.xml" file
+                 * because resources may be hosted on different servers, or the path may be
+                 * relative instead than absolute.
+                 */
+                int i = url.lastIndexOf('/', f-1) + 1;
+                if (regionMatches(   "gmxUom.xml", url, i, f) ||  // Name used on http://schemas.opengis.net
+                    regionMatches("ML_gmxUom.xml", url, i, f))    // Name used on http://standards.iso.org
+                {
+                    /*
+                     * The fragment should typically be of the form "xpointer(//*[@gml:id='m'])".
+                     * However sometime we found no "xpointer", but directly the unit instead.
+                     */
+                    i = url.indexOf('(', f+1);
+                    if (i >= 0 && regionMatches("xpointer", url, f+1, i)) {
+                        i = url.indexOf("@gml:id=", i+1);
+                        if (i >= 0) {
+                            i = skipLeadingWhitespaces(url, i+8, url.length()); // 8 is the length of "@gml:id="
+                            final int c = url.charAt(i);
+                            if (c == '\'' || c == '"') {
+                                final int s = url.indexOf(c, ++i);
+                                if (s >= 0) {
+                                    return (String) trimWhitespaces(url, i, s);
+                                }
+                            }
+                        }
+                    } else {
+                        return (String) trimWhitespaces(url, f+1, url.length());
+                    }
+                }
+            }
+        }
+        return null;
+    }
+}

Propchange: sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/util/URIParser.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/util/URIParser.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain;charset=UTF-8

Modified: sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/measure/Units.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/measure/Units.java?rev=1546824&r1=1546823&r2=1546824&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/measure/Units.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/measure/Units.java [UTF-8] Sun Dec  1 17:09:26 2013
@@ -35,6 +35,7 @@ import org.apache.sis.util.ArraysExt;
 import org.apache.sis.util.Exceptions;
 import org.apache.sis.util.CharSequences;
 import org.apache.sis.util.resources.Errors;
+import org.apache.sis.internal.util.URIParser;
 
 import static java.lang.Math.PI;
 import static java.lang.Math.abs;
@@ -48,7 +49,7 @@ import static org.apache.sis.util.CharSe
  *
  * @author  Martin Desruisseaux (IRD, Geomatys)
  * @since   0.3 (derived from geotk-2.1)
- * @version 0.3
+ * @version 0.4
  * @module
  */
 public final class Units extends Static {
@@ -130,7 +131,7 @@ public final class Units extends Static 
                 final Object value;
                 try {
                     value = field.get(null);
-                } catch (ReflectiveOperationException e) {
+                } catch (IllegalAccessException e) {
                     // Should not happen since we asked only for public static constants.
                     throw new AssertionError(e);
                 }
@@ -397,8 +398,8 @@ public final class Units extends Static 
      *
      * {@section Parsing authority codes}
      * As a special case, if the given {@code uom} arguments is of the form {@code "EPSG:####"}
-     * (ignoring case and whitespaces), then {@code "####"} is parsed as an integer and forwarded
-     * to the {@link #valueOfEPSG(int)} method.
+     * or {@code "urn:ogc:def:uom:EPSG:####"} (ignoring case and whitespaces), then {@code "####"}
+     * is parsed as an integer and forwarded to the {@link #valueOfEPSG(int)} method.
      *
      * {@section NetCDF unit symbols}
      * The attributes in NetCDF files often merge the axis direction with the angular unit,
@@ -422,16 +423,24 @@ public final class Units extends Static 
          * Check for authority codes (currently only EPSG, but more could be added later).
          * If the unit is not an authority code (which is the most common case), then we
          * will check for hard-coded unit symbols.
+         *
+         * URIParser.codeOf(…) returns 'uom' directly (provided that whitespaces were already trimmed)
+         * if no ':' character were found, in which case the string is assumed to be the code directly.
+         * This is the intended behavior for AuthorityFactory, but in the particular case of this method
+         * we want to try to parse as a xpointer before to give up.
          */
-        int s = uom.indexOf(':');
-        if (s >= 0) {
-            final String authority = (String) trimWhitespaces(uom, 0, s);
-            if (authority.equalsIgnoreCase("EPSG")) try {
-                return valueOfEPSG(Integer.parseInt((String) trimWhitespaces(uom, s+1, length)));
+        if (isURI(uom)) {
+            String code = URIParser.codeOf("uom", "EPSG", uom);
+            if (code != null && code != uom) try { // Really identity check, see above comment.
+                return valueOfEPSG(Integer.parseInt(code));
             } catch (NumberFormatException e) {
                 throw new IllegalArgumentException(Errors.format(
                         Errors.Keys.IllegalArgumentValue_2, "uom", uom), e);
             }
+            code = URIParser.xpointer("uom", uom);
+            if (code != null) {
+                uom = code;
+            }
         }
         /*
          * Check for degrees units. Note that "deg" could be both angular and Celsius degrees.
@@ -445,7 +454,7 @@ public final class Units extends Static 
             }
             String prefix = uom;
             boolean isTemperature = false;
-            s = Math.max(uom.lastIndexOf(' '), uom.lastIndexOf('_'));
+            final int s = Math.max(uom.lastIndexOf(' '), uom.lastIndexOf('_'));
             if (s >= 1) {
                 final String suffix = (String) trimWhitespaces(uom, s+1, length);
                 if (ArraysExt.containsIgnoreCase(DEGREE_SUFFIXES, suffix) || (isTemperature = isCelsius(suffix))) {
@@ -513,6 +522,23 @@ public final class Units extends Static 
     }
 
     /**
+     * Returns {@code true} if the given unit seems to be an URI. Example:
+     * <ul>
+     *   <li>{@code "urn:ogc:def:uom:EPSG::9102"}</li>
+     *   <li>{@code "http://schemas.opengis.net/iso/19139/20070417/resources/uom/gmxUom.xml#xpointer(//*[@gml:id='m'])"}</li>
+     * </ul>
+     */
+    private static boolean isURI(final String uom) {
+        for (int i=uom.length(); --i>=0;) {
+            final char c = uom.charAt(i);
+            if (c == ':' || c == '#') {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
      * Returns a hard-coded unit from an EPSG code. The {@code code} argument given to this
      * method shall be a code identifying a record in the {@code "Unit of Measure"} table of
      * the EPSG database. If this method does not recognize the given code, then it returns

Modified: sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/internal/jaxb/gco/MeasureTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/internal/jaxb/gco/MeasureTest.java?rev=1546824&r1=1546823&r2=1546824&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/internal/jaxb/gco/MeasureTest.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/internal/jaxb/gco/MeasureTest.java [UTF-8] Sun Dec  1 17:09:26 2013
@@ -47,12 +47,12 @@ public final strictfp class MeasureTest 
         assertEquals("http://schemas.opengis.net/iso/19139/20070417/resources/uom/gmxUom.xml#xpointer(//*[@gml:id='m'])", measure.getUOM());
 
         measure.unit = null;
-        measure.setUOM("../uom/ML_gmxUom.xsd#xpointer(//*[@gml:id='deg'])");
+        measure.setUOM("../uom/ML_gmxUom.xml#xpointer(//*[@gml:id='deg'])");
         assertEquals(NonSI.DEGREE_ANGLE, measure.unit);
         assertEquals("http://schemas.opengis.net/iso/19139/20070417/resources/uom/gmxUom.xml#xpointer(//*[@gml:id='deg'])", measure.getUOM());
 
         measure.unit = null;
-        measure.setUOM("http://my.big.org/units/kg");
+        measure.setUOM("gmxUom.xml#kg"); // Not really an existing unit in 'gmxUom'.
         assertEquals(SI.KILOGRAM, measure.unit);
         assertEquals("http://schemas.opengis.net/iso/19139/20070417/resources/uom/gmxUom.xml#xpointer(//*[@gml:id='kg'])", measure.getUOM());
     }

Added: sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/internal/util/URIParserTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/internal/util/URIParserTest.java?rev=1546824&view=auto
==============================================================================
--- sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/internal/util/URIParserTest.java (added)
+++ sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/internal/util/URIParserTest.java [UTF-8] Sun Dec  1 17:09:26 2013
@@ -0,0 +1,90 @@
+/*
+ * 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.internal.util;
+
+import org.apache.sis.test.TestCase;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+
+/**
+ * Tests {@link URIParser}.
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @since   0.4
+ * @version 0.4
+ * @module
+ */
+public final strictfp class URIParserTest extends TestCase {
+    /**
+     * Tests {@link URIParser#codeOf(String, String, String)} with URI like {@code "EPSG:4326"}.
+     */
+    @Test
+    public void testCodeOfEPSG() {
+        assertEquals("4326", URIParser.codeOf("crs", "EPSG", "4326"));
+        assertEquals("4326", URIParser.codeOf("crs", "EPSG", "EPSG:4326"));
+        assertEquals("4326", URIParser.codeOf("crs", "EPSG", "EPSG::4326"));
+        assertNull  (        URIParser.codeOf("crs", "EPSG", "EPSG:::4326"));
+        assertEquals("4326", URIParser.codeOf("crs", "EPSG", "EPSG:8.2:4326"));
+        assertEquals("4326", URIParser.codeOf("crs", "EPSG", " epsg : 4326 "));
+        assertEquals("4326", URIParser.codeOf("crs", "EPSG", " epsg :: 4326 "));
+        assertEquals("4326", URIParser.codeOf("crs", "EPSG", " epsg : : 4326 "));
+    }
+
+    /**
+     * Tests {@link URIParser#codeOf(String, String, String)} with URN like
+     * {@code "urn:ogc:def:crs:EPSG::4326"}.
+     */
+    @Test
+    public void testCodeOfURN() {
+        assertEquals("4326",  URIParser.codeOf("crs", "EPSG", "urn:ogc:def:crs:EPSG:4326"));
+        assertEquals("4326",  URIParser.codeOf("crs", "EPSG", "urn:ogc:def:crs:EPSG::4326"));
+        assertEquals("4326",  URIParser.codeOf("crs", "EPSG", "urn:ogc:def:crs:EPSG:8.2:4326"));
+        assertEquals("4326",  URIParser.codeOf("crs", "EPSG", "urn:x-ogc:def:crs:EPSG::4326"));
+        assertNull  (         URIParser.codeOf("crs", "EPSG", "urn:n-ogc:def:crs:EPSG::4326"));
+        assertEquals("4326",  URIParser.codeOf("crs", "EPSG", " urn : ogc : def : crs : epsg : : 4326"));
+        assertNull  (         URIParser.codeOf("crs", "EPSG", "urn:ogc:def:uom:EPSG:9102"));
+        assertEquals("9102",  URIParser.codeOf("uom", "EPSG", "urn:ogc:def:uom:EPSG:9102"));
+        assertNull  (         URIParser.codeOf("crs", "EPSG", "urn:ogc:def:crs:OGC:1.3:CRS84"));
+        assertEquals("CRS84", URIParser.codeOf("crs", "OGC",  "urn:ogc:def:crs:OGC:1.3:CRS84"));
+        assertNull  (         URIParser.codeOf("crs", "OGC",  "urn:ogc:def:crs:OGC:1.3:AUTO42003:1:-100:45"));
+    }
+
+    /**
+     * Tests {@link URIParser#codeOf(String, String, String)} with URL like
+     * {@code "http://www.opengis.net/gml/srs/epsg.xml#4326"}.
+     */
+    @Test
+    public void testCodeOfHTTP() {
+        assertEquals("4326", URIParser.codeOf("crs", "EPSG", "http://www.opengis.net/gml/srs/epsg.xml#4326"));
+        assertNull  (        URIParser.codeOf("crs", "OGC",  "http://www.opengis.net/gml/srs/epsg.xml#4326"));
+        assertNull  (        URIParser.codeOf("uom", "EPSG", "http://www.opengis.net/gml/srs/epsg.xml#4326"));
+        assertNull  (        URIParser.codeOf("uom", "EPSG", "http://schemas.opengis.net/iso/19139/20070417/resources/uom/gmxUom.xml#xpointer(//*[@gml:id='m'])"));
+    }
+
+    /**
+     * Tests {@link URIParser#xpointer(String, String)}.
+     */
+    @Test
+    public void testXPointer() {
+        assertEquals("m", URIParser.xpointer("uom", "http://schemas.opengis.net/iso/19139/20070417/resources/uom/gmxUom.xml#m"));
+        assertEquals("m", URIParser.xpointer("uom", "http://schemas.opengis.net/iso/19139/20070417/resources/uom/gmxUom.xml#xpointer(//*[@gml:id='m'])"));
+        assertEquals("m", URIParser.xpointer("uom", "http://standards.iso.org/ittf/PubliclyAvailableStandards/ISO_19139_Schemas/resources/uom/ML_gmxUom.xml#xpointer(//*[@gml:id='m'])"));
+        assertEquals("m", URIParser.xpointer("uom", "../uom/ML_gmxUom.xml#xpointer(//*[@gml:id='m'])"));
+    }
+}

Propchange: sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/internal/util/URIParserTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/internal/util/URIParserTest.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain;charset=UTF-8

Modified: sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/measure/UnitsTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/measure/UnitsTest.java?rev=1546824&r1=1546823&r2=1546824&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/measure/UnitsTest.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/measure/UnitsTest.java [UTF-8] Sun Dec  1 17:09:26 2013
@@ -19,6 +19,7 @@ package org.apache.sis.measure;
 import javax.measure.unit.Unit;
 import javax.measure.quantity.Quantity;
 import javax.measure.converter.UnitConverter;
+import org.apache.sis.test.DependsOn;
 import org.apache.sis.test.TestCase;
 import org.junit.*;
 
@@ -45,9 +46,10 @@ import static org.apache.sis.test.Assert
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.3 (derived from geotk-2.5)
- * @version 0.3
+ * @version 0.4
  * @module
  */
+@DependsOn(org.apache.sis.internal.util.URIParserTest.class)
 public final strictfp class UnitsTest extends TestCase {
     /**
      * Compares two values for equality.
@@ -260,7 +262,7 @@ public final strictfp class UnitsTest ex
     }
 
     /**
-     * Tests {@link Units#valueOfEPSG(int)}.
+     * Tests {@link Units#valueOfEPSG(int)} and {@link Units#valueOf(String)} with a {@code "EPSG:####"} syntax.
      */
     @Test
     public void testValueOfEPSG() {
@@ -268,5 +270,8 @@ public final strictfp class UnitsTest ex
         assertSame(DEGREE_ANGLE, valueOfEPSG(9102));
         assertSame(METRE,        valueOf("EPSG:9001"));
         assertSame(DEGREE_ANGLE, valueOf(" epsg : 9102"));
+        assertSame(DEGREE_ANGLE, valueOf("urn:ogc:def:uom:EPSG::9102"));
+        assertSame(METRE,        valueOf("http://schemas.opengis.net/iso/19139/20070417/resources/uom/gmxUom.xml#xpointer(//*[@gml:id='m'])"));
+        assertSame(METRE,        valueOf("gmxUom.xml#m"));
     }
 }

Modified: sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/test/suite/UtilityTestSuite.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/test/suite/UtilityTestSuite.java?rev=1546824&r1=1546823&r2=1546824&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/test/suite/UtilityTestSuite.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/test/suite/UtilityTestSuite.java [UTF-8] Sun Dec  1 17:09:26 2013
@@ -78,6 +78,7 @@ import org.junit.BeforeClass;
     org.apache.sis.internal.util.CollectionsExtTest.class,
 
     // GeoAPI most basic types.
+    org.apache.sis.internal.util.URIParserTest.class,
     org.apache.sis.util.iso.TypesTest.class,
     org.apache.sis.util.iso.SimpleInternationalStringTest.class,
     org.apache.sis.util.iso.DefaultInternationalStringTest.class,



Mime
View raw message