All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.rgi.geopackage.metadata.MetadataVerifier Maven / Gradle / Ivy

The newest version!
/* The MIT License (MIT)
 *
 * Copyright (c) 2015 Reinventing Geospatial, Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

package com.rgi.geopackage.metadata;

import com.rgi.common.util.jdbc.JdbcUtility;
import com.rgi.common.util.jdbc.ResultSetStream;
import com.rgi.geopackage.core.GeoPackageCore;
import com.rgi.geopackage.utility.DatabaseUtility;
import com.rgi.geopackage.verification.AssertionError;
import com.rgi.geopackage.verification.ColumnDefinition;
import com.rgi.geopackage.verification.ForeignKeyDefinition;
import com.rgi.geopackage.verification.Requirement;
import com.rgi.geopackage.verification.Severity;
import com.rgi.geopackage.verification.VerificationLevel;
import com.rgi.geopackage.verification.Verifier;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static com.rgi.geopackage.verification.Assert.assertTrue;

/**
 * @author Luke Lambert
 * @author Jenifer Cochran
 */
public class MetadataVerifier extends Verifier
{
    /**
     * @param sqliteConnection
     *            the handle to the database connection
     * @param verificationLevel
     *             Controls the level of verification testing performed
     * @throws SQLException
     *             throws when the method
     *             {@link DatabaseUtility#tableOrViewExists(Connection, String)}
     *             or when other SQLExceptions occur
     */
    public MetadataVerifier(final Connection sqliteConnection, final VerificationLevel verificationLevel) throws SQLException
    {
        super(sqliteConnection, verificationLevel);

        this.hasMetadataTable          = DatabaseUtility.tableOrViewExists(this.getSqliteConnection(), GeoPackageMetadata.MetadataTableName);
        this.hasMetadataReferenceTable = DatabaseUtility.tableOrViewExists(this.getSqliteConnection(), GeoPackageMetadata.MetadataReferenceTableName);

        this.metadataValues = this.hasMetadataTable ? JdbcUtility.select(this.getSqliteConnection(),
                                                                         String.format("SELECT md_scope, id FROM %s;", GeoPackageMetadata.MetadataTableName),
                                                                         null,
                                                                         resultSet -> new MetadataVerifier.MetadataEntry(resultSet.getInt("id"),
                                                                                                                         resultSet.getString("md_scope")))
                                                    : Collections.emptyList();

        final String metadataReferencesQuery = String.format("SELECT reference_scope, table_name, column_name, row_id_value, timestamp, md_file_id, md_parent_id FROM %s;", GeoPackageMetadata.MetadataReferenceTableName);

        this.metadataReferenceValues = this.hasMetadataReferenceTable ? JdbcUtility.select(this.getSqliteConnection(),
                                                                                           metadataReferencesQuery,
                                                                                           null,
                                                                                           resultSet -> new MetadataVerifier.MetadataReference(resultSet.getString("reference_scope"),
                                                                                                                                               resultSet.getString("table_name"),
                                                                                                                                               resultSet.getString("column_name"),
                                                                                                                                               resultSet.getString("timestamp"),
                                                                                                                                               resultSet.getInt   ("md_file_id"),      // Cannot be null
                                                                                                                                               nullSafeGet(resultSet, "row_id_value"), // getInt() returns 0 if the value in the database was null
                                                                                                                                               nullSafeGet(resultSet, "md_parent_id")))
                                                                      : Collections.emptyList();
    }

    /**
     * Requirement 93
     *
     * 
* A GeoPackage MAY contain a table named gpkg_metadata. If present it * SHALL be defined per clause 2.4.2.1.1 Table * Definition, Metadata Table * Definition and gpkg_metadata Table * Definition SQL. *
* * @throws SQLException * if the method verifyTable throws * @throws AssertionError * when the GeoPackage fails to meet this requirement */ @Requirement(reference = "Requirement 93", text = "A GeoPackage MAY contain a table named gpkg_metadata. If present it SHALL be defined per clause 2.4.2.1.1 Table Definition, Metadata Table Definition and gpkg_metadata Table Definition SQL.") public void Requirement93() throws AssertionError, SQLException { if(this.hasMetadataTable) { final Map metadataTableColumns = new HashMap<>(); metadataTableColumns.put("id", new ColumnDefinition("INTEGER", true, true, false, null)); metadataTableColumns.put("md_scope", new ColumnDefinition("TEXT", true, false, false, "'dataset'")); metadataTableColumns.put("md_standard_uri", new ColumnDefinition("TEXT", true, false, false, null)); metadataTableColumns.put("mime_type", new ColumnDefinition("TEXT", true, false, false, "'text/xml'")); metadataTableColumns.put("metadata", new ColumnDefinition("TEXT", true, false, false, "''")); this.verifyTable(GeoPackageMetadata.MetadataTableName, metadataTableColumns, Collections.emptySet(), Collections.emptyList()); } } /** * Requirement 94 * *
* Each {@code md_scope} column value in a {@code gpkg_metadata} table or * updateable view SHALL be one of the name column values from Metadata Scopes. *
* * @throws AssertionError throws when the GeoPackage fails to meet this requirement */ @Requirement(reference = "Requirement 94", text = "Each md_scope column value in a gpkg_metadata table or updateable view SHALL be one of the name column values from Metadata Scopes.") public void Requirement94() throws AssertionError { if(this.hasMetadataTable) { final List invalidScopeValues = this.metadataValues.stream() .filter(metadata -> !MetadataVerifier.isValidMdScope(metadata.mdScope)) .map(metadata -> metadata.mdScope) .collect(Collectors.toList()); assertTrue(String.format("The following md_scope(s) are invalid values in the %s table: %s", GeoPackageMetadata.MetadataTableName, String.join(", ", invalidScopeValues)), invalidScopeValues.isEmpty(), Severity.Warning); } } /** * Requirement 95 * *
* A GeoPackage that contains a {@code gpkg_metadata} table SHALL contain a * {@code gpkg_metadata_reference} table per clause 2.4.3.1.1 Table Definition, Metadata * Reference Table Definition (Table Name: gpkg_metadata_reference) and * * gpkg_metadata_reference Table Definition SQL. *
* * @throws SQLException * if there is a database error * @throws AssertionError * when the GeoPackage fails to meet this requirement */ @Requirement(reference = "Requirement 95", text = "A GeoPackage that contains a gpkg_metadata table SHALL contain a gpkg_metadata_reference table per clause 2.4.3.1.1 Table Definition, Metadata Reference Table Definition (Table Name: gpkg_metadata_reference) and gpkg_metadata_reference Table Definition SQL.") public void Requirement95() throws SQLException, AssertionError { if(this.hasMetadataTable) { assertTrue(String.format("This contains a %1$s table but not a %2$s table. Either drop the %1$s table or add a %2$s table", GeoPackageMetadata.MetadataTableName, GeoPackageMetadata.MetadataReferenceTableName), this.hasMetadataReferenceTable, Severity.Error); final Map metadataReferenceTableColumns = new HashMap<>(); metadataReferenceTableColumns.put("reference_scope", new ColumnDefinition("TEXT", true, false, false, null)); metadataReferenceTableColumns.put("table_name", new ColumnDefinition("TEXT", false, false, false, null)); metadataReferenceTableColumns.put("column_name", new ColumnDefinition("TEXT", false, false, false, null)); metadataReferenceTableColumns.put("row_id_value", new ColumnDefinition("INTEGER", false, false, false, null)); metadataReferenceTableColumns.put("timestamp", new ColumnDefinition("DATETIME", true, false, false, "strftime('%Y-%m-%dT%H:%M:%fZ', 'now')")); metadataReferenceTableColumns.put("md_file_id", new ColumnDefinition("INTEGER", true, false, false, null)); metadataReferenceTableColumns.put("md_parent_id", new ColumnDefinition("INTEGER", false, false, false, null)); this.verifyTable(GeoPackageMetadata.MetadataReferenceTableName, metadataReferenceTableColumns, new HashSet<>(Arrays.asList(new ForeignKeyDefinition(GeoPackageMetadata.MetadataTableName, "md_parent_id", "id"), new ForeignKeyDefinition(GeoPackageMetadata.MetadataTableName, "md_file_id", "id"))), Collections.emptyList()); } } /** * Requirement 96 * *
* Every {@code gpkg_metadata_reference} table reference scope column value * SHALL be one of 'geopackage', 'table', 'column', 'row', 'row/col' in * lowercase. *
* * @throws AssertionError * when the GeoPackage fails to meet this requirement */ @Requirement(reference = "Requirement 96", text = "Every gpkg_metadata_reference table reference scope column value SHALL be one of 'geopackage', 'table', 'column', 'row', 'row/col' in lowercase.") public void Requirement96() throws AssertionError { if(this.hasMetadataReferenceTable) { final Collection invalidScopeValues = this.metadataReferenceValues .stream() .filter(value -> !MetadataVerifier.isValidReferenceScope(value.referenceScope)) .map(value -> value.referenceScope) .collect(Collectors.toList()); assertTrue(String.format("The following reference_scope value(s) are invalid from the %s table: %s", GeoPackageMetadata.MetadataReferenceTableName, String.join(", ", invalidScopeValues)), invalidScopeValues.isEmpty(), Severity.Warning); } } /** * Requirement 97 * *
* Every {@code gpkg_metadata_reference} table row with a {@code * reference_scope} column value of 'geopackage' SHALL have a {@code * table_name} column value that is NULL. Every other {@code * gpkg_metadata_reference} table row SHALL have a {@code table_name} * column value that references a value in the {@code gpkg_contents} * {@code table_name} column. *
* * @throws SQLException * if there is a database error * @throws AssertionError * when the GeoPackage fails to meet this requirement */ @Requirement(reference = "Requirement 97", text = "Every gpkg_metadata_reference table row with a reference_scope column value of 'geopackage' SHALL have a table_name column value that is NULL. Every other gpkg_metadata_reference table row SHALL have a table_name column value that references a value in the gpkg_contents table_name column.") public void Requirement97() throws SQLException, AssertionError { if(this.hasMetadataReferenceTable) { // Check reference_scope column that has 'geopackage' final List invalidGeoPackageValue = this.metadataReferenceValues.stream() .filter(columnValue -> columnValue.referenceScope.equalsIgnoreCase(ReferenceScope.GeoPackage.toString())) .filter(columnValue -> columnValue.columnName != null) .collect(Collectors.toList()); assertTrue(String.format("The following column_name value(s) from %s table are invalid. They have a reference_scope = 'geopackage' and a non-null value in column_name: %s.", GeoPackageMetadata.MetadataReferenceTableName, invalidGeoPackageValue.stream() .map(columnValue -> columnValue.columnName) .collect(Collectors.joining(", "))), invalidGeoPackageValue.isEmpty(), Severity.Warning); // Get table_name values from the gpkg_contents table final String query = String.format("SELECT table_name FROM %s;", GeoPackageCore.ContentsTableName); try(PreparedStatement stmt = this.getSqliteConnection().prepareStatement(query); ResultSet contentsTableNamesRS = stmt.executeQuery()) { final List contentsTableNames = ResultSetStream.getStream(contentsTableNamesRS) .map(resultSet -> { try { return resultSet.getString("table_name"); } catch(final SQLException ignored) { return null; } }) .filter(Objects::nonNull) .collect(Collectors.toList()); //check other records that does not have 'geopackage' as a value final List invalidTableNameValues = this.metadataReferenceValues.stream() .filter(columnValue -> !columnValue.referenceScope.equalsIgnoreCase(ReferenceScope.GeoPackage.toString())) .filter(columnValue -> contentsTableNames.stream().anyMatch(contentsTableName -> !columnValue.tableName.equals(contentsTableName))) .collect(Collectors.toList()); assertTrue(String.format("The following table_name value(s) in %s table are invalid. The table_name value(s) must reference the table_name(s) in %s table.\n%s", GeoPackageMetadata.MetadataReferenceTableName, GeoPackageCore.ContentsTableName, invalidTableNameValues.stream() .map(tableName -> String.format("reference_scope: %s, invalid table_name: %s.", tableName.referenceScope, tableName.tableName)) .collect(Collectors.joining("\n"))), invalidTableNameValues.isEmpty(), Severity.Warning); } } } /** * Requirement 98 * *
* Every {@code gpkg_metadata_reference} table row with a {@code * reference_scope} column value of 'geopackage','table' or 'row' * SHALL have a {@code column_name} column value that is NULL. Every * other {@code gpkg_metadata_reference} table row SHALL have a {@code * column_name} column value that contains the name of a column in * the SQLite table or view identified by the {@code table_name} * column value. *
* * @throws AssertionError throws when the GeoPackage fails to meet this requirement * @throws SQLException throws if various SQLExceptions occur */ @Requirement(reference = "Requirement 98", text = "Every gpkg_metadata_reference table row with a reference_scope column " + "value of 'geopackage','table' or 'row' SHALL have a column_name column" + " value that is NULL. Every other gpkg_metadata_reference table row SHALL" + " have a column_name column value that contains the name of a column in the " + "SQLite table or view identified by the table_name column value. ") public void Requirement98() throws AssertionError, SQLException { if(this.hasMetadataReferenceTable) { final List invalidColumnNameValues = this.metadataReferenceValues.stream() .filter(columnValue -> columnValue.referenceScope.equalsIgnoreCase(ReferenceScope.GeoPackage.toString()) || columnValue.referenceScope.equalsIgnoreCase(ReferenceScope.Table.toString()) || columnValue.referenceScope.equalsIgnoreCase(ReferenceScope.Row.toString())) .filter(columnValue -> columnValue.columnName != null) .collect(Collectors.toList()); assertTrue(String.format("The following column_name values from %s table are invalid. They contain a reference_scope of either 'geopackage', 'table' or 'row' and need to have a column_value of NULL.\n%s", GeoPackageMetadata.MetadataReferenceTableName, invalidColumnNameValues.stream() .map(value -> String.format("reference_scope: %s, invalid column_name: %s.", value.referenceScope, value.columnName)) .collect(Collectors.joining("\n"))), invalidColumnNameValues.isEmpty(), Severity.Warning); final List otherReferenceScopeValues = this.metadataReferenceValues.stream() .filter(columnValue -> !columnValue.referenceScope.equalsIgnoreCase(ReferenceScope.GeoPackage.toString()) && !columnValue.referenceScope.equalsIgnoreCase(ReferenceScope.Table.toString()) && !columnValue.referenceScope.equalsIgnoreCase(ReferenceScope.Row.toString())) .collect(Collectors.toList()); for(final MetadataVerifier.MetadataReference value : otherReferenceScopeValues) { if(DatabaseUtility.tableOrViewExists(this.getSqliteConnection(), value.tableName)) { final String query = "PRAGMA table_info('?');"; try(PreparedStatement statement = this.getSqliteConnection().prepareStatement(query)) { statement.setString(1, value.tableName); try( ResultSet tableInfo = statement.executeQuery(query)) { final boolean columnExists = ResultSetStream.getStream(tableInfo) .anyMatch(resultSet -> { try { return resultSet.getString("name").equals(value.columnName); } catch(final SQLException ignored) { return false; } }); assertTrue(String.format("The column_name %s referenced in the %s table doesn't exist in the table %s.", value.columnName, GeoPackageMetadata.MetadataReferenceTableName, value.tableName), columnExists, Severity.Warning); } } } } } } /** * Requirement 75 * *
* Every {@code gpkg_metadata_reference} table row with a {@code * reference_scope} column value of 'geopackage', 'table' or 'column' * SHALL have a {@code row_id_value} column value that is NULL. Every * other {@code gpkg_metadata_reference} table row SHALL have a {@code * row_id_value} column value that contains the ROWID of a row in the * SQLite table or view identified by the {@code table_name} column * value. *
* * @throws AssertionError throws when the GeoPackage fails to meet this requirement * @throws SQLException throws if various SQLExceptions occur */ @Requirement(reference = "Requirement 75", text = "Every gpkg_metadata_reference table row with a reference_scope column value " + "of 'geopackage', 'table' or 'column' SHALL have a row_id_value column value " + "that is NULL. Every other gpkg_metadata_reference table row SHALL have a row_id_value" + " column value that contains the ROWID of a row in the SQLite table or view identified " + "by the table_name column value.") public void Requirement75() throws AssertionError, SQLException { if(this.hasMetadataReferenceTable) { final List invalidColumnValues = this.metadataReferenceValues.stream() .filter(columnValue -> columnValue.referenceScope.equalsIgnoreCase(ReferenceScope.GeoPackage.toString()) || columnValue.referenceScope.equalsIgnoreCase(ReferenceScope.Table.toString()) || columnValue.referenceScope.equalsIgnoreCase(ReferenceScope.Column.toString())) .filter(columnValue -> columnValue.rowIdValue != null) .collect(Collectors.toList()); assertTrue(String.format("The following row_id_value(s) has(have) a reference_scope value of 'geopackage', " + "'table' or 'column and do not have a value of NULL in row_id_value.\n %s", invalidColumnValues.stream() .map(columnValue -> String.format("reference_scope: %s, invalid row_id_value: %d.", columnValue.referenceScope, columnValue.rowIdValue)) .collect(Collectors.joining("\n"))), invalidColumnValues.isEmpty(), Severity.Warning); final List invalidColumnNameValues = this.metadataReferenceValues.stream() .filter(columnValue -> !columnValue.referenceScope.equalsIgnoreCase(ReferenceScope.GeoPackage.toString()) && !columnValue.referenceScope.equalsIgnoreCase(ReferenceScope.Table.toString()) && !columnValue.referenceScope.equalsIgnoreCase(ReferenceScope.Column.toString())) .collect(Collectors.toList()); for(final MetadataVerifier.MetadataReference value: invalidColumnNameValues) { final String query = String.format("SELECT COUNT(1) FROM %s WHERE ROWID = ?;", // TODO make sure COUNT(1) works the way I think it does... value.tableName); try(PreparedStatement statement = this.getSqliteConnection().prepareStatement(query)) { statement.setString(1, value.tableName); statement.setInt (2, value.rowIdValue); try(ResultSet matchingRowIdRS = statement.executeQuery()) { assertTrue(String.format("The row_id_value %d in the %s table does not reference a row id in the table %s.", value.rowIdValue, GeoPackageMetadata.MetadataReferenceTableName, value.tableName), matchingRowIdRS.next(), Severity.Warning); } } } } } /** * Requirement 76 * *
* Every {@code gpkg_metadata_reference} table row timestamp column * value SHALL be in ISO 8601 format containing a complete date plus UTC * hours, minutes, seconds and a decimal fraction of a second, with a 'Z' * ('zulu') suffix indicating UTC. *
* * @throws AssertionError throws when the GeoPackage fails to meet this requirement */ @Requirement(reference = "Requirement 76", text = "Every gpkg_metadata_reference table row timestamp column value " + "SHALL be in ISO 8601 format containing a complete date plus " + "UTC hours, minutes, seconds and a decimal fraction of a second, with " + "a 'Z' ('zulu') suffix indicating UTC.") public void Requirement76() throws AssertionError { if(this.hasMetadataReferenceTable) { for(final MetadataVerifier.MetadataReference value : this.metadataReferenceValues) { assertTrue(String.format("The timestamp %s in the %s table is not in the correct format.", value.timestamp, GeoPackageMetadata.MetadataReferenceTableName), isValidDate(value.timestamp), Severity.Warning); } } } /** * Requirement 77 * *
* Every {@code gpkg_metadata_reference} table row {@code md_file_id * } column value SHALL be an id column value from the {@code * gpkg_metadata} table. *
* * @throws AssertionError throws when the GeoPackage fails to meet this requirement */ @Requirement(reference = "Requirement 77", text = "Every gpkg_metadata_reference table row md_file_id column " + "value SHALL be an id column value from the gpkg_metadata table. ") public void Requirement77() throws AssertionError { if(this.hasMetadataReferenceTable) { final List invalidIds = this.metadataReferenceValues.stream() .filter(metadataReferenceValue -> !(this.metadataValues.stream() .anyMatch(metadataValue -> metadataReferenceValue.mdFileId == metadataValue.id))) .collect(Collectors.toList()); assertTrue(String.format("The following md_file_id(s) from %s table do not reference an id column value from the %s table.\n%s", GeoPackageMetadata.MetadataReferenceTableName, GeoPackageMetadata.MetadataTableName, invalidIds.stream() .map(invalidId -> String.format("invalid md_file_id: %s, md_parent_id: %d, reference_scope: %s.", invalidId.mdFileId, invalidId.mdParentId, invalidId.referenceScope)) .collect(Collectors.joining("\n"))), invalidIds.isEmpty(), Severity.Warning); } } /** * Requirement 78 * *
* Every {@code gpkg_metadata_reference} table row {@code md_parent_id * } column value that is NOT NULL SHALL be an id column value from * the {@code gpkg_metadata} table that is not equal to the {@code * md_file_id} column value for that row. *
* * @throws AssertionError throws when the GeoPackage fails to meet this requirement */ @Requirement(reference = "Requirement 78", text = "Every gpkg_metadata_reference table row md_parent_id column value " + "that is NOT NULL SHALL be an id column value from the gpkg_metadata " + "table that is not equal to the md_file_id column value for that row. ") public void Requirement78() throws AssertionError { if(this.hasMetadataReferenceTable) { final List invalidParentIdsBcFileIds = this.metadataReferenceValues.stream() .filter(metadataReferenceValue -> metadataReferenceValue.mdFileId == metadataReferenceValue.mdParentId) .collect(Collectors.toList()); assertTrue(String.format("The following md_parent_id(s) are invalid because they cannot be equivalent to their correspoding md_file_id.\n%s", invalidParentIdsBcFileIds.stream() .map(value -> String.format("Invalid md_parent_id: %d, md_file_id: %d.", value.mdParentId, value.mdFileId)) .collect(Collectors.joining("\n"))), invalidParentIdsBcFileIds.isEmpty(), Severity.Warning); final List invalidParentIds = this.metadataReferenceValues.stream() .filter(metadataReferenceValue -> metadataReferenceValue.mdParentId != null) .filter(metadataReferenceValue -> !(this.metadataValues.stream() .anyMatch(metadataValue -> metadataReferenceValue.mdParentId.equals(metadataValue.id)))) .collect(Collectors.toList()); assertTrue(String.format("The following md_parent_id value(s) are invalid because they do not equal id column value from the %s table. \n%s", GeoPackageMetadata.MetadataTableName, invalidParentIds.stream() .map(value -> String.format("Invalid md_parent_id: %d, md_file_id: %d.", value.mdParentId, value.mdFileId)) .collect(Collectors.joining("\n"))), invalidParentIds.isEmpty(), Severity.Warning); } } private static Integer nullSafeGet(final ResultSet resultSet, final String columnLabel) throws SQLException { final Integer value = resultSet.getInt(columnLabel); return resultSet.wasNull() ? null : value; } private static boolean isValidReferenceScope(final String referenceScope) { return Stream.of(ReferenceScope.values()).anyMatch(scope -> scope.toString().equalsIgnoreCase(referenceScope)); } private static boolean isValidMdScope(final String mdScope) { return Stream.of(Scope.values()).anyMatch(scope -> scope.toString().equalsIgnoreCase(mdScope)); } private static boolean isValidDate(final String date) { final SimpleDateFormat dateFormatWithFractionalSeconds = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'.'SS'Z'"); final SimpleDateFormat dateFormatWithoutFractionalSeconds = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); return isValidDate(dateFormatWithFractionalSeconds, date) || isValidDate(dateFormatWithoutFractionalSeconds, date); } private static boolean isValidDate(final SimpleDateFormat dateFormat, final String date) { try { dateFormat.parse(date); return true; } catch(final ParseException ignored) { return false; } } private final boolean hasMetadataTable; private final boolean hasMetadataReferenceTable; private final List metadataValues; private final List metadataReferenceValues; // TODO don't use these inner classes private static final class MetadataEntry { private MetadataEntry(final int id, final String mdScope) { this.id = id; this.mdScope = mdScope; } private final int id; private final String mdScope; } // TODO don't use these inner classes private static final class MetadataReference { private final String referenceScope; private final String tableName; private final String columnName; private final Integer rowIdValue; private final String timestamp; private final int mdFileId; private final Integer mdParentId; private MetadataReference(final String referenceScope, final String tableName, final String columnName, final String timestamp, final int mdFileId, final Integer rowIdValue, final Integer mdParentId) { this.referenceScope = referenceScope; this.tableName = tableName; this.columnName = columnName; this.rowIdValue = rowIdValue; this.timestamp = timestamp; this.mdFileId = mdFileId; this.mdParentId = mdParentId; } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy