sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1796383 - in /sis/branches/JDK8/core: sis-metadata/src/main/java/org/apache/sis/metadata/ sis-metadata/src/main/java/org/apache/sis/metadata/sql/ sis-utility/src/main/java/org/apache/sis/util/iso/
Date Sat, 27 May 2017 11:46:44 GMT
Author: desruisseaux
Date: Sat May 27 11:46:44 2017
New Revision: 1796383

URL: http://svn.apache.org/viewvc?rev=1796383&view=rev
Log:
When a GeoAPI interface is not defined for an ISO type, fallback on the Apache SIS implementation
class.
It does not make a difference for Apache SIS branches using GeoAPI 4.0-SNAPSHOT, but it makes
a difference
for Apache SIS trunk using GeoAPI 3.0 releases.

Modified:
    sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/metadata/MetadataStandard.java
    sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/metadata/sql/Dispatcher.java
    sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/metadata/sql/MetadataSource.java
    sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/metadata/sql/MetadataWriter.java
    sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/iso/Types.java

Modified: sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/metadata/MetadataStandard.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/metadata/MetadataStandard.java?rev=1796383&r1=1796382&r2=1796383&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/metadata/MetadataStandard.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/metadata/MetadataStandard.java
[UTF-8] Sat May 27 11:46:44 2017
@@ -592,6 +592,7 @@ public class MetadataStandard implements
      * Returns the implementation class for the given interface, or {@code null} if none.
      * If non-null, the returned class must have a public no-argument constructor and the
      * metadata instance created by that constructor must be initially empty (no default
value).
+     * That no-argument constructor should never throw any checked exception.
      *
      * <p>The default implementation returns {@code null} in every cases. Subclasses
shall
      * override this method in order to map GeoAPI interfaces to their implementation.</p>

Modified: sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/metadata/sql/Dispatcher.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/metadata/sql/Dispatcher.java?rev=1796383&r1=1796382&r2=1796383&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/metadata/sql/Dispatcher.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/metadata/sql/Dispatcher.java
[UTF-8] Sat May 27 11:46:44 2017
@@ -157,14 +157,7 @@ final class Dispatcher implements Invoca
                 try {
                     value = fetchValue(source.getLookupInfo(method.getDeclaringClass()),
method);
                 } catch (ReflectiveOperationException | SQLException | MetadataStoreException
e) {
-                    Class<?> returnType = method.getReturnType();
-                    if (Collection.class.isAssignableFrom(returnType)) {
-                        final Class<?> elementType = Classes.boundOfParameterizedProperty(method);
-                        if (elementType != null) {
-                            returnType = elementType;
-                        }
-                    }
-                    throw new BackingStoreException(Errors.format(Errors.Keys.DatabaseError_2,
returnType, identifier), e);
+                    throw new BackingStoreException(error(method), e);
                 }
                 /*
                  * At this point we got the metadata property value, which may be null.
@@ -291,6 +284,20 @@ final class Dispatcher implements Invoca
     }
 
     /**
+     * Returns the error message for a failure to query the database for the property identified
by the given method.
+     */
+    final String error(final Method method) {
+        Class<?> returnType = method.getReturnType();
+        if (Collection.class.isAssignableFrom(returnType)) {
+            final Class<?> elementType = Classes.boundOfParameterizedProperty(method);
+            if (elementType != null) {
+                returnType = elementType;
+            }
+        }
+        return Errors.format(Errors.Keys.DatabaseError_2, returnType, identifier);
+    }
+
+    /**
      * Returns a string representation of a metadata of the given type.
      */
     private String toString(final Class<?> type) {

Modified: sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/metadata/sql/MetadataSource.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/metadata/sql/MetadataSource.java?rev=1796383&r1=1796382&r2=1796383&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/metadata/sql/MetadataSource.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/metadata/sql/MetadataSource.java
[UTF-8] Sat May 27 11:46:44 2017
@@ -768,6 +768,25 @@ public class MetadataSource implements A
     }
 
     /**
+     * If the given identifier specifies a subtype of the given type, then returns that subtype.
+     * For example if the given type is {@code Party.class} and the given identifier is
+     * {@code "{CI_Organisation}EPSG"}, then this method returns {@code Organisation.class}.
+     * Otherwise this method returns {@code type} unchanged.
+     */
+    private static Class<?> subType(Class<?> type, final String identifier) {
+        if (identifier.charAt(0) == TYPE_OPEN) {
+            final int i = identifier.indexOf(TYPE_CLOSE);
+            if (i >= 0) {
+                final Class<?> subType = Types.forStandardName(identifier.substring(1,
i));
+                if (subType != null && type.isAssignableFrom(subType)) {
+                    type = subType;
+                }
+            }
+        }
+        return type;
+    }
+
+    /**
      * Returns an implementation of the specified metadata interface filled with the data
referenced
      * by the specified identifier. Alternatively, this method can also return a {@link CodeList}
element.
      *
@@ -781,24 +800,54 @@ public class MetadataSource implements A
      */
     public <T> T lookup(final Class<T> type, final String identifier) throws
MetadataStoreException {
         ArgumentChecks.ensureNonNull("type", type);
-        ArgumentChecks.ensureNonNull("identifier", identifier);
-        /*
-         * IMPLEMENTATION NOTE: This method must not invoke any method which may access 'statements'.
-         * It is not allowed to acquire the lock on 'statements' neither.
-         */
+        ArgumentChecks.ensureNonEmpty("identifier", identifier);
         Object value;
         if (CodeList.class.isAssignableFrom(type)) {
             value = getCodeList(type, identifier);
         } else {
             final CacheKey key = new CacheKey(type, identifier);
+            /*
+             * IMPLEMENTATION NOTE: be careful to not invoke any method that may synchronize
on 'this'
+             * inside the block synchronized on 'pool'.
+             */
             synchronized (pool) {
                 value = pool.get(key);
-                if (value == null) {
+                if (value == null && type.isInterface()) {
                     value = Proxy.newProxyInstance(classloader,
                             new Class<?>[] {type, MetadataProxy.class}, new Dispatcher(identifier,
this));
                     pool.put(key, value);
                 }
             }
+            /*
+             * At this point, a null value means that the given type is a class rather than
an interface.
+             * This may happen when a new type defined by a standard has not yet been defined
in GeoAPI.
+             * In such case, we only have the implementation class in Apache SIS, not yet
the interface.
+             * Since we can not create a Proxy, we have to fetch all property values now.
This is not
+             * very efficient and may waste a little bit of memory, but it should not happen
too often.
+             */
+            if (value == null) {
+                Method method = null;
+                final Class<?> subType = subType(type, identifier);
+                final Dispatcher toSearch = new Dispatcher(identifier, this);
+                try {
+                    value = subType.newInstance();
+                    final LookupInfo info            = getLookupInfo(subType);
+                    final Map<String,Object> map     = asValueMap(value);
+                    final Map<String,String> methods = standard.asNameMap(subType,
NAME_POLICY, KeyNamePolicy.METHOD_NAME);
+                    for (final Map.Entry<String,Object> entry : map.entrySet()) {
+                        method = subType.getMethod(methods.get(entry.getKey()));
+                        info.setMetadataType(subType);
+                        final Object p = readColumn(info, method, toSearch);
+                        if (p != null) {
+                            entry.setValue(p);
+                        }
+                    }
+                } catch (ReflectiveOperationException e) {
+                    throw new MetadataStoreException(Errors.format(Errors.Keys.UnsupportedImplementation_1,
subType), e);
+                } catch (SQLException e) {
+                    throw new MetadataStoreException(toSearch.error(method), e);
+                }
+            }
         }
         return type.cast(value);
     }
@@ -834,16 +883,7 @@ public class MetadataSource implements A
          * If the identifier is prefixed with a table name as in "{CI_Organisation}identifier",
          * the name between bracket is a subtype of the given 'type' argument.
          */
-        Class<?> type = info.getMetadataType();
-        if (toSearch.identifier.charAt(0) == TYPE_OPEN) {
-            final int i = toSearch.identifier.indexOf(TYPE_CLOSE);
-            if (i >= 0) {
-                final Class<?> subType = Types.forStandardName(toSearch.identifier.substring(1,
i));
-                if (subType != null && type.isAssignableFrom(subType)) {
-                    type = subType;
-                }
-            }
-        }
+        final Class<?> type           = subType(info.getMetadataType(), toSearch.identifier);
         final Class<?> returnType     = method.getReturnType();
         final boolean  wantCollection = Collection.class.isAssignableFrom(returnType);
         final Class<?> elementType    = wantCollection ? Classes.boundOfParameterizedProperty(method)
: returnType;
@@ -931,8 +971,8 @@ public class MetadataSource implements A
     }
 
     /**
-     * Returns the code of the given type and name. This method is defined for avoiding the
warning message
-     * when the actual class is unknown (it must have been checked dynamically by the caller
however).
+     * Returns the code of the given type and name. This method is defined for avoiding the
compiler warning
+     * message when the actual class is unknown (it must have been checked dynamically by
the caller however).
      */
     @SuppressWarnings({"unchecked","rawtypes"})
     private static CodeList<?> getCodeList(final Class<?> type, final String
name) {

Modified: sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/metadata/sql/MetadataWriter.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/metadata/sql/MetadataWriter.java?rev=1796383&r1=1796382&r2=1796383&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/metadata/sql/MetadataWriter.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/metadata/sql/MetadataWriter.java
[UTF-8] Sat May 27 11:46:44 2017
@@ -525,6 +525,16 @@ public class MetadataWriter extends Meta
     }
 
     /**
+     * Returns the parent of the given type. Normally, {@code type} is an interface, in which
case the parent types are
+     * other interfaces that the given type extends. But in some cases (e.g. when Apache
SIS implements a new ISO 19115
+     * type not yet defined in GeoAPI), the given type is a class. In such cases we ignore
its interface (it usually do
+     * not implement any) and look for its parent class.
+     */
+    private static Class<?>[] getParentTypes(final Class<?> type) {
+        return type.isInterface() ? type.getInterfaces() : new Class<?>[] {type.getSuperclass()};
+    }
+
+    /**
      * Returns {@code true} if the given metadata type is a subtype of another metadata.
      * If true, then we will need to prefix the identifier by the metadata subtype.
      *
@@ -532,7 +542,7 @@ public class MetadataWriter extends Meta
      *         the result is nevertheless given as a {@code Boolean} wrapper for consistency
with {@code createTable(…)}.
      */
     private Boolean isChildTable(final Class<?> type) {
-        for (final Class<?> candidate : type.getInterfaces()) {
+        for (final Class<?> candidate : getParentTypes(type)) {
             if (standard.isMetadata(candidate)) {
                 return Boolean.TRUE;
             }
@@ -559,7 +569,7 @@ public class MetadataWriter extends Meta
         if (columns.isEmpty()) {
             isChildTable = Boolean.FALSE;
             StringBuilder inherits = null;
-            for (final Class<?> candidate : type.getInterfaces()) {
+            for (final Class<?> candidate : getParentTypes(type)) {
                 if (standard.isMetadata(candidate)) {
                     isChildTable = Boolean.TRUE;
                     final SQLBuilder helper = helper();

Modified: sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/iso/Types.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/iso/Types.java?rev=1796383&r1=1796382&r2=1796383&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/iso/Types.java [UTF-8]
(original)
+++ sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/iso/Types.java [UTF-8]
Sat May 27 11:46:44 2017
@@ -504,9 +504,9 @@ public final class Types extends Static
     }
 
     /**
-     * Returns the GeoAPI interface for the given ISO name, or {@code null} if none.
-     * The identifier argument shall be the value documented in the {@link UML#identifier()}
-     * annotation associated with the GeoAPI interface.
+     * Returns the Java type (usually a GeoAPI interface) for the given ISO name, or {@code
null} if none.
+     * The identifier argument shall be the value documented in the {@link UML#identifier()}
annotation on
+     * the Java type.
      *
      * <div class="note"><b>Examples:</b>
      * <ul>
@@ -515,8 +515,16 @@ public final class Types extends Static
      * </ul>
      * </div>
      *
-     * Only identifiers for the stable part of GeoAPI are recognized. This method does not
handle
-     * the identifiers for the {@code geoapi-pending} module.
+     * Only identifiers for the stable part of GeoAPI or for some Apache SIS classes are
recognized.
+     * This method does not handle the identifiers for interfaces in the {@code geoapi-pending}
module.
+     *
+     * <div class="note"><b>Future evolution:</b>
+     * when a new ISO type does not yet have a corresponding GeoAPI interface,
+     * this method may temporarily return an Apache SIS class instead until a future version
can use the interface.
+     * For example {@code forStandardName("CI_Individual")} returns
+     * <code>{@linkplain org.apache.sis.metadata.iso.citation.DefaultIndividual}.class</code>
in Apache SIS versions
+     * that depend on GeoAPI 3.0, but the return type may be changed to {@code Individual.class}
when Apache SIS will
+     * be upgraded to GeoAPI 3.1.</div>
      *
      * @param  identifier  the ISO {@linkplain UML} identifier, or {@code null}.
      * @return the GeoAPI interface, or {@code null} if the given identifier is {@code null}
or unknown.



Mime
View raw message