sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1794451 - in /sis/branches/JDK8/core/sis-metadata/src: main/java/org/apache/sis/metadata/sql/MetadataSource.java main/java/org/apache/sis/metadata/sql/MetadataWriter.java test/java/org/apache/sis/metadata/sql/MetadataWriterTest.java
Date Mon, 08 May 2017 20:13:33 GMT
Author: desruisseaux
Date: Mon May  8 20:13:33 2017
New Revision: 1794451

URL: http://svn.apache.org/viewvc?rev=1794451&view=rev
Log:
Lookups for responsibly parties (or any other metadata type having subtypes) must search in
the right "child" table.

Modified:
    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-metadata/src/test/java/org/apache/sis/metadata/sql/MetadataWriterTest.java

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=1794451&r1=1794450&r2=1794451&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] Mon May  8 20:13:33 2017
@@ -124,6 +124,16 @@ public class MetadataSource implements A
     static final String ID_COLUMN = "ID";
 
     /**
+     * Delimiter characters for the table name in identifier. Table names are prefixed to
identifiers only if
+     * the type represented by the table is a subtype. For example since {@code CI_Organisation}
is a subtype
+     * of {@code CI_Party}, identifiers for organizations need to be prefixed by {@code {CI_Organisation}}
in
+     * order allow {@code MetadataSource} to know in which table to search for such party.
+     *
+     * @see MetadataWriter#isReservedChar(int)
+     */
+    static final char TYPE_OPEN = '{', TYPE_CLOSE = '}';
+
+    /**
      * The timeout before to close a prepared statement, in nanoseconds. This is set to 2
seconds,
      * which is a bit short but should be okay if the {@link DataSource} creates pooled connections.
      * In case there is no connection pool, then the mechanism defined in this package will
hopefully
@@ -524,7 +534,7 @@ public class MetadataSource implements A
      * Returns the table name for the specified class.
      * This is usually the ISO 19115 name.
      */
-    static String getTableName(Class<?> type) {
+    static String getTableName(final Class<?> type) {
         final UML annotation = type.getAnnotation(UML.class);
         if (annotation == null) {
             return type.getSimpleName();
@@ -772,7 +782,7 @@ public class MetadataSource implements A
      * @return an implementation of the required interface, or the code list element.
      * @throws MetadataStoreException if a SQL query failed.
      */
-    public <T> T lookup(final Class<T> type, String identifier) throws MetadataStoreException
{
+    public <T> T lookup(final Class<T> type, final String identifier) throws
MetadataStoreException {
         ArgumentChecks.ensureNonNull("type", type);
         ArgumentChecks.ensureNonNull("identifier", identifier);
         /*
@@ -806,9 +816,22 @@ public class MetadataSource implements A
      * @throws SQLException if the SQL query failed.
      * @throws MetadataStoreException if a value was not found or can not be converted to
the expected type.
      */
-    final Object getValue(final Class<?> type, final Method method, final Dispatcher
toSearch)
+    final Object getValue(Class<?> type, final Method method, final Dispatcher toSearch)
             throws SQLException, MetadataStoreException
     {
+        /*
+         * 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.
+         */
+        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<?> returnType     = method.getReturnType();
         final boolean  wantCollection = Collection.class.isAssignableFrom(returnType);
         final Class<?> elementType    = wantCollection ? Classes.boundOfParameterizedProperty(method)
: returnType;

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=1794451&r1=1794450&r2=1794451&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] Mon May  8 20:13:33 2017
@@ -218,6 +218,7 @@ public class MetadataWriter extends Meta
      * @param  metadata  the metadata object to add.
      * @param  done      the metadata objects already added, mapped to their primary keys.
      * @param  parent    the primary key of the parent, or {@code null} if there is no parent.
+     *                   This identifier shall not contain {@linkplain #isReservedChar(int)
reserved characters}.
      * @return the identifier (primary key) of the metadata just added.
      * @throws SQLException if an exception occurred while reading or writing the database.
      * @throws ClassCastException if the metadata object does not implement a metadata interface
@@ -267,7 +268,10 @@ public class MetadataWriter extends Meta
          * created first. The later will work only for database supporting table inheritance,
like PostgreSQL.
          * For other kind of database engine, we can not store metadata having parent interfaces.
          */
-        createTable(stmt, interfaceType, table, columns);
+        Boolean isChildTable = createTable(stmt, interfaceType, table, columns);
+        if (isChildTable == null) {
+            isChildTable = isChildTable(interfaceType);
+        }
         /*
          * Add missing columns if there is any. If columns are added, we will keep trace
of foreigner keys in
          * this process but will not create the constraints now because the foreigner tables
may not exist yet.
@@ -319,7 +323,7 @@ public class MetadataWriter extends Meta
          * etc.) is associated only to Responsibility. So it make sense to use the Responsibility
ID for
          * the contact info.
          */
-        identifier = suggestIdentifier(metadata, asValueMap);
+        identifier = nonEmpty(removeReservedChars(suggestIdentifier(metadata, asValueMap),
null));
         if (identifier == null) {
             identifier = parent;
             if (identifier == null) {
@@ -337,6 +341,17 @@ public class MetadataWriter extends Meta
             }
         }
         /*
+         * If the record to add is located in a child table, we need to prepend the child
table name
+         * in the identifier in order to allow MetadataSource to locate the right table to
query.
+         */
+        final int minimalIdentifierLength;
+        if (isChildTable) {
+            identifier = TYPE_OPEN + table + TYPE_CLOSE + identifier;
+            minimalIdentifierLength = table.length() + 2;
+        } else {
+            minimalIdentifierLength = 0;
+        }
+        /*
          * Check for key collision. We will add a suffix if there is one. Note that the final
identifier must be
          * found before we put its value in the map, otherwise cyclic references (if any)
will use the wrong value.
          *
@@ -347,6 +362,7 @@ public class MetadataWriter extends Meta
         try (IdentifierGenerator idCheck = new IdentifierGenerator(this, schema(), table,
ID_COLUMN, helper)) {
             for (int i=0; i<MINIMAL_LIMIT-1; i++) {
                 final int maxLength = maximumIdentifierLength - i;
+                if (maxLength < minimalIdentifierLength) break;
                 if (identifier.length() > maxLength) {
                     identifier = identifier.substring(0, maxLength);
                 }
@@ -505,22 +521,43 @@ public class MetadataWriter extends Meta
     }
 
     /**
+     * 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.
+     *
+     * @return whether the given metadata is a subtype of another metadata. This method never
return {@code null}, but
+     *         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()) {
+            if (standard.isMetadata(candidate)) {
+                return Boolean.TRUE;
+            }
+        }
+        return Boolean.FALSE;
+    }
+
+    /**
      * Creates a table for the given type, if the table does not already exists.
      * This method may call itself recursively for creating parent tables, if they do not
exist neither.
+     * This method opportunistically computes the same return value than {@link #isChildTable(Class)}.
      *
      * @param  stmt     the statement to use for creating tables.
      * @param  type     the interface class.
      * @param  table    the name of the table (should be consistent with the type).
      * @param  columns  the existing columns, as an empty set if the table does not exist
yet.
+     * @return the value that {@code isChildTable(type)} would return, or {@code null} if
undetermined.
      * @throws SQLException if an error occurred while creating the table.
      */
-    private void createTable(final Statement stmt, final Class<?> type, final String
table, final Set<String> columns)
+    private Boolean createTable(final Statement stmt, final Class<?> type, final String
table, final Set<String> columns)
             throws SQLException
     {
+        Boolean isChildTable = null;
         if (columns.isEmpty()) {
+            isChildTable = Boolean.FALSE;
             StringBuilder inherits = null;
             for (final Class<?> candidate : type.getInterfaces()) {
                 if (standard.isMetadata(candidate)) {
+                    isChildTable = Boolean.TRUE;
                     final SQLBuilder helper = helper();
                     if (helper.dialect.isTableInheritanceSupported) {
                         final String parent = getTableName(candidate);
@@ -553,6 +590,7 @@ public class MetadataWriter extends Meta
             stmt.executeUpdate(sql);
             columns.add(ID_COLUMN);
         }
+        return isChildTable;
     }
 
     /**
@@ -649,20 +687,60 @@ public class MetadataWriter extends Meta
 
     /**
      * Returns an abbreviation of the given identifier, if one is found.
+     * The returned identifier is guaranteed to not contain {@linkplain #isReservedChar(int)
reserved characters}.
      */
     private static String abbreviation(final String identifier) {
         final StringBuilder buffer = new StringBuilder();
         final StringTokenizer tokens = new StringTokenizer(identifier);
         while (tokens.hasMoreTokens()) {
-            buffer.appendCodePoint(tokens.nextToken().codePointAt(0));
+            final int c = tokens.nextToken().codePointAt(0);
+            if (!isReservedChar(c)) {
+                buffer.appendCodePoint(c);
+            }
         }
+        /*
+         * If there is not enough characters in the abbreviation, take the given
+         * identifier as-is except for the reserved characters which are removed.
+         */
         if (buffer.length() >= 3) {
             return buffer.toString();
         }
+        buffer.setLength(0);
+        return removeReservedChars(identifier, buffer.append(identifier));
+    }
+
+    /**
+     * Removes the reserved characters in the given identifier.
+     * If the given buffer is non-null, then it shall contain a copy of {@code identifier}.
+     */
+    private static String removeReservedChars(final String identifier, StringBuilder buffer)
{
+        if (identifier != null) {
+            boolean modified = false;
+            for (int i=identifier.length(); --i >= 0;) {
+                final char c = identifier.charAt(i);
+                if (isReservedChar(c)) {
+                    if (buffer == null) {
+                        buffer = new StringBuilder(identifier);
+                    }
+                    buffer.deleteCharAt(i);
+                    modified = true;
+                }
+            }
+            if (modified) {
+                return buffer.toString();
+            }
+        }
         return identifier;
     }
 
     /**
+     * Returns {@code true} if the given code point is a reserved character.
+     */
+    private static boolean isReservedChar(final int c) {
+        return (c == TYPE_OPEN) || (c == TYPE_CLOSE);
+    }
+
+    /**
      * Trims leading and trailing spaces and returns the given value if non-empty, or {@code
null} otherwise.
      */
     private static String nonEmpty(String value) {

Modified: sis/branches/JDK8/core/sis-metadata/src/test/java/org/apache/sis/metadata/sql/MetadataWriterTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-metadata/src/test/java/org/apache/sis/metadata/sql/MetadataWriterTest.java?rev=1794451&r1=1794450&r2=1794451&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-metadata/src/test/java/org/apache/sis/metadata/sql/MetadataWriterTest.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-metadata/src/test/java/org/apache/sis/metadata/sql/MetadataWriterTest.java
[UTF-8] Mon May  8 20:13:33 2017
@@ -67,7 +67,7 @@ public final strictfp class MetadataWrit
         try {
             write();
             search();
-//          read();
+            read();
             source.close();
         } finally {
             TestDatabase.drop(ds);



Mime
View raw message