sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1725653 - in /sis/branches/JDK8/core: sis-metadata/src/main/java/org/apache/sis/internal/metadata/ sis-metadata/src/main/java/org/apache/sis/metadata/iso/ sis-referencing/src/main/java/org/apache/sis/referencing/factory/ sis-referencing/sr...
Date Tue, 19 Jan 2016 23:50:30 GMT
Author: desruisseaux
Date: Tue Jan 19 23:50:29 2016
New Revision: 1725653

URL: http://svn.apache.org/viewvc?rev=1725653&view=rev
Log:
Partial work on MultiAuthoritiesFactory: contains the private methods needed for creating objects, not yet tested and not yet connected to public API.

Added:
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/AuthorityFactoryIdentifier.java   (with props)
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/MultiAuthoritiesFactory.java   (with props)
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/NoSuchAuthorityFactoryException.java   (with props)
Modified:
    sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/NameMeaning.java
    sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/ImmutableIdentifier.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/AuthorityFactoryProxy.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/CommonAuthorityFactory.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/ConcurrentAuthorityFactory.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/GeodeticAuthorityFactory.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGDataAccess.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGFactory.java
    sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/AuthorityFactoryProxyTest.java

Modified: sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/NameMeaning.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/NameMeaning.java?rev=1725653&r1=1725652&r2=1725653&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/NameMeaning.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/NameMeaning.java [UTF-8] Tue Jan 19 23:50:29 2016
@@ -84,8 +84,10 @@ public final class NameMeaning extends S
      *
      * <p><b>Note on the case:</b> The <cite>"Name type specification — definitions"</cite> document (OGC 09-048) writes
      * authorities in upper cases, while <a href="http://www.opengis.net/def/auth/">http://www.opengis.net/def/auth/</a>
-     * use lower cases. Apache SIS uses upper cases for now.</p>
+     * use lower cases. Apache SIS uses upper cases for now. The lower/upper case policy should be kept consistent with
+     * the policy used by {@link org.apache.sis.referencing.factory.MultiAuthoritiesFactory} for its keys.</p>
      *
+     * @see org.apache.sis.referencing.factory.MultiAuthoritiesFactory
      * @see <a href="http://www.opengis.net/def/auth/">http://www.opengis.net/def/auth/</a>
      *
      * @since 0.7

Modified: sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/ImmutableIdentifier.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/ImmutableIdentifier.java?rev=1725653&r1=1725652&r2=1725653&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/ImmutableIdentifier.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/ImmutableIdentifier.java [UTF-8] Tue Jan 19 23:50:29 2016
@@ -330,8 +330,8 @@ public class ImmutableIdentifier extends
         value = properties.get(CODESPACE_KEY);
         if (value == null) {
             codeSpace = org.apache.sis.internal.util.Citations.getCodeSpace(authority);
-        } else if (value instanceof CharSequence) {
-            codeSpace = trimWhitespaces((CharSequence) value).toString();
+        } else if (value instanceof String) {
+            codeSpace = trimWhitespaces((String) value);
         } else {
             throw illegalPropertyType(properties, CODESPACE_KEY, value);
         }

Added: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/AuthorityFactoryIdentifier.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/AuthorityFactoryIdentifier.java?rev=1725653&view=auto
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/AuthorityFactoryIdentifier.java (added)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/AuthorityFactoryIdentifier.java [UTF-8] Tue Jan 19 23:50:29 2016
@@ -0,0 +1,243 @@
+/*
+ * 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.referencing.factory;
+
+import java.util.Locale;
+import org.opengis.util.InternationalString;
+import org.opengis.metadata.citation.Citation;
+import org.opengis.referencing.AuthorityFactory;
+import org.opengis.referencing.cs.CSAuthorityFactory;
+import org.opengis.referencing.crs.CRSAuthorityFactory;
+import org.opengis.referencing.datum.DatumAuthorityFactory;
+import org.opengis.referencing.operation.CoordinateOperationAuthorityFactory;
+import org.apache.sis.util.Debug;
+import org.apache.sis.util.Classes;
+import org.apache.sis.util.iso.DefaultNameSpace;
+
+// Branch-dependent imports
+import java.util.Objects;
+
+
+/**
+ * Identification of an authority factory by its type, namespace and version.
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @since   0.7
+ * @version 0.7
+ * @module
+ */
+final class AuthorityFactoryIdentifier {
+    /**
+     * Factory needed is {@link CRSAuthorityFactory}.
+     */
+    static final byte CRS = 0;
+
+    /**
+     * Factory needed is {@link CSAuthorityFactory}.
+     */
+    static final byte CS = 1;
+
+    /**
+     * Factory needed is {@link DatumAuthorityFactory}.
+     */
+    static final byte DATUM = 2;
+
+    /**
+     * Factory needed is {@link CoordinateOperationAuthorityFactory}.
+     */
+    static final byte OPERATION = 3;
+
+    /**
+     * Factory needed is the Apache-SIS specific {@link GeodeticAuthorityFactory}.
+     */
+    static final byte GEODETIC = 4;
+
+    /**
+     * Factory needed is {@link AuthorityFactory}, the base interface of all factories.
+     */
+    static final byte ANY = 5;
+
+    /**
+     * The interfaces or abstract base classes for the above constants.
+     */
+    @SuppressWarnings({"unchecked", "rawtypes"})
+    private static final Class<? extends AuthorityFactory> TYPES[] = new Class[6];
+    static {
+        TYPES[CRS]       = CRSAuthorityFactory.class;
+        TYPES[CS]        = CSAuthorityFactory.class;
+        TYPES[DATUM]     = DatumAuthorityFactory.class;
+        TYPES[OPERATION] = CoordinateOperationAuthorityFactory.class;
+        TYPES[GEODETIC]  = GeodeticAuthorityFactory.class;
+        TYPES[ANY]       = AuthorityFactory.class;
+    }
+
+    /**
+     * The type of the factory needed, as one of the {@link #CRS}, {@link #CS}, {@link #DATUM},
+     * {@link #OPERATION}, {@link #GEODETIC} or {@link #ANY} constants.
+     */
+    final byte type;
+
+    /**
+     * The authority of the factory, in upper case. The upper case policy should be kept
+     * consistent with {@link org.apache.sis.internal.metadata.NameMeaning#AUTHORITIES}.
+     *
+     * <div class="note"><b>Example:</b>
+     * In the {@code "urn:ogc:def:crs:EPSG:8.2:4326"} URN, this is {@code "EPSG"}.</div>
+     *
+     * @see #getAuthority()
+     * @see org.apache.sis.internal.util.DefinitionURI
+     * @see org.apache.sis.internal.metadata.NameMeaning
+     */
+    private String authority;
+
+    /**
+     * The version part of a URI, or {@code null} if none.
+     * If the version contains alphabetic characters, they should be in lower case.
+     *
+     * <div class="note"><b>Example:</b>
+     * In the {@code "urn:ogc:def:crs:EPSG:8.2:4326"} URN, this is {@code "8.2"}.</div>
+     *
+     * @see #hasVersion()
+     * @see #unversioned(String)
+     * @see #versionOf(Citation)
+     */
+    private String version;
+
+    /**
+     * Creates a new identifier for a factory of the given type, authority and version.
+     * The given authority shall be already in upper cases and the version in lower cases
+     * (this is not verified by this constructor).
+     */
+    private AuthorityFactoryIdentifier(final byte type, final String authority, final String version) {
+        this.type      = type;
+        this.authority = authority;
+        this.version   = version;
+    }
+
+    /**
+     * Creates a new identifier for a factory of the given type, authority and version.
+     * Only the version can be null.
+     */
+    static AuthorityFactoryIdentifier create(final byte type, final String authority, final String version) {
+        return new AuthorityFactoryIdentifier(type, authority.toUpperCase(Locale.US),
+                           (version == null) ? null : version.toLowerCase(Locale.US));
+    }
+
+    /**
+     * Returns an identifier for a factory of the same type than this identifier,
+     * but a different authority and no version.
+     */
+    AuthorityFactoryIdentifier unversioned(final String newAuthority) {
+        if (version == null && newAuthority.equals(authority)) {
+            return this;
+        }
+        return new AuthorityFactoryIdentifier(type, newAuthority.toUpperCase(Locale.US), null);
+    }
+
+    /**
+     * Creates a new identifier for the same type and authority than this identifier, but a different version
+     * extracted from the given authority.
+     *
+     * @param  factory The factory's authority.
+     * @return An identifier for the version of the given authority, or {@code this} if the version is the same.
+     */
+    AuthorityFactoryIdentifier versionOf(final Citation factory) {
+        String newVersion = null;
+        if (factory != null) {
+            final InternationalString i18n = factory.getEdition();
+            if (i18n != null) {
+                newVersion = i18n.toString(Locale.US);
+                if (newVersion != null) {
+                    newVersion = newVersion.toLowerCase(Locale.US);
+                }
+            }
+        }
+        if (Objects.equals(version, newVersion)) {
+            return this;
+        }
+        return new AuthorityFactoryIdentifier(type, authority, newVersion);
+    }
+
+    /**
+     * Creates a new identifier for the same authority and version than this identifier, but a different factory.
+     */
+    AuthorityFactoryIdentifier newType(final byte newType) {
+        return (newType != type) ? new AuthorityFactoryIdentifier(newType, authority, version) : this;
+    }
+
+    /**
+     * Returns the authority.
+     */
+    String getAuthority() {
+        return authority;
+    }
+
+    /**
+     * Returns {@code true} if this identifier is for a specific dataset version.
+     */
+    boolean hasVersion() {
+        return version != null;
+    }
+
+    /**
+     * Ensures that the authority and version use shared {@link String} instances. This method is invoked only when
+     * we have determined that this {@code AuthorityFactoryIdentifier} instance will be used as a key in a hash map.
+     */
+    AuthorityFactoryIdentifier intern() {
+        authority = authority.intern();
+        if (version != null) {
+            version = version.intern();
+        }
+        return this;
+    }
+
+    /**
+     * Returns a hash code value for this object.
+     */
+    @Override
+    public int hashCode() {
+        return type + 31*authority.hashCode() + Objects.hashCode(version);
+    }
+
+    /**
+     * Compares the given object with this identifier.
+     */
+    @Override
+    public boolean equals(final Object other) {
+        if (other instanceof AuthorityFactoryIdentifier) {
+            final AuthorityFactoryIdentifier that = (AuthorityFactoryIdentifier) other;
+            if (type == that.type && authority.equals(that.authority)) {
+                return Objects.equals(version, that.version);
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Returns a string representation of this identifier for debugging purpose.
+     */
+    @Debug
+    @Override
+    public String toString() {
+        final StringBuilder buffer = new StringBuilder();
+        buffer.append(Classes.getShortName(TYPES[type])).append(DefaultNameSpace.DEFAULT_SEPARATOR).append(authority);
+        if (version != null) {
+            buffer.append(DefaultNameSpace.DEFAULT_SEPARATOR).append(version);
+        }
+        return buffer.toString();
+    }
+}

Propchange: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/AuthorityFactoryIdentifier.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/AuthorityFactoryIdentifier.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain;charset=UTF-8

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/AuthorityFactoryProxy.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/AuthorityFactoryProxy.java?rev=1725653&r1=1725652&r2=1725653&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/AuthorityFactoryProxy.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/AuthorityFactoryProxy.java [UTF-8] Tue Jan 19 23:50:29 2016
@@ -16,6 +16,9 @@
  */
 package org.apache.sis.referencing.factory;
 
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Locale;
 import javax.measure.unit.Unit;
 import org.opengis.referencing.cs.*;
 import org.opengis.referencing.crs.*;
@@ -64,10 +67,17 @@ abstract class AuthorityFactoryProxy<T>
     final Class<T> type;
 
     /**
+     * The type of factory needed for creating objects,
+     * as one of the constants defined in {@link AuthorityFactoryIdentifier}.
+     */
+    final byte factoryType;
+
+    /**
      * Creates a new proxy for objects of the given type.
      */
-    AuthorityFactoryProxy(final Class<T> type) {
+    AuthorityFactoryProxy(final Class<T> type, final byte factoryType) {
         this.type = type;
+        this.factoryType = factoryType;
     }
 
     /**
@@ -165,7 +175,7 @@ abstract class AuthorityFactoryProxy<T>
      * The proxy for the {@link GeodeticAuthorityFactory#createObject} method.
      */
     static final AuthorityFactoryProxy<IdentifiedObject> OBJECT =
-        new AuthorityFactoryProxy<IdentifiedObject>(IdentifiedObject.class) {
+        new AuthorityFactoryProxy<IdentifiedObject>(IdentifiedObject.class, AuthorityFactoryIdentifier.ANY) {
             @Override IdentifiedObject create(GeodeticAuthorityFactory factory, String code) throws FactoryException {
                 return factory.createObject(code);
             }
@@ -175,7 +185,7 @@ abstract class AuthorityFactoryProxy<T>
     };
 
     static final AuthorityFactoryProxy<Datum> DATUM =
-        new AuthorityFactoryProxy<Datum>(Datum.class) {
+        new AuthorityFactoryProxy<Datum>(Datum.class, AuthorityFactoryIdentifier.DATUM) {
             @Override Datum create(GeodeticAuthorityFactory factory, String code) throws FactoryException {
                 return factory.createDatum(code);
             }
@@ -185,7 +195,7 @@ abstract class AuthorityFactoryProxy<T>
     };
 
     static final AuthorityFactoryProxy<EngineeringDatum> ENGINEERING_DATUM =
-        new AuthorityFactoryProxy<EngineeringDatum>(EngineeringDatum.class) {
+        new AuthorityFactoryProxy<EngineeringDatum>(EngineeringDatum.class, AuthorityFactoryIdentifier.DATUM) {
             @Override EngineeringDatum create(GeodeticAuthorityFactory factory, String code) throws FactoryException {
                 return factory.createEngineeringDatum(code);
             }
@@ -195,7 +205,7 @@ abstract class AuthorityFactoryProxy<T>
     };
 
     static final AuthorityFactoryProxy<ImageDatum> IMAGE_DATUM =
-        new AuthorityFactoryProxy<ImageDatum>(ImageDatum.class) {
+        new AuthorityFactoryProxy<ImageDatum>(ImageDatum.class, AuthorityFactoryIdentifier.DATUM) {
             @Override ImageDatum create(GeodeticAuthorityFactory factory, String code) throws FactoryException {
                 return factory.createImageDatum(code);
             }
@@ -205,7 +215,7 @@ abstract class AuthorityFactoryProxy<T>
     };
 
     static final AuthorityFactoryProxy<VerticalDatum> VERTICAL_DATUM =
-        new AuthorityFactoryProxy<VerticalDatum>(VerticalDatum.class) {
+        new AuthorityFactoryProxy<VerticalDatum>(VerticalDatum.class, AuthorityFactoryIdentifier.DATUM) {
             @Override VerticalDatum create(GeodeticAuthorityFactory factory, String code) throws FactoryException {
                 return factory.createVerticalDatum(code);
             }
@@ -215,7 +225,7 @@ abstract class AuthorityFactoryProxy<T>
     };
 
     static final AuthorityFactoryProxy<TemporalDatum> TEMPORAL_DATUM =
-        new AuthorityFactoryProxy<TemporalDatum>(TemporalDatum.class) {
+        new AuthorityFactoryProxy<TemporalDatum>(TemporalDatum.class, AuthorityFactoryIdentifier.DATUM) {
             @Override TemporalDatum create(GeodeticAuthorityFactory factory, String code) throws FactoryException {
                 return factory.createTemporalDatum(code);
             }
@@ -225,7 +235,7 @@ abstract class AuthorityFactoryProxy<T>
     };
 
     static final AuthorityFactoryProxy<GeodeticDatum> GEODETIC_DATUM =
-        new AuthorityFactoryProxy<GeodeticDatum>(GeodeticDatum.class) {
+        new AuthorityFactoryProxy<GeodeticDatum>(GeodeticDatum.class, AuthorityFactoryIdentifier.DATUM) {
             @Override GeodeticDatum create(GeodeticAuthorityFactory factory, String code) throws FactoryException {
                 return factory.createGeodeticDatum(code);
             }
@@ -235,7 +245,7 @@ abstract class AuthorityFactoryProxy<T>
     };
 
     static final AuthorityFactoryProxy<Ellipsoid> ELLIPSOID =
-        new AuthorityFactoryProxy<Ellipsoid>(Ellipsoid.class) {
+        new AuthorityFactoryProxy<Ellipsoid>(Ellipsoid.class, AuthorityFactoryIdentifier.DATUM) {
             @Override Ellipsoid create(GeodeticAuthorityFactory factory, String code) throws FactoryException {
                 return factory.createEllipsoid(code);
             }
@@ -245,7 +255,7 @@ abstract class AuthorityFactoryProxy<T>
     };
 
     static final AuthorityFactoryProxy<PrimeMeridian> PRIME_MERIDIAN =
-        new AuthorityFactoryProxy<PrimeMeridian>(PrimeMeridian.class) {
+        new AuthorityFactoryProxy<PrimeMeridian>(PrimeMeridian.class, AuthorityFactoryIdentifier.DATUM) {
             @Override PrimeMeridian create(GeodeticAuthorityFactory factory, String code) throws FactoryException {
                 return factory.createPrimeMeridian(code);
             }
@@ -255,7 +265,7 @@ abstract class AuthorityFactoryProxy<T>
     };
 
     static final AuthorityFactoryProxy<Extent> EXTENT =
-        new AuthorityFactoryProxy<Extent>(Extent.class) {
+        new AuthorityFactoryProxy<Extent>(Extent.class, AuthorityFactoryIdentifier.GEODETIC) {
             @Override Extent create(GeodeticAuthorityFactory factory, String code) throws FactoryException {
                 return factory.createExtent(code);
             }
@@ -265,7 +275,7 @@ abstract class AuthorityFactoryProxy<T>
     };
 
     static final AuthorityFactoryProxy<CoordinateSystem> COORDINATE_SYSTEM =
-        new AuthorityFactoryProxy<CoordinateSystem>(CoordinateSystem.class) {
+        new AuthorityFactoryProxy<CoordinateSystem>(CoordinateSystem.class, AuthorityFactoryIdentifier.CS) {
             @Override CoordinateSystem create(GeodeticAuthorityFactory factory, String code) throws FactoryException {
                 return factory.createCoordinateSystem(code);
             }
@@ -275,7 +285,7 @@ abstract class AuthorityFactoryProxy<T>
     };
 
     static final AuthorityFactoryProxy<CartesianCS> CARTESIAN_CS =
-        new AuthorityFactoryProxy<CartesianCS>(CartesianCS.class) {
+        new AuthorityFactoryProxy<CartesianCS>(CartesianCS.class, AuthorityFactoryIdentifier.CS) {
             @Override CartesianCS create(GeodeticAuthorityFactory factory, String code) throws FactoryException {
                 return factory.createCartesianCS(code);
             }
@@ -285,7 +295,7 @@ abstract class AuthorityFactoryProxy<T>
     };
 
     static final AuthorityFactoryProxy<PolarCS> POLAR_CS =
-        new AuthorityFactoryProxy<PolarCS>(PolarCS.class) {
+        new AuthorityFactoryProxy<PolarCS>(PolarCS.class, AuthorityFactoryIdentifier.CS) {
             @Override PolarCS create(GeodeticAuthorityFactory factory, String code) throws FactoryException {
                 return factory.createPolarCS(code);
             }
@@ -295,7 +305,7 @@ abstract class AuthorityFactoryProxy<T>
     };
 
     static final AuthorityFactoryProxy<CylindricalCS> CYLINDRICAL_CS =
-        new AuthorityFactoryProxy<CylindricalCS>(CylindricalCS.class) {
+        new AuthorityFactoryProxy<CylindricalCS>(CylindricalCS.class, AuthorityFactoryIdentifier.CS) {
             @Override CylindricalCS create(GeodeticAuthorityFactory factory, String code) throws FactoryException {
                 return factory.createCylindricalCS(code);
             }
@@ -305,7 +315,7 @@ abstract class AuthorityFactoryProxy<T>
     };
 
     static final AuthorityFactoryProxy<SphericalCS> SPHERICAL_CS =
-        new AuthorityFactoryProxy<SphericalCS>(SphericalCS.class) {
+        new AuthorityFactoryProxy<SphericalCS>(SphericalCS.class, AuthorityFactoryIdentifier.CS) {
             @Override SphericalCS create(GeodeticAuthorityFactory factory, String code) throws FactoryException {
                 return factory.createSphericalCS(code);
             }
@@ -315,7 +325,7 @@ abstract class AuthorityFactoryProxy<T>
     };
 
     static final AuthorityFactoryProxy<EllipsoidalCS> ELLIPSOIDAL_CS =
-        new AuthorityFactoryProxy<EllipsoidalCS>(EllipsoidalCS.class) {
+        new AuthorityFactoryProxy<EllipsoidalCS>(EllipsoidalCS.class, AuthorityFactoryIdentifier.CS) {
             @Override EllipsoidalCS create(GeodeticAuthorityFactory factory, String code) throws FactoryException {
                 return factory.createEllipsoidalCS(code);
             }
@@ -325,7 +335,7 @@ abstract class AuthorityFactoryProxy<T>
     };
 
     static final AuthorityFactoryProxy<VerticalCS> VERTICAL_CS =
-        new AuthorityFactoryProxy<VerticalCS>(VerticalCS.class) {
+        new AuthorityFactoryProxy<VerticalCS>(VerticalCS.class, AuthorityFactoryIdentifier.CS) {
             @Override VerticalCS create(GeodeticAuthorityFactory factory, String code) throws FactoryException {
                 return factory.createVerticalCS(code);
             }
@@ -335,7 +345,7 @@ abstract class AuthorityFactoryProxy<T>
     };
 
     static final AuthorityFactoryProxy<TimeCS> TIME_CS =
-        new AuthorityFactoryProxy<TimeCS>(TimeCS.class) {
+        new AuthorityFactoryProxy<TimeCS>(TimeCS.class, AuthorityFactoryIdentifier.CS) {
             @Override TimeCS create(GeodeticAuthorityFactory factory, String code) throws FactoryException {
                 return factory.createTimeCS(code);
             }
@@ -345,7 +355,7 @@ abstract class AuthorityFactoryProxy<T>
     };
 
     static final AuthorityFactoryProxy<CoordinateSystemAxis> AXIS =
-        new AuthorityFactoryProxy<CoordinateSystemAxis>(CoordinateSystemAxis.class) {
+        new AuthorityFactoryProxy<CoordinateSystemAxis>(CoordinateSystemAxis.class, AuthorityFactoryIdentifier.CS) {
             @Override CoordinateSystemAxis create(GeodeticAuthorityFactory factory, String code) throws FactoryException {
                 return factory.createCoordinateSystemAxis(code);
             }
@@ -356,7 +366,7 @@ abstract class AuthorityFactoryProxy<T>
 
     @SuppressWarnings({"rawtypes","unchecked"})
     static final AuthorityFactoryProxy<Unit<?>> UNIT =
-        new AuthorityFactoryProxy<Unit<?>>((Class) Unit.class) {
+        new AuthorityFactoryProxy<Unit<?>>((Class) Unit.class, AuthorityFactoryIdentifier.CS) {
             @Override Unit<?> create(GeodeticAuthorityFactory factory, String code) throws FactoryException {
                 return factory.createUnit(code);
             }
@@ -366,7 +376,7 @@ abstract class AuthorityFactoryProxy<T>
     };
 
     static final AuthorityFactoryProxy<CoordinateReferenceSystem> CRS =
-        new AuthorityFactoryProxy<CoordinateReferenceSystem>(CoordinateReferenceSystem.class) {
+        new AuthorityFactoryProxy<CoordinateReferenceSystem>(CoordinateReferenceSystem.class, AuthorityFactoryIdentifier.CRS) {
             @Override CoordinateReferenceSystem create(GeodeticAuthorityFactory factory, String code) throws FactoryException {
                 return factory.createCoordinateReferenceSystem(code);
             }
@@ -376,7 +386,7 @@ abstract class AuthorityFactoryProxy<T>
     };
 
     static final AuthorityFactoryProxy<CompoundCRS> COMPOUND_CRS =
-        new AuthorityFactoryProxy<CompoundCRS>(CompoundCRS.class) {
+        new AuthorityFactoryProxy<CompoundCRS>(CompoundCRS.class, AuthorityFactoryIdentifier.CRS) {
             @Override CompoundCRS create(GeodeticAuthorityFactory factory, String code) throws FactoryException {
                 return factory.createCompoundCRS(code);
             }
@@ -386,7 +396,7 @@ abstract class AuthorityFactoryProxy<T>
     };
 
     static final AuthorityFactoryProxy<DerivedCRS> DERIVED_CRS =
-        new AuthorityFactoryProxy<DerivedCRS>(DerivedCRS.class) {
+        new AuthorityFactoryProxy<DerivedCRS>(DerivedCRS.class, AuthorityFactoryIdentifier.CRS) {
             @Override DerivedCRS create(GeodeticAuthorityFactory factory, String code) throws FactoryException {
                 return factory.createDerivedCRS(code);
             }
@@ -396,7 +406,7 @@ abstract class AuthorityFactoryProxy<T>
     };
 
     static final AuthorityFactoryProxy<EngineeringCRS> ENGINEERING_CRS =
-        new AuthorityFactoryProxy<EngineeringCRS>(EngineeringCRS.class) {
+        new AuthorityFactoryProxy<EngineeringCRS>(EngineeringCRS.class, AuthorityFactoryIdentifier.CRS) {
             @Override EngineeringCRS create(GeodeticAuthorityFactory factory, String code) throws FactoryException {
                 return factory.createEngineeringCRS(code);
             }
@@ -406,7 +416,7 @@ abstract class AuthorityFactoryProxy<T>
     };
 
     static final AuthorityFactoryProxy<GeographicCRS> GEOGRAPHIC_CRS =
-        new AuthorityFactoryProxy<GeographicCRS>(GeographicCRS.class) {
+        new AuthorityFactoryProxy<GeographicCRS>(GeographicCRS.class, AuthorityFactoryIdentifier.CRS) {
             @Override GeographicCRS create(GeodeticAuthorityFactory factory, String code) throws FactoryException {
                 return factory.createGeographicCRS(code);
             }
@@ -416,7 +426,7 @@ abstract class AuthorityFactoryProxy<T>
     };
 
     static final AuthorityFactoryProxy<GeocentricCRS> GEOCENTRIC_CRS =
-        new AuthorityFactoryProxy<GeocentricCRS>(GeocentricCRS.class) {
+        new AuthorityFactoryProxy<GeocentricCRS>(GeocentricCRS.class, AuthorityFactoryIdentifier.CRS) {
             @Override GeocentricCRS create(GeodeticAuthorityFactory factory, String code) throws FactoryException {
                 return factory.createGeocentricCRS(code);
             }
@@ -426,7 +436,7 @@ abstract class AuthorityFactoryProxy<T>
     };
 
     static final AuthorityFactoryProxy<ImageCRS> IMAGE_CRS =
-        new AuthorityFactoryProxy<ImageCRS>(ImageCRS.class) {
+        new AuthorityFactoryProxy<ImageCRS>(ImageCRS.class, AuthorityFactoryIdentifier.CRS) {
             @Override ImageCRS create(GeodeticAuthorityFactory factory, String code) throws FactoryException {
                 return factory.createImageCRS(code);
             }
@@ -436,7 +446,7 @@ abstract class AuthorityFactoryProxy<T>
     };
 
     static final AuthorityFactoryProxy<ProjectedCRS> PROJECTED_CRS =
-        new AuthorityFactoryProxy<ProjectedCRS>(ProjectedCRS.class) {
+        new AuthorityFactoryProxy<ProjectedCRS>(ProjectedCRS.class, AuthorityFactoryIdentifier.CRS) {
             @Override ProjectedCRS create(GeodeticAuthorityFactory factory, String code) throws FactoryException {
                 return factory.createProjectedCRS(code);
             }
@@ -446,7 +456,7 @@ abstract class AuthorityFactoryProxy<T>
     };
 
     static final AuthorityFactoryProxy<TemporalCRS> TEMPORAL_CRS =
-        new AuthorityFactoryProxy<TemporalCRS>(TemporalCRS.class) {
+        new AuthorityFactoryProxy<TemporalCRS>(TemporalCRS.class, AuthorityFactoryIdentifier.CRS) {
             @Override TemporalCRS create(GeodeticAuthorityFactory factory, String code) throws FactoryException {
                 return factory.createTemporalCRS(code);
             }
@@ -456,7 +466,7 @@ abstract class AuthorityFactoryProxy<T>
     };
 
     static final AuthorityFactoryProxy<VerticalCRS> VERTICAL_CRS =
-        new AuthorityFactoryProxy<VerticalCRS>(VerticalCRS.class) {
+        new AuthorityFactoryProxy<VerticalCRS>(VerticalCRS.class, AuthorityFactoryIdentifier.CRS) {
             @Override VerticalCRS create(GeodeticAuthorityFactory factory, String code) throws FactoryException {
                 return factory.createVerticalCRS(code);
             }
@@ -467,7 +477,7 @@ abstract class AuthorityFactoryProxy<T>
 
     @SuppressWarnings("rawtypes")
     static final AuthorityFactoryProxy<ParameterDescriptor> PARAMETER =
-        new AuthorityFactoryProxy<ParameterDescriptor>(ParameterDescriptor.class) {
+        new AuthorityFactoryProxy<ParameterDescriptor>(ParameterDescriptor.class, AuthorityFactoryIdentifier.GEODETIC) {
             @Override ParameterDescriptor<?> create(GeodeticAuthorityFactory factory, String code) throws FactoryException {
                 return factory.createParameterDescriptor(code);
             }
@@ -477,7 +487,7 @@ abstract class AuthorityFactoryProxy<T>
     };
 
     static final AuthorityFactoryProxy<OperationMethod> METHOD =
-        new AuthorityFactoryProxy<OperationMethod>(OperationMethod.class) {
+        new AuthorityFactoryProxy<OperationMethod>(OperationMethod.class, AuthorityFactoryIdentifier.OPERATION) {
             @Override OperationMethod create(GeodeticAuthorityFactory factory, String code) throws FactoryException {
                 return factory.createOperationMethod(code);
             }
@@ -487,7 +497,7 @@ abstract class AuthorityFactoryProxy<T>
     };
 
     static final AuthorityFactoryProxy<CoordinateOperation> OPERATION =
-        new AuthorityFactoryProxy<CoordinateOperation>(CoordinateOperation.class) {
+        new AuthorityFactoryProxy<CoordinateOperation>(CoordinateOperation.class, AuthorityFactoryIdentifier.OPERATION) {
             @Override CoordinateOperation create(GeodeticAuthorityFactory factory, String code) throws FactoryException {
                 return factory.createCoordinateOperation(code);
             }
@@ -497,6 +507,70 @@ abstract class AuthorityFactoryProxy<T>
     };
 
     /**
+     * The list of all proxies. The most specific types must appear first in this array,
+     * with a preference for those who are more likely to be requested.
+     * This field can be declared only after all the above constants.
+     */
+    static final AuthorityFactoryProxy<?>[] PROXIES = new AuthorityFactoryProxy<?>[] {
+        PROJECTED_CRS,      // Special kind of GeneralDerivedCRS.
+        GEOGRAPHIC_CRS,     // Special kind of GeodeticCRS.
+        GEOCENTRIC_CRS,     // Special kind of GeodeticCRS.
+        VERTICAL_CRS,
+        TEMPORAL_CRS,
+        IMAGE_CRS,          // Can been seen as a special kind of EngineeringCRS (even if not shown in hierarchy).
+        ENGINEERING_CRS,
+        DERIVED_CRS,        // DerivedCRS can be also Vertical, Temporal or Engineering CRS. Give precedence to those.
+        COMPOUND_CRS,
+        CRS,
+        GEODETIC_DATUM,
+        VERTICAL_DATUM,
+        TEMPORAL_DATUM,
+        IMAGE_DATUM,        // Can been seen as a special kind of EngineeringDatum (even if not shown in hierarchy).
+        ENGINEERING_DATUM,
+        DATUM,
+        ELLIPSOID,
+        PRIME_MERIDIAN,
+        CARTESIAN_CS,       // Special case of AffineCS.
+        ELLIPSOIDAL_CS,
+        SPHERICAL_CS,
+        CYLINDRICAL_CS,
+        POLAR_CS,
+        VERTICAL_CS,
+        TIME_CS,
+        COORDINATE_SYSTEM,
+        AXIS,
+        OPERATION,
+        METHOD,
+        PARAMETER,
+        UNIT,
+        EXTENT,
+        OBJECT
+    };
+
+    /**
+     * The proxy to use for a given type declared in a URN.
+     * For example in the {@code "urn:ogc:def:crs:EPSG::4326"} URN, the proxy to use is {@link #CRS}.
+     *
+     * <p>Keys must be in lower case.</p>
+     */
+    private static final Map<String, AuthorityFactoryProxy<?>> BY_URN_TYPE;
+    static {
+        final Map<String, AuthorityFactoryProxy<?>> map = new HashMap<>(14);
+        map.put("crs",                  CRS);
+        map.put("datum",                DATUM);
+        map.put("ellipsoid",            ELLIPSOID);
+        map.put("meridian",             PRIME_MERIDIAN);
+        map.put("cs",                   COORDINATE_SYSTEM);
+        map.put("axis",                 AXIS);
+        map.put("coordinateoperation",  OPERATION);
+        map.put("method",               METHOD);
+        map.put("parameter",            PARAMETER);
+        map.put("referencesystem",      CRS);
+        map.put("uom",                  UNIT);
+        BY_URN_TYPE = map;
+    }
+
+    /**
      * Returns the instance for the given type. The {@code type} argument can be a GeoAPI interface
      * or some implementation class like {@link org.apache.sis.referencing.crs.DefaultProjectedCRS}.
      * This method returns the most specific proxy for the given type.
@@ -519,42 +593,13 @@ abstract class AuthorityFactoryProxy<T>
     }
 
     /**
-     * The types of proxies. The most specific types must appear first in this list.
-     * This field can be declared only after all the above constants.
+     * The proxy to use for a given type declared in a URN.
+     * For example in the {@code "urn:ogc:def:crs:EPSG::4326"} URN, the proxy to use is {@link #CRS}.
+     *
+     * @param  type The URN type.
+     * @return The proxy for the given type, or {@code null} if none.
      */
-    static final AuthorityFactoryProxy<?>[] PROXIES = new AuthorityFactoryProxy<?>[] {
-        OPERATION,
-        METHOD,
-        PARAMETER,
-        PROJECTED_CRS,
-        GEOGRAPHIC_CRS,
-        GEOCENTRIC_CRS,
-        IMAGE_CRS,
-        DERIVED_CRS,
-        VERTICAL_CRS,
-        TEMPORAL_CRS,
-        ENGINEERING_CRS,
-        COMPOUND_CRS,
-        CRS,
-        AXIS,
-        CARTESIAN_CS,
-        ELLIPSOIDAL_CS,
-        SPHERICAL_CS,
-        CYLINDRICAL_CS,
-        POLAR_CS,
-        VERTICAL_CS,
-        TIME_CS,
-        COORDINATE_SYSTEM,
-        PRIME_MERIDIAN,
-        ELLIPSOID,
-        GEODETIC_DATUM,
-        IMAGE_DATUM,
-        VERTICAL_DATUM,
-        TEMPORAL_DATUM,
-        ENGINEERING_DATUM,
-        DATUM,
-        EXTENT,
-        UNIT,
-        OBJECT
-    };
+    static AuthorityFactoryProxy<?> getInstance(final String type) {
+        return BY_URN_TYPE.get(type.toLowerCase(Locale.US));
+    }
 }

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/CommonAuthorityFactory.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/CommonAuthorityFactory.java?rev=1725653&r1=1725652&r2=1725653&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/CommonAuthorityFactory.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/CommonAuthorityFactory.java [UTF-8] Tue Jan 19 23:50:29 2016
@@ -20,7 +20,9 @@ import java.util.Map;
 import java.util.Set;
 import java.util.HashMap;
 import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
 import java.util.Collections;
+import java.util.Arrays;
 import javax.measure.unit.SI;
 import javax.measure.unit.NonSI;
 import javax.measure.unit.Unit;
@@ -200,6 +202,14 @@ public class CommonAuthorityFactory exte
     private static final String AUTO2 = "AUTO2";
 
     /**
+     * The namespaces of codes defined by OGC.
+     *
+     * @see #getCodeSpaces()
+     */
+    private static final Set<String> CODESPACES = Collections.unmodifiableSet(
+            new LinkedHashSet<>(Arrays.asList(Constants.OGC, Constants.CRS, "AUTO", AUTO2)));
+
+    /**
      * The bit for saying that a namespace is the legacy {@code "AUTO"} namespace.
      */
     private static final int LEGACY_MASK = 0x80000000;
@@ -267,13 +277,6 @@ public class CommonAuthorityFactory exte
     }
 
     /**
-     * Returns {@code true} if the given portion of the code is equal, ignoring case, to the given namespace.
-     */
-    private static boolean regionMatches(final String namespace, final String code, final int start, final int end) {
-        return (namespace.length() == end - start) && code.regionMatches(true, start, namespace, 0, namespace.length());
-    }
-
-    /**
      * Returns the index where the code begins, ignoring spaces and the {@code "OGC"}, {@code "CRS"}, {@code "AUTO"},
      * {@code "AUTO1"} or {@code "AUTO2"} namespaces if present. If a namespace is found and is a legacy one, then
      * this {@link #LEGACY_MASK} bit will be set.
@@ -372,6 +375,16 @@ public class CommonAuthorityFactory exte
     }
 
     /**
+     * Returns the namespaces of codes defined by OGC.
+     *
+     * @return A set containing at least the {@code "CRS"}, {@code "AUTO"} and {@code "AUTO2"} strings.
+     */
+    @Override
+    public Set<String> getCodeSpaces() {
+        return CODESPACES;
+    }
+
+    /**
      * Returns a description of the object corresponding to a code.
      * The description can be used for example in a combo box in a graphical user interface.
      *

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/ConcurrentAuthorityFactory.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/ConcurrentAuthorityFactory.java?rev=1725653&r1=1725652&r2=1725653&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/ConcurrentAuthorityFactory.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/ConcurrentAuthorityFactory.java [UTF-8] Tue Jan 19 23:50:29 2016
@@ -762,9 +762,8 @@ public abstract class ConcurrentAuthorit
      *
      * <p>The default implementation performs the following steps:</p>
      * <ol>
-     *   <li>Removes the authority scope if presents. For example if the {@linkplain #getAuthority() authority}
-     *       is EPSG and the given code starts with the {@code "EPSG:"} prefix, then that prefix is removed.
-     *       Otherwise, the scope is unchanged.</li>
+     *   <li>Removes the namespace if presents. For example if the {@linkplain #getCodeSpaces() codespace}
+     *       is EPSG and the given code starts with the {@code "EPSG:"} prefix, then that prefix is removed.</li>
      *   <li>Removes leading and trailing spaces.</li>
      * </ol>
      *
@@ -777,7 +776,7 @@ public abstract class ConcurrentAuthorit
      * @throws FactoryException if an error occurred while normalizing the given code.
      */
     protected String normalizeCode(String code) throws FactoryException {
-        return trimAuthority(code, null);
+        return trimNamespace(code);
     }
 
     /**

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/GeodeticAuthorityFactory.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/GeodeticAuthorityFactory.java?rev=1725653&r1=1725652&r2=1725653&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/GeodeticAuthorityFactory.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/GeodeticAuthorityFactory.java [UTF-8] Tue Jan 19 23:50:29 2016
@@ -102,6 +102,44 @@ public abstract class GeodeticAuthorityF
     public abstract Citation getAuthority();
 
     /**
+     * Returns all namespaces recognized by this factory. Those namespaces can appear before codes in
+     * calls to {@code createFoo(String)} methods, for example {@code "EPSG"} in {@code "EPSG::4326"}.
+     * Namespaces are case-insensitive.
+     *
+     * <p>The namespaces are closely related to the {@linkplain #getAuthority() authority}. Often the namespace is
+     * the authority {@linkplain org.apache.sis.metadata.iso.citation.DefaultCitation#getIdentifiers() identifier},
+     * but not always.</p>
+     *
+     * <div class="note"><b>Examples:</b>
+     * <ul>
+     *   <li><p>The {@link org.apache.sis.referencing.factory.sql.EPSGFactory} authority identifier is {@code "EPSG"}
+     *       and its {@code getCodeSpaces()} method returns a set containing {@code "EPSG"}. So in this example,
+     *       authority and namespace match. That namespace value means that {@code EPSGFactory.createFoo(String)}
+     *       methods accept both {@code "EPSG::4326"} (case-insensitive) and {@code "4326"} codes as argument.</p></li>
+     *
+     *   <li><p>The {@link org.apache.sis.referencing.factory.sql.EPSGDataAccess} authority identifier is {@code "EPSG"}
+     *       but its {@code getCodeSpaces()} method returns an empty set. This means that despite the EPSG authority,
+     *       {@code EPSGDataAccess.createFoo(String)} methods accept only codes like {@code "4326"} without
+     *       {@code "EPSG:"} prefix (the reason is that {@code EPSGDataAccess} is not expected to be used directly).</p></li>
+     *
+     *   <li><p>The {@link CommonAuthorityFactory} authority identifier is {@code "OGC"} but its {@code getCodeSpaces()}
+     *       method returns a set containing {@code "CRS"}, {@code "AUTO"} and {@code "AUTO2"}.
+     *       While OGC is the authority defining those namespaces, the {@code "OGC"} string itself
+     *       is not used as a namespace for CRS objects (in theory — in practice some do).</p></li>
+     * </ul></div>
+     *
+     * The default implementation infers the namespace from the {@linkplain #getAuthority() authority}.
+     * Subclasses can override this method, but the set should always contain the same elements during
+     * all factory lifetime.
+     *
+     * @return The namespaces recognized by this factory, or an empty set if none.
+     */
+    public Set<String> getCodeSpaces() {
+        final String authority = Citations.getCodeSpace(getAuthority());
+        return (authority != null) ? Collections.singleton(authority) : Collections.emptySet();
+    }
+
+    /**
      * Returns a description of the object corresponding to a code.
      * The description can be used for example in a combo box in a graphical user interface.
      *
@@ -1125,33 +1163,41 @@ public abstract class GeodeticAuthorityF
     }
 
     /**
-     * Trims the authority scope, if present. For example if this factory is an EPSG authority factory
+     * Returns {@code true} if the given portion of the code is equal, ignoring case, to the given namespace.
+     */
+    static boolean regionMatches(final String namespace, final String code, final int start, final int end) {
+        return (namespace.length() == end - start) && code.regionMatches(true, start, namespace, 0, namespace.length());
+    }
+
+    /**
+     * Trims the namespace, if present. For example if this factory is an EPSG authority factory
      * and the specified code start with the {@code "EPSG:"} prefix, then the prefix is removed.
      * Otherwise, the string is returned unchanged (except for leading and trailing spaces).
      *
      * @param  code The code to trim.
-     * @param  authority The authority factory, or {@code null} for {@link #getAuthority()}.
-     * @return The code with the authority part removed if that part matched the expected authority.
+     * @return The code with the namespace part removed if that part matched one of the values given by
+     *         {@link #getCodeSpaces()}.
      */
-    final String trimAuthority(final String code, Citation authority) {
+    final String trimNamespace(final String code) {
         int s = code.indexOf(DefaultNameSpace.DEFAULT_SEPARATOR);
         if (s >= 0) {
-            if (authority == null) {
-                authority = getAuthority();     // Costly operation for EPSGDataAccess.
-            }
-            if (Citations.identifierMatches(authority, null, code.substring(0, s))) {    // Comparison ignores spaces.
-                final int n = code.indexOf(DefaultNameSpace.DEFAULT_SEPARATOR, s + 1);
-                if (n >= 0) {
-                    /*
-                     * The separator sometime appears twice, as in "EPSG::4326" or "EPSG:8.8:4326".
-                     * The part between the two separators is the verion number, which we ignore in
-                     * this simple version.
-                     */
-                    s = n;
+            final int end   = CharSequences.skipTrailingWhitespaces(code, 0, s);
+            final int start = CharSequences.skipLeadingWhitespaces (code, 0, end);
+            for (final String codespace : getCodeSpaces()) {
+                if (regionMatches(codespace, code, start, end)) {
+                    final int n = code.indexOf(DefaultNameSpace.DEFAULT_SEPARATOR, s + 1);
+                    if (n >= 0) {
+                        /*
+                         * The separator sometime appears twice, as in "EPSG::4326" or "EPSG:8.8:4326".
+                         * The part between the two separators is the verion number, which we ignore in
+                         * this simple version.
+                         */
+                        s = n;
+                    }
+                    final int length = code.length();
+                    s = CharSequences.skipLeadingWhitespaces(code, s+1, length);
+                    return code.substring(s, CharSequences.skipTrailingWhitespaces(code, s, length));
                 }
-                final int length = code.length();
-                s = CharSequences.skipLeadingWhitespaces(code, s+1, length);
-                return code.substring(s, CharSequences.skipTrailingWhitespaces(code, s, length));
             }
         }
         return CharSequences.trimWhitespaces(code);
@@ -1191,7 +1237,7 @@ public abstract class GeodeticAuthorityF
         final Identifier id = object.getName();
         final Citation authority = (id != null) ? id.getAuthority() : getAuthority();
         throw new NoSuchAuthorityCodeException(Errors.format(Errors.Keys.UnexpectedTypeForReference_3, code, type, actual),
-                Citations.getIdentifier(authority, false), trimAuthority(code, authority), code);
+                Citations.getIdentifier(authority, false), trimNamespace(code), code);
     }
 
     /**

Added: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/MultiAuthoritiesFactory.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/MultiAuthoritiesFactory.java?rev=1725653&view=auto
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/MultiAuthoritiesFactory.java (added)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/MultiAuthoritiesFactory.java [UTF-8] Tue Jan 19 23:50:29 2016
@@ -0,0 +1,423 @@
+/*
+ * 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.referencing.factory;
+
+import java.util.ServiceLoader;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicInteger;
+import org.opengis.referencing.*;
+import org.opengis.referencing.cs.*;
+import org.opengis.referencing.crs.*;
+import org.opengis.referencing.datum.*;
+import org.opengis.referencing.operation.*;
+import org.opengis.metadata.citation.Citation;
+import org.opengis.util.FactoryException;
+import org.apache.sis.internal.util.Citations;
+import org.apache.sis.internal.util.DefinitionURI;
+import org.apache.sis.util.ArraysExt;
+import org.apache.sis.util.CharSequences;
+import org.apache.sis.util.ArgumentChecks;
+import org.apache.sis.util.resources.Errors;
+import org.apache.sis.util.iso.DefaultNameSpace;
+
+
+/**
+ * A factory that delegates the object creation to another factory determined from the <var>authority</var> part
+ * in {@code "}<var>authority</var>{@code :}<var>code</var>{code "} arguments.
+ * The list of factories to use as delegates can be specified at construction time.
+ *
+ * <p>This factory requires that every codes given to a {@code createFoo(String)} method are prefixed by
+ * the authority name, for example {@code "EPSG:4326"}. When a {@code createFoo(String)} method is invoked,
+ * this class extracts the authority name from the {@code "authority:code"} argument and searches
+ * for a factory for that authority in the list of factories given at construction time.
+ * If a factory is found, then the work is delegated to that factory.
+ * Otherwise a {@link NoSuchAuthorityCodeException} is thrown.</p>
+ *
+ * <p>This factory can also parse URNs of the form
+ * {@code "urn:ogc:def:}<var>type</var>{@code :}<var>authority</var>{@code :}<var>version</var>{@code :}<var>code</var>{@code "}.
+ * In such case, the <var>type</var> specified in the URN may be used for invoking a more specific method.
+ * However {@code MultiAuthoritiesFactory} uses the type information in the URN only for
+ * delegating to a more specific method, never for delegating to a less specific method.
+ * An exception will be thrown if the type in the URN is incompatible with the method invoked.</p>
+ *
+ * <div class="note"><b>Example:</b>
+ * if the {@link #createObject(String)} method is invoked with the <code>"urn:ogc:def:<b>crs</b>:EPSG::4326"</code>
+ * URN, then {@code MultiAuthoritiesFactory} will delegate (indirectly, ignoring caching for this example) the object
+ * creation to {@link org.apache.sis.referencing.factory.sql.EPSGDataAccess#createCoordinateReferenceSystem(String)}
+ * instead of {@link org.apache.sis.referencing.factory.sql.EPSGDataAccess#createObject(String)} because of the
+ * {@code "crs"} part in the URN. The more specific method gives more performances and avoid ambiguities.</div>
+ *
+ * <div class="section">Multiple versions for the same authority</div>
+ * {@code MultiAuthoritiesFactory} accepts an arbitrary amount of factories for the same authority, provided that
+ * those factories have different version numbers. If a {@code createFoo(String)} method is invoked with a URN
+ * containing a version number, then {@code MultiAuthoritiesFactory} will search for a factory with that exact
+ * version, or throw a {@link NoSuchAuthorityCodeException} if no suitable factory is found.
+ * If a {@code createFoo(String)} method is invoked with the version number omitted, then {@code MultiAuthoritiesFactory}
+ * will use the first factory in iteration order for the requested authority regardless of its version number.
+ *
+ * <div class="note"><b>Example:</b>
+ * a {@code MultiAuthoritiesFactory} instance could contain two {@code EPSGFactory} instances:
+ * one for version 8.2 of the EPSG dataset and another one for version 7.9 of the EPSG dataset.
+ * A specific version can be requested in the URN given to {@code createFoo(String)} methods,
+ * for example <code>"urn:ogc:def:crs:EPSG:<b>8.2</b>:4326"</code>.
+ * If no version is given as in {@code "urn:ogc:def:crs:EPSG::4326"},
+ * then the first EPSG factory in iteration order is used regardless of its version number.
+ * </div>
+ *
+ * <div class="section">Multi-threading</div>
+ * This class is thread-safe if all delegate factories are themselves thread-safe.
+ * However the factory <em>providers</em>, which are given to the constructor as
+ * {@code Iterable<? extends AuthorityFactory>} instances, do not need to be thread-safe.
+ * See constructor Javadoc for more information.
+ *
+ * @author  Martin Desruisseaux (IRD, Geomatys)
+ * @since   0.7
+ * @version 0.7
+ * @module
+ */
+public abstract class MultiAuthoritiesFactory extends GeodeticAuthorityFactory implements CRSAuthorityFactory,
+        CSAuthorityFactory, DatumAuthorityFactory, CoordinateOperationAuthorityFactory
+{
+    /**
+     * The factory providers given at construction time. Elements in the array are for {@link CRSAuthorityFactory},
+     * {@link CSAuthorityFactory}, {@link DatumAuthorityFactory} and {@link CoordinateOperationAuthorityFactory}
+     * in that order. That order is defined by the constant values in {@link AuthorityFactoryIdentifier}.
+     *
+     * <p>Note that this array is shorter than the amount of {@link AuthorityFactoryIdentifier} values.
+     * The last {@link AuthorityFactoryIdentifier} values are handled in a special way.</p>
+     *
+     * <p>The array may contain {@code null} elements when there is no provider for a given type.
+     * Content of this array shall be immutable after construction time in order to avoid the need
+     * for synchronization when reading the array. However usage of an {@code Iterable} element
+     * shall be synchronized on that {@code Iterable}.</p>
+     */
+    private final Iterable<? extends AuthorityFactory>[] providers;
+
+    /**
+     * The factories obtained from the {@link #iterators}.
+     */
+    private final ConcurrentMap<AuthorityFactoryIdentifier, AuthorityFactory> factories;
+
+    /**
+     * A bit masks identifying which providers have given us all their factories.
+     */
+    private final AtomicInteger iterationCompleted;
+
+    /**
+     * Creates a new multi-factory using the given lists of factories.
+     * Calls to {@code createFoo(String)} methods will scan the supplied factories in their iteration order when first needed.
+     * The first factory having the expected {@linkplain GeodeticAuthorityFactory#getAuthority() authority name} will be used.
+     *
+     * <div class="section">Requirements</div>
+     * {@code MultiAuthoritiesFactory} may iterate over the same {@code Iterable} more than once.
+     * Each iteration <strong>shall</strong> return the same instances than previous iterations,
+     * unless {@link #reload()} has been invoked.
+     *
+     * <p>The {@code Iterable}s do not need to be thread-safe.
+     * {@code MultiAuthoritiesFactory} will use them only in blocks synchronized on the {@code Iterable} instance.
+     * For example all usages of {@code crsFactory} will be done inside a {@code synchronized(crsFactory)} block.</p>
+     *
+     * <div class="section">Name collision</div>
+     * If an {@code Iterable} contains more than one factory for the same namespace and version,
+     * then only the first occurrence will be used. All additional factories for the same namespace
+     * and version will be ignored, after a warning has been logged.
+     *
+     * <div class="section">Caching</div>
+     * {@code MultiAuthoritiesFactory} caches the factories found from the given {@code Iterable}s,
+     * but does not cache the objects created by those factories.
+     * This constructor assumes that the given factories already do their own caching.
+     *
+     * @param crsFactories   The factories for creating {@link CoordinateReferenceSystem} objects, or null if none.
+     * @param csFactories    The factories for creating {@link CoordinateSystem} objects, or null if none.
+     * @param datumFactories The factories for creating {@link Datum} objects, or null if none.
+     * @param copFactories   The factories for creating {@link CoordinateOperation} objects, or null if none.
+     */
+    @SuppressWarnings({"unchecked", "rawtypes", "empty-statement"})    // Generic array creation.
+    public MultiAuthoritiesFactory(final Iterable<? extends CRSAuthorityFactory> crsFactories,
+                                   final Iterable<? extends CSAuthorityFactory> csFactories,
+                                   final Iterable<? extends DatumAuthorityFactory> datumFactories,
+                                   final Iterable<? extends CoordinateOperationAuthorityFactory> copFactories)
+    {
+        final Iterable<? extends AuthorityFactory>[] p = new Iterable[4];
+        p[AuthorityFactoryIdentifier.CRS]       = crsFactories;
+        p[AuthorityFactoryIdentifier.CS]        = csFactories;
+        p[AuthorityFactoryIdentifier.DATUM]     = datumFactories;
+        p[AuthorityFactoryIdentifier.OPERATION] = copFactories;
+        /*
+         * Mark null Iterables as if we already iterated over all their elements.
+         * Opportunistically reduce the array size by trimming trailing null elements.
+         * The memory gain is negligible, but this will reduce the number of iterations in loops.
+         */
+        int length = 0, nullMask = 0;
+        for (int i=0; i < p.length; i++) {
+            if (p[i] != null) length = i+1;
+            else nullMask |= (1 << i);
+        }
+        providers = ArraysExt.resize(p, length);
+        factories = new ConcurrentHashMap<>();
+        iterationCompleted = new AtomicInteger(nullMask);
+    }
+
+    /**
+     * Returns the organization or party responsible for definition and maintenance of the database.
+     * The default implementation returns {@code null} since {@code MultiAuthoritiesFactory} is not
+     * about a particular authority.
+     */
+    @Override
+    public Citation getAuthority() {
+        return null;
+    }
+
+    /**
+     * Returns the code spaces for the given factory.
+     * This method delegates to {@link GeodeticAuthorityFactory#getCodeSpaces()} if possible,
+     * or reproduces its default implementation otherwise.
+     */
+    private static Set<String> getCodeSpaces(final AuthorityFactory factory) {
+        if (factory instanceof GeodeticAuthorityFactory) {
+            return ((GeodeticAuthorityFactory) factory).getCodeSpaces();
+        } else {
+            final String authority = Citations.getCodeSpace(factory.getAuthority());
+            return (authority != null) ? Collections.singleton(authority) : Collections.emptySet();
+        }
+    }
+
+    /**
+     * Caches the given factory, but without replacing existing instance if any.
+     * This method returns the factory that we should use, either the given instance of the cached one.
+     *
+     * @param  identifier The type, authority and version of the factory to cache.
+     * @param  factory The factory to cache.
+     * @return The given {@code factory} if no previous instance was cached, or the existing instance otherwise.
+     */
+    private AuthorityFactory cache(final AuthorityFactoryIdentifier identifier, final AuthorityFactory factory) {
+        final AuthorityFactory existing = factories.putIfAbsent(identifier.intern(), factory);
+        return (existing != null) ? existing : factory;
+    }
+
+    /**
+     * Returns the factory identified by the given type, authority and version. If no such factory is found in
+     * the cache, then this method iterates on the factories created by the providers given at construction time.
+     *
+     * @param  request The type, authority and version of the desired factory.
+     * @return The factory.
+     * @throws NoSuchAuthorityFactoryException if no suitable factory has been found.
+     */
+    private AuthorityFactory getAuthorityFactory(final AuthorityFactoryIdentifier request)
+            throws NoSuchAuthorityFactoryException
+    {
+        AuthorityFactory factory = factories.get(request);
+        if (factory != null) {
+            return factory;
+        }
+        /*
+         * If there is no factory in the cache for the given type, authority and version, then check if the
+         * default factory (when no version is specified) is actually the factory for the requested version.
+         * The reason why we have to do this check is because we do not ask the version of a factory before
+         * we really need to do so, since fetching this information is relatively costly for some factories
+         * (e.g. EPSGFactory needs to look in the "Version History" table of the dataset) and rarely needed.
+         */
+        if (request.hasVersion()) {
+            factory = factories.get(request.versionOf(null));
+            if (factory != null && request.versionOf(factory.getAuthority()) == request) {
+                // Default factory is for the version that user requested. Cache that finding.
+                return cache(request, factory);
+            }
+        }
+        /*
+         * At this point we know that there is no factory in the cache for the requested type, authority and version.
+         * Create new factories with the Iterables given at construction time. If we already started an iteration in
+         * a previous call to this getAuthorityFactory(…) method, we will continue the search after skipping already
+         * cached instances.
+         */
+        int doneMask = iterationCompleted.get();
+        final int type = request.type;
+        if ((doneMask & (1 << type)) == 0) {
+            if (type >= 0 && type < providers.length) {
+                final Iterable<? extends AuthorityFactory> provider = providers[type];
+                synchronized (provider) {   // Should never be null because of the 'doneMask' check.
+                    /*
+                     * Check again in case another thread has found the factory after the check at
+                     * the beginning of this method but before we entered in the synchronized block.
+                     */
+                    factory = factories.get(request);
+                    if (factory != null) {
+                        return factory;
+                    }
+                    /*
+                     * Search for a factory for the given authority. Caches all factories that we find
+                     * during the iteration process. Some factories may be already cached as a result
+                     * of a partial iteration in a previous call to getAuthorityFactory(…).
+                     */
+                    for (final Iterator<? extends AuthorityFactory> it = provider.iterator(); it.hasNext();) {
+                        factory = it.next();
+                        AuthorityFactory found = null;
+                        AuthorityFactory conflict = null;
+                        for (final String namespace : getCodeSpaces(factory)) {
+                            final AuthorityFactoryIdentifier unversioned = request.unversioned(namespace);
+                            AuthorityFactory cached = cache(unversioned, factory);
+                            if (request.equals(unversioned)) {
+                                found = cached;
+                            }
+                            /*
+                             * Only if we have no choice, ask to the factory what is its version number.
+                             * We have no choice when ignoring the version number causes a conflict, or
+                             * when the user asked for a specific version.
+                             */
+                            if (cached != factory || request.hasVersion()) {
+                                // Make sure that we took in account the version number of the default factory.
+                                cache(unversioned.versionOf(cached.getAuthority()), cached);
+
+                                // Now check the version number of the new factory that we just fetched.
+                                final AuthorityFactoryIdentifier versioned = unversioned.versionOf(factory.getAuthority());
+                                if (versioned != unversioned) {
+                                    cached = cache(versioned, factory);
+                                    if (request.equals(versioned)) {
+                                        found = cached;
+                                    }
+                                }
+                                if (cached != factory) {
+                                    conflict = cached;
+                                }
+                            }
+                        }
+                        if (conflict != null) {
+                            // TODO: log a warning
+                        }
+                        if (found != null) {
+                            return found;
+                        }
+                    }
+                }
+            } else if (type >= AuthorityFactoryIdentifier.GEODETIC) {
+                /*
+                 * Special cases: if the requested factory is ANY, take the first factory that we can found
+                 * regardless of its type. We will try CRS, CS, DATUM and OPERATION factories in that order.
+                 * The GEODETIC type is like ANY except for the additional restriction that the factory shall
+                 * be an instance of the SIS-specific GeodeticAuthorityFactory class.
+                 */
+                assert providers.length < Math.min(type, Byte.MAX_VALUE) : type;
+                for (byte i=0; i < providers.length; i++) {
+                    factory = getAuthorityFactory(request.newType(i));
+                    switch (type) {
+                        case AuthorityFactoryIdentifier.ANY: {
+                            return factory;
+                        }
+                        case AuthorityFactoryIdentifier.GEODETIC: {
+                            if (factory instanceof GeodeticAuthorityFactory) {
+                                return factory;
+                            }
+                        }
+                    }
+                }
+            }
+            /*
+             * Remember that we have iterated over all elements of this provider, so we will not try again.
+             * Note that the mask values may also be modified in other threads for other providers, so we
+             * need to atomically verify that the current value has not been modified before to set it.
+             */
+            while (!iterationCompleted.compareAndSet(doneMask, doneMask | (1 << type))) {
+                doneMask = iterationCompleted.get();
+            }
+        }
+        final String authority = request.getAuthority();
+        throw new NoSuchAuthorityFactoryException(Errors.format(Errors.Keys.UnknownAuthority_1, authority), authority);
+    }
+
+    /**
+     * Returns an object from a code using the given proxy.
+     *
+     * @param  <T>   The type of the object to be returned.
+     * @param  proxy The proxy to use for creating the object.
+     * @param  code  The code of the object to create.
+     * @return The object from one of the authority factory specified at construction time.
+     * @throws FactoryException If an error occurred while creating the object.
+     */
+    private <T> T create(final AuthorityFactoryProxy<T> proxy, final String code) throws FactoryException {
+        ArgumentChecks.ensureNonNull("code", code);
+        final String authority, version;
+        final DefinitionURI uri = DefinitionURI.parse(code);
+        if (uri != null) {
+            authority = uri.authority;
+            version = uri.version;
+        } else {
+            /*
+             * Usages of CharSequences.skipLeadingWhitespaces(…) and skipTrailingWhitespaces(…)
+             * below will work even if code.indexOf(…) returned -1.
+             */
+            int afterAuthority = code.indexOf(DefaultNameSpace.DEFAULT_SEPARATOR);
+            int end = CharSequences.skipTrailingWhitespaces(code, 0, afterAuthority);
+            int start = CharSequences.skipLeadingWhitespaces(code, 0, end);
+            if (start >= end) {
+                throw new NoSuchAuthorityFactoryException(Errors.format(Errors.Keys.MissingAuthority_1, code), null);
+            }
+            authority = code.substring(start, end);
+            int afterVersion = code.indexOf(DefaultNameSpace.DEFAULT_SEPARATOR, ++afterAuthority);
+            start = CharSequences.skipLeadingWhitespaces(code, afterAuthority, afterVersion);
+            end = CharSequences.skipTrailingWhitespaces(code, start, afterVersion);
+            if (start < end) {
+                version = code.substring(start, end);
+                afterVersion++;
+            } else {
+                version = null;
+                afterVersion = afterAuthority;
+            }
+        }
+        return proxy.createFromAPI(getAuthorityFactory(
+                AuthorityFactoryIdentifier.create(proxy.factoryType, authority, version)), code);
+    }
+
+    /**
+     * Clears the cache and notifies all factories need to be fetched again from the providers given at
+     * construction time. All providers that are instances of {@link ServiceLoader} will have their
+     * {@link ServiceLoader#reload() reload()} method invoked.
+     *
+     * <p>This method is intended for use in situations in which new factories can be installed into a running
+     * Java virtual machine. This method invocation will happen automatically if Apache SIS is running in a
+     * servlet or OSGi container.</p>
+     */
+    public void reload() {
+        for (int type=0; type < providers.length; type++) {
+            final Iterable<?> provider = providers[type];
+            if (provider != null) {
+                synchronized (provider) {
+                    if (provider instanceof ServiceLoader<?>) {
+                        ((ServiceLoader<?>) provider).reload();
+                    }
+                    /*
+                     * Clear the cache on a provider-by-provider basis, not by a call to factories.clear().
+                     * This is needed because this MultiAuthoritiesFactory instance may be used concurrently
+                     * by other threads, and we have no global lock for the whole factory.
+                     */
+                    final Iterator<AuthorityFactoryIdentifier> it = factories.keySet().iterator();
+                    while (it.hasNext()) {
+                        if (it.next().type == type) {
+                            it.remove();
+                        }
+                    }
+                    int doneMask;
+                    do doneMask = iterationCompleted.get();
+                    while (iterationCompleted.compareAndSet(doneMask, doneMask & ~(1 << type)));
+                }
+            }
+        }
+    }
+}

Propchange: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/MultiAuthoritiesFactory.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/MultiAuthoritiesFactory.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain;charset=UTF-8

Added: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/NoSuchAuthorityFactoryException.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/NoSuchAuthorityFactoryException.java?rev=1725653&view=auto
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/NoSuchAuthorityFactoryException.java (added)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/NoSuchAuthorityFactoryException.java [UTF-8] Tue Jan 19 23:50:29 2016
@@ -0,0 +1,47 @@
+/*
+ * 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.referencing.factory;
+
+import org.opengis.referencing.NoSuchAuthorityCodeException;
+
+
+/**
+ * Thrown when no factory has been found for a given authority name.
+ * This exception is a little bit more specific than {@link NoSuchAuthorityCodeException}
+ * since it means that in a code like {@code "FOO:456"}, the unrecognized part was {@code "FOO"}.
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @since   0.7
+ * @version 0.7
+ * @module
+ */
+public class NoSuchAuthorityFactoryException extends NoSuchAuthorityCodeException {
+    /**
+     * Serial number for inter-operability with different versions.
+     */
+    private static final long serialVersionUID = -871607314555498523L;
+
+    /**
+     * Constructs an exception with the specified detail message and authority name.
+     *
+     * @param  message   The detail message, saved for later retrieval by the {@link #getMessage()} method.
+     * @param  authority The authority, saved for retrieval by the {@link #getAuthority()} method.
+     */
+    public NoSuchAuthorityFactoryException(final String message, final String authority) {
+        super(message, authority, null, authority);
+    }
+}

Propchange: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/NoSuchAuthorityFactoryException.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/NoSuchAuthorityFactoryException.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain;charset=UTF-8

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGDataAccess.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGDataAccess.java?rev=1725653&r1=1725652&r2=1725653&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGDataAccess.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGDataAccess.java [UTF-8] Tue Jan 19 23:50:29 2016
@@ -518,6 +518,17 @@ addURIs:    for (int i=0; ; i++) {
     }
 
     /**
+     * Returns an empty set since this data access class expects no namespace.
+     * Code shall be given to {@code createFoo(String)} methods directly, without {@code "EPSG:"} prefix.
+     *
+     * @return Empty set.
+     */
+    @Override
+    public Set<String> getCodeSpaces() {
+        return Collections.emptySet();
+    }
+
+    /**
      * Gets a description of the object corresponding to a code.
      * This method returns the object name in a lightweight manner, without creating the full {@link IdentifiedObject}.
      *

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGFactory.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGFactory.java?rev=1725653&r1=1725652&r2=1725653&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGFactory.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGFactory.java [UTF-8] Tue Jan 19 23:50:29 2016
@@ -16,7 +16,9 @@
  */
 package org.apache.sis.referencing.factory.sql;
 
+import java.util.Collections;
 import java.util.Locale;
+import java.util.Set;
 import java.sql.Connection;
 import java.sql.SQLException;
 import javax.sql.DataSource;
@@ -33,6 +35,7 @@ import org.opengis.referencing.operation
 import org.opengis.referencing.operation.MathTransformFactory;
 import org.apache.sis.internal.metadata.sql.Initializer;
 import org.apache.sis.internal.system.DefaultFactories;
+import org.apache.sis.internal.util.Constants;
 import org.apache.sis.referencing.factory.ConcurrentAuthorityFactory;
 import org.apache.sis.referencing.factory.UnavailableFactoryException;
 import org.apache.sis.util.ArgumentChecks;
@@ -59,6 +62,13 @@ public class EPSGFactory extends Concurr
         CSAuthorityFactory, DatumAuthorityFactory, CoordinateOperationAuthorityFactory, Localized
 {
     /**
+     * The namespace of EPSG codes.
+     *
+     * @see #getCodeSpaces()
+     */
+    private static final Set<String> CODESPACES = Collections.singleton(Constants.EPSG);
+
+    /**
      * The factory to use for creating {@link Connection}s to the EPSG database.
      */
     protected final DataSource dataSource;
@@ -181,6 +191,16 @@ public class EPSGFactory extends Concurr
     }
 
     /**
+     * Returns the namespace of EPSG codes.
+     *
+     * @return The {@code "EPSG"} string in a singleton map.
+     */
+    @Override
+    public Set<String> getCodeSpaces() {
+        return CODESPACES;
+    }
+
+    /**
      * Returns the locale used by this factory for producing error messages.
      * This locale does not change the way data are read from the EPSG database.
      *

Modified: sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/AuthorityFactoryProxyTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/AuthorityFactoryProxyTest.java?rev=1725653&r1=1725652&r2=1725653&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/AuthorityFactoryProxyTest.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/AuthorityFactoryProxyTest.java [UTF-8] Tue Jan 19 23:50:29 2016
@@ -21,10 +21,16 @@ import org.opengis.referencing.Identifie
 import org.opengis.referencing.AuthorityFactory;
 import org.opengis.referencing.datum.GeodeticDatum;
 import org.opengis.referencing.crs.*;
+import org.opengis.referencing.cs.CoordinateSystem;
+import org.opengis.referencing.cs.CoordinateSystemAxis;
+import org.opengis.referencing.datum.PrimeMeridian;
+import org.opengis.referencing.datum.Ellipsoid;
+import org.opengis.referencing.datum.Datum;
 import org.apache.sis.referencing.datum.DefaultGeodeticDatum;
 import org.apache.sis.referencing.crs.DefaultGeographicCRS;
 import org.apache.sis.referencing.crs.DefaultProjectedCRS;
 import org.apache.sis.referencing.crs.DefaultDerivedCRS;
+import org.apache.sis.referencing.crs.AbstractCRS;
 
 import org.apache.sis.test.DependsOn;
 import org.apache.sis.test.TestCase;
@@ -61,13 +67,32 @@ public final strictfp class AuthorityFac
      * Tests {@link AuthorityFactoryProxy#getInstance(Class)}.
      */
     @Test
-    public void testType() {
-        assertEquals(ProjectedCRS.class,  AuthorityFactoryProxy.getInstance(ProjectedCRS.class)        .type);
-        assertEquals(ProjectedCRS.class,  AuthorityFactoryProxy.getInstance(DefaultProjectedCRS.class) .type);
-        assertEquals(GeographicCRS.class, AuthorityFactoryProxy.getInstance(GeographicCRS.class)       .type);
-        assertEquals(GeographicCRS.class, AuthorityFactoryProxy.getInstance(DefaultGeographicCRS.class).type);
-        assertEquals(DerivedCRS.class,    AuthorityFactoryProxy.getInstance(DefaultDerivedCRS.class)   .type);
-        assertEquals(GeodeticDatum.class, AuthorityFactoryProxy.getInstance(DefaultGeodeticDatum.class).type);
+    public void testGetInstanceFromType() {
+        assertEquals(ProjectedCRS.class,              AuthorityFactoryProxy.getInstance(ProjectedCRS.class)        .type);
+        assertEquals(ProjectedCRS.class,              AuthorityFactoryProxy.getInstance(DefaultProjectedCRS.class) .type);
+        assertEquals(GeographicCRS.class,             AuthorityFactoryProxy.getInstance(GeographicCRS.class)       .type);
+        assertEquals(GeographicCRS.class,             AuthorityFactoryProxy.getInstance(DefaultGeographicCRS.class).type);
+        assertEquals(DerivedCRS.class,                AuthorityFactoryProxy.getInstance(DefaultDerivedCRS.class)   .type);
+        assertEquals(GeodeticDatum.class,             AuthorityFactoryProxy.getInstance(DefaultGeodeticDatum.class).type);
+        assertEquals(CoordinateReferenceSystem.class, AuthorityFactoryProxy.getInstance(AbstractCRS.class)         .type);
+        assertEquals(CoordinateSystem.class,          AuthorityFactoryProxy.getInstance(CoordinateSystem.class)    .type);
+        assertEquals(CoordinateSystemAxis.class,      AuthorityFactoryProxy.getInstance(CoordinateSystemAxis.class).type);
+        assertEquals(PrimeMeridian.class,             AuthorityFactoryProxy.getInstance(PrimeMeridian.class)       .type);
+        assertEquals(Ellipsoid.class,                 AuthorityFactoryProxy.getInstance(Ellipsoid.class)           .type);
+        assertEquals(Datum.class,                     AuthorityFactoryProxy.getInstance(Datum.class)               .type);
+    }
+
+    /**
+     * Tests {@link AuthorityFactoryProxy#getInstance(String)}.
+     */
+    @Test
+    public void testGetInstanceFromName() {
+        assertEquals(CoordinateReferenceSystem.class, AuthorityFactoryProxy.getInstance("CRS")      .type);
+        assertEquals(CoordinateSystem.class,          AuthorityFactoryProxy.getInstance("CS")       .type);
+        assertEquals(CoordinateSystemAxis.class,      AuthorityFactoryProxy.getInstance("aXis")     .type);
+        assertEquals(PrimeMeridian.class,             AuthorityFactoryProxy.getInstance("Meridian") .type);
+        assertEquals(Ellipsoid.class,                 AuthorityFactoryProxy.getInstance("ellipsoid").type);
+        assertEquals(Datum.class,                     AuthorityFactoryProxy.getInstance("datum")    .type);
     }
 
     /**



Mime
View raw message