Index: extensions/dna-connector-jdbc-metadata/.classpath =================================================================== --- extensions/dna-connector-jdbc-metadata/.classpath (revision 1450) +++ extensions/dna-connector-jdbc-metadata/.classpath (working copy) @@ -1,11 +1,10 @@ - - - - - - - - - - - + + + + + + + + + + Index: extensions/dna-connector-jdbc-metadata/pom.xml =================================================================== --- extensions/dna-connector-jdbc-metadata/pom.xml (revision 1450) +++ extensions/dna-connector-jdbc-metadata/pom.xml (working copy) @@ -1,94 +1,100 @@ - - 4.0.0 - - dna - org.jboss.dna - 0.7-SNAPSHOT - ../.. - - - dna-connector-jdbc-metadata - jar - JBoss DNA Connector to JDBC - JBoss DNA Connector that processes JDBC metadata - http://labs.jboss.org/dna - - - org.jboss.dna - dna-common - - - org.jboss.dna - dna-graph - - - org.jboss.dna - dna-common-jdbc - ${project.version} - - - - org.slf4j - slf4j-api - - - org.slf4j - slf4j-log4j12 - test - - - log4j - log4j - test - - - junit - junit - 4.4 - test - - - hsqldb - hsqldb - 1.8.0.7 - test - - - org.dbunit - dbunit - 2.4.1 - test - - - - org.hsqldb.jdbcDriver - sa - - jdbc:hsqldb:file:${basedir}/target/testdb/db - + + 4.0.0 + + dna + org.jboss.dna + 0.7-SNAPSHOT + ../.. + + + dna-connector-jdbc-metadata + jar + JBoss DNA Connector to JDBC + JBoss DNA Connector that processes JDBC metadata + http://labs.jboss.org/dna + + + org.jboss.dna + dna-graph + + + org.hibernate + hibernate-c3p0 + 3.3.0.GA + + + + org.slf4j + slf4j-api + + + org.jboss.dna + dna-common + ${project.version} + test-jar + test + + + org.jboss.dna + dna-graph + + + org.jboss.dna + dna-graph + ${project.version} + test-jar + test + + + org.slf4j + slf4j-log4j12 + test + + + log4j + log4j + test + + + junit + junit + 4.4 + test + + + hsqldb + hsqldb + 1.8.0.7 + test + + + org.mockito + mockito-all + test + + - - - src/main/resources - true - - - - - src/test/resources - true - - - src/test/data - true - ../ - - - src/it/resources - true - - + + + false + src/test/resources + + * + **/* + + + + + true + src/test/resources + + database.properties + + + \ No newline at end of file Index: extensions/dna-connector-jdbc-metadata/src/main/java/org/jboss/dna/connector/meta/jdbc/ColumnMetadata.java =================================================================== --- extensions/dna-connector-jdbc-metadata/src/main/java/org/jboss/dna/connector/meta/jdbc/ColumnMetadata.java (revision 0) +++ extensions/dna-connector-jdbc-metadata/src/main/java/org/jboss/dna/connector/meta/jdbc/ColumnMetadata.java (revision 0) @@ -0,0 +1,207 @@ +/* + * JBoss DNA (http://www.jboss.org/dna) + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. Some portions may be licensed + * to Red Hat, Inc. under one or more contributor license agreements. + * See the AUTHORS.txt file in the distribution for a full listing of + * individual contributors. + * + * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA + * is licensed to you under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * JBoss DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.jboss.dna.connector.meta.jdbc; + +import java.sql.DatabaseMetaData; +import java.sql.Types; +import net.jcip.annotations.Immutable; + +/** + * Container for column-level metadata. The fields in this class roughly parallel the information returned from the + * {@link DatabaseMetaData#getColumns(String, String, String, String)} method. + */ +@Immutable +public class ColumnMetadata { + + private final String name; + private final int jdbcDataType; + private final String typeName; + private final int columnSize; + private final int decimalDigits; + private final int radix; + private final Boolean nullable; + private final String description; + private final String defaultValue; + private final int length; + private final int ordinalPosition; + private final String scopeCatalogName; + private final String scopeSchemaName; + private final String scopeTableName; + private final Integer sourceJdbcDataType; + + public ColumnMetadata( String name, + int jdbcDataType, + String typeName, + int columnSize, + int decimalDigits, + int radix, + Boolean nullable, + String description, + String defaultValue, + int length, + int ordinalPosition, + String scopeCatalogName, + String scopeSchemaName, + String scopeTableName, + Integer sourceJdbcDataType ) { + super(); + this.name = name; + this.jdbcDataType = jdbcDataType; + this.typeName = typeName; + this.columnSize = columnSize; + this.decimalDigits = decimalDigits; + this.radix = radix; + this.nullable = nullable; + this.description = description; + this.defaultValue = defaultValue; + this.length = length; + this.ordinalPosition = ordinalPosition; + this.scopeCatalogName = scopeCatalogName; + this.scopeSchemaName = scopeSchemaName; + this.scopeTableName = scopeTableName; + this.sourceJdbcDataType = sourceJdbcDataType; + } + + /** + * @return the column name (COLUMN_NAME in the {@link DatabaseMetaData#getColumns(String, String, String, String)} result + * set). + */ + public String getName() { + return name; + } + + /** + * @return the JDBC data type (from {@link Types}) (DATA_TYPE in the + * {@link DatabaseMetaData#getColumns(String, String, String, String)} result set). + */ + public int getJdbcDataType() { + return jdbcDataType; + } + + /** + * @return the database-dependent type name (TYPENAME in the + * {@link DatabaseMetaData#getColumns(String, String, String, String)} result set). + */ + public String getTypeName() { + return typeName; + } + + /** + * @return the column size (length for character data types, precision for numeric data types) (COLUMN_SIZE in the + * {@link DatabaseMetaData#getColumns(String, String, String, String)} result set). + */ + public int getColumnSize() { + return columnSize; + } + + /** + * @return the number of fractional digits in the column (DECIMAL_DIGITS in the + * {@link DatabaseMetaData#getColumns(String, String, String, String)} result set). + */ + public int getDecimalDigits() { + return decimalDigits; + } + + /** + * @return the radix for the column (NUM_PREC_RADIX in the {@link DatabaseMetaData#getColumns(String, String, String, String)} + * result set). + */ + public int getRadix() { + return radix; + } + + /** + * @return whether the column allows NULLs or not (NULLABLE in the + * {@link DatabaseMetaData#getColumns(String, String, String, String)} result set); null indicates that it cannot be + * determined if the column allows NULLs. + */ + public Boolean getNullable() { + return nullable; + } + + /** + * @return the column description (REMARKS in the {@link DatabaseMetaData#getColumns(String, String, String, String)} result + * set). + */ + public String getDescription() { + return description; + } + + /** + * @return the default value for the column, if any (COLUMN_DEF in the + * {@link DatabaseMetaData#getColumns(String, String, String, String)} result set). + */ + public String getDefaultValue() { + return defaultValue; + } + + /** + * @return the number of bytes in the column (for char types) (CHAR_OCTECT_LENGTH in the + * {@link DatabaseMetaData#getColumns(String, String, String, String)} result set). + */ + public int getLength() { + return length; + } + + /** + * @return the 1-based index of the column within its table (ORDINAL_POSITION in the + * {@link DatabaseMetaData#getColumns(String, String, String, String)} result set). + */ + public int getOrdinalPosition() { + return ordinalPosition; + } + + /** + * @return for columns of type REF, the catalog name of the target table (SCOPE_CATALOG in the + * {@link DatabaseMetaData#getColumns(String, String, String, String)} result set). + */ + public String getScopeCatalogName() { + return scopeCatalogName; + } + + /** + * @return for columns of type REF, the schema name of the target table (SCOPE_SCHEMA in the + * {@link DatabaseMetaData#getColumns(String, String, String, String)} result set). + */ + public String getScopeSchemaName() { + return scopeSchemaName; + } + + /** + * @return for columns of type REF, the name of the target table (SCOPE_TABLE in the + * {@link DatabaseMetaData#getColumns(String, String, String, String)} result set). + */ + public String getScopeTableName() { + return scopeTableName; + } + + /** + * @return the source type of the referred type (from {@link Types}) for REF columns (SOURCE_DATA_TYPE in the + * {@link DatabaseMetaData#getColumns(String, String, String, String)} result set). + */ + public Integer getSourceJdbcDataType() { + return sourceJdbcDataType; + } + +} Property changes on: extensions\dna-connector-jdbc-metadata\src\main\java\org\jboss\dna\connector\meta\jdbc\ColumnMetadata.java ___________________________________________________________________ Added: svn:keywords + Id Revision Added: svn:eol-style + LF Index: extensions/dna-connector-jdbc-metadata/src/main/java/org/jboss/dna/connector/meta/jdbc/JdbcMetadataCollector.java =================================================================== --- extensions/dna-connector-jdbc-metadata/src/main/java/org/jboss/dna/connector/meta/jdbc/JdbcMetadataCollector.java (revision 0) +++ extensions/dna-connector-jdbc-metadata/src/main/java/org/jboss/dna/connector/meta/jdbc/JdbcMetadataCollector.java (revision 0) @@ -0,0 +1,209 @@ +/* + * JBoss DNA (http://www.jboss.org/dna) + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. Some portions may be licensed + * to Red Hat, Inc. under one or more contributor license agreements. + * See the AUTHORS.txt file in the distribution for a full listing of + * individual contributors. + * + * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA + * is licensed to you under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * JBoss DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.jboss.dna.connector.meta.jdbc; + +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.LinkedList; +import java.util.List; + +/** + * Default {@link MetadataCollector} implementation that uses the {@link DatabaseMetaData built-in JDBC support} for collecting + * database metadata. + * + * @see DatabaseMetaData + */ +class JdbcMetadataCollector implements MetadataCollector { + + public List getCatalogNames( Connection conn ) throws JdbcMetadataException { + List catalogNames = new LinkedList(); + + ResultSet catalogs = null; + try { + DatabaseMetaData dmd = conn.getMetaData(); + catalogs = dmd.getCatalogs(); + while (catalogs.next()) { + catalogNames.add(catalogs.getString("TABLE_CAT")); + } + return catalogNames; + } catch (SQLException se) { + throw new JdbcMetadataException(se); + } finally { + try { + catalogs.close(); + } catch (Exception ignore) { + } + } + } + + public List getColumns( Connection conn, + String catalogName, + String schemaName, + String tableName, + String columnName ) throws JdbcMetadataException { + List columnData = new LinkedList(); + + ResultSet columns = null; + try { + DatabaseMetaData dmd = conn.getMetaData(); + // Adjust default values of catalogName and schemaName to the "match tables with no catalog/schema" pattern + if (catalogName == null) catalogName = ""; + if (schemaName == null) schemaName = ""; + columns = dmd.getColumns(catalogName, schemaName, tableName, columnName); + while (columns.next()) { + ColumnMetadata column = new ColumnMetadata(columns.getString("COLUMN_NAME"), columns.getInt("DATA_TYPE"), + columns.getString("TYPE_NAME"), columns.getInt("COLUMN_SIZE"), + columns.getInt("DECIMAL_DIGITS"), columns.getInt("NUM_PREC_RADIX"), + getNullableBoolean(columns, "NULLABLE"), columns.getString("REMARKS"), + columns.getString("COLUMN_DEF"), columns.getInt("CHAR_OCTET_LENGTH"), + columns.getInt("ORDINAL_POSITION"), columns.getString("SCOPE_CATLOG"), + columns.getString("SCOPE_SCHEMA"), columns.getString("SCOPE_TABLE"), + getNullableInteger(columns, "SOURCE_DATA_TYPE")); + columnData.add(column); + + } + + return columnData; + } catch (SQLException se) { + throw new JdbcMetadataException(se); + } finally { + try { + columns.close(); + } catch (Exception ignore) { + } + } + } + + public List getSchemaNames( Connection conn, + String catalogName ) throws JdbcMetadataException { + List schemaNames = new LinkedList(); + + ResultSet schemas = null; + try { + DatabaseMetaData dmd = conn.getMetaData(); + schemas = dmd.getSchemas(); + while (schemas.next()) { + String catalogNameForSchema = schemas.getString("TABLE_CATALOG"); + if ((catalogName == null && schemas.wasNull()) + || (catalogName != null && catalogName.equals(catalogNameForSchema))) { + + schemaNames.add(schemas.getString("TABLE_SCHEM")); + } + } + + return schemaNames; + } catch (SQLException se) { + throw new JdbcMetadataException(se); + } finally { + try { + schemas.close(); + } catch (Exception ignore) { + } + } + } + + public List getTables( Connection conn, + String catalogName, + String schemaName, + String tableName ) throws JdbcMetadataException { + List tableData = new LinkedList(); + + ResultSet tables = null; + try { + DatabaseMetaData dmd = conn.getMetaData(); + + // Adjust default values of catalogName and schemaName to the "match tables with no catalog/schema" pattern + if (catalogName == null) catalogName = ""; + if (schemaName == null) schemaName = ""; + tables = dmd.getTables(catalogName, schemaName, tableName, null); + while (tables.next()) { + TableMetadata table = new TableMetadata(tables.getString("TABLE_NAME"), tables.getString("TABLE_TYPE"), + tables.getString("REMARKS"), tables.getString("TYPE_CAT"), + tables.getString("TYPE_SCHEM"), tables.getString("TYPE_NAME"), + tables.getString("SELF_REFERENCING_COL_NAME"), + tables.getString("REF_GENERATION")); + tableData.add(table); + + } + + return tableData; + } catch (SQLException se) { + throw new JdbcMetadataException(se); + } finally { + try { + tables.close(); + } catch (Exception ignore) { + } + } + } + + public List getProcedures( Connection conn, + String catalogName, + String schemaName, + String procedureName ) throws JdbcMetadataException { + List tableData = new LinkedList(); + + ResultSet procedures = null; + try { + DatabaseMetaData dmd = conn.getMetaData(); + + // Adjust default values of catalogName and schemaName to the "match tables with no catalog/schema" pattern + if (catalogName == null) catalogName = ""; + if (schemaName == null) schemaName = ""; + procedures = dmd.getProcedures(catalogName, schemaName, procedureName); + while (procedures.next()) { + ProcedureMetadata procedure = new ProcedureMetadata(procedures.getString("PROCEDURE_NAME"), + procedures.getString("REMARKS"), + procedures.getShort("PROCEDURE_TYPE")); + tableData.add(procedure); + + } + + return tableData; + } catch (SQLException se) { + throw new JdbcMetadataException(se); + } finally { + try { + procedures.close(); + } catch (Exception ignore) { + } + } + } + + private Boolean getNullableBoolean( ResultSet rs, + String columnName ) throws SQLException { + Boolean b = rs.getBoolean(columnName); + if (rs.wasNull()) b = null; + return b; + } + + private Integer getNullableInteger( ResultSet rs, + String columnName ) throws SQLException { + Integer i = rs.getInt(columnName); + if (rs.wasNull()) i = null; + return i; + } +} Property changes on: extensions\dna-connector-jdbc-metadata\src\main\java\org\jboss\dna\connector\meta\jdbc\JdbcMetadataCollector.java ___________________________________________________________________ Added: svn:keywords + Id Revision Added: svn:eol-style + LF Index: extensions/dna-connector-jdbc-metadata/src/main/java/org/jboss/dna/connector/meta/jdbc/JdbcMetadataException.java =================================================================== --- extensions/dna-connector-jdbc-metadata/src/main/java/org/jboss/dna/connector/meta/jdbc/JdbcMetadataException.java (revision 0) +++ extensions/dna-connector-jdbc-metadata/src/main/java/org/jboss/dna/connector/meta/jdbc/JdbcMetadataException.java (revision 0) @@ -0,0 +1,49 @@ +/* + * JBoss DNA (http://www.jboss.org/dna) + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. Some portions may be licensed + * to Red Hat, Inc. under one or more contributor license agreements. + * See the AUTHORS.txt file in the distribution for a full listing of + * individual contributors. + * + * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA + * is licensed to you under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * JBoss DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.jboss.dna.connector.meta.jdbc; + +/** + * Thrown to indicate that there was a failure while attempting to retrieve metadata + */ +public class JdbcMetadataException extends Exception { + + private static final long serialVersionUID = 1L; + + public JdbcMetadataException() { + } + + public JdbcMetadataException( String message ) { + super(message); + } + + public JdbcMetadataException( Throwable cause ) { + super(cause); + } + + public JdbcMetadataException( String message, + Throwable cause ) { + super(message, cause); + } + +} Property changes on: extensions\dna-connector-jdbc-metadata\src\main\java\org\jboss\dna\connector\meta\jdbc\JdbcMetadataException.java ___________________________________________________________________ Added: svn:keywords + Id Revision Added: svn:eol-style + LF Index: extensions/dna-connector-jdbc-metadata/src/main/java/org/jboss/dna/connector/meta/jdbc/JdbcMetadataI18n.java =================================================================== --- extensions/dna-connector-jdbc-metadata/src/main/java/org/jboss/dna/connector/meta/jdbc/JdbcMetadataI18n.java (revision 0) +++ extensions/dna-connector-jdbc-metadata/src/main/java/org/jboss/dna/connector/meta/jdbc/JdbcMetadataI18n.java (revision 0) @@ -0,0 +1,75 @@ +/* + * JBoss DNA (http://www.jboss.org/dna) + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. Some portions may be licensed + * to Red Hat, Inc. under one or more contributor license agreements. + * See the AUTHORS.txt file in the distribution for a full listing of + * individual contributors. + * + * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA + * is licensed to you under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * JBoss DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.jboss.dna.connector.meta.jdbc; + +import java.util.Locale; +import java.util.Set; +import org.jboss.dna.common.CommonI18n; +import org.jboss.dna.common.i18n.I18n; + +/** + * The internationalized string constants for the org.jboss.dna.connector.meta.jdbc.* packages. + */ +public final class JdbcMetadataI18n { + + public static I18n errorClosingConnection; + public static I18n errorObtainingConnection; + + public static I18n couldNotGetDatabaseMetadata; + public static I18n couldNotGetCatalogNames; + public static I18n couldNotGetSchemaNames; + public static I18n couldNotGetTableNames; + public static I18n couldNotGetTable; + public static I18n couldNotGetColumn; + public static I18n duplicateTablesWithSameName; + public static I18n couldNotGetProcedureNames; + public static I18n couldNotGetProcedure; + + public static I18n repositorySourceMustHaveName; + public static I18n errorFindingDataSourceInJndi; + public static I18n errorSettingContextClassLoader; + public static I18n driverClassNameAndUrlAreRequired; + public static I18n couldNotSetDriverProperties; + + static { + try { + I18n.initialize(JdbcMetadataI18n.class); + } catch (final Exception err) { + System.err.println(err); + } + } + + public static Set getLocalizationProblemLocales() { + return I18n.getLocalizationProblemLocales(CommonI18n.class); + } + + public static Set getLocalizationProblems() { + return I18n.getLocalizationProblems(CommonI18n.class); + } + + public static Set getLocalizationProblems( Locale locale ) { + return I18n.getLocalizationProblems(CommonI18n.class, locale); + } + +} Property changes on: extensions\dna-connector-jdbc-metadata\src\main\java\org\jboss\dna\connector\meta\jdbc\JdbcMetadataI18n.java ___________________________________________________________________ Added: svn:keywords + Id Revision Added: svn:eol-style + LF Index: extensions/dna-connector-jdbc-metadata/src/main/java/org/jboss/dna/connector/meta/jdbc/JdbcMetadataLexicon.java =================================================================== --- extensions/dna-connector-jdbc-metadata/src/main/java/org/jboss/dna/connector/meta/jdbc/JdbcMetadataLexicon.java (revision 0) +++ extensions/dna-connector-jdbc-metadata/src/main/java/org/jboss/dna/connector/meta/jdbc/JdbcMetadataLexicon.java (revision 0) @@ -0,0 +1,72 @@ +/* + * JBoss DNA (http://www.jboss.org/dna) + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. Some portions may be licensed + * to Red Hat, Inc. under one or more contributor license agreements. + * See the AUTHORS.txt file in the distribution for a full listing of + * individual contributors. + * + * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA + * is licensed to you under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * JBoss DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.jboss.dna.connector.meta.jdbc; + +import org.jboss.dna.graph.property.Name; +import org.jboss.dna.graph.property.basic.BasicName; + +/** + * The namespace and property names used within a {@link JdbcMetadataSource} to store internal information. + */ +public class JdbcMetadataLexicon { + + public static class Namespace { + public static final String URI = "http://www.jboss.org/dna/connector/meta/jdbc"; + public static final String PREFIX = "metajdbc"; + } + + public static final Name CATALOG = new BasicName(Namespace.URI, "catalog"); + public static final Name COLUMN = new BasicName(Namespace.URI, "column"); + public static final Name COLUMNS = new BasicName(Namespace.URI, "columns"); + public static final Name COLUMN_SIZE = new BasicName(Namespace.URI, "columnSize"); + public static final Name DATABASE_MAJOR_VERSION = new BasicName(Namespace.URI, "databaseMajorVersion"); + public static final Name DATABASE_MINOR_VERSION = new BasicName(Namespace.URI, "databaseMinorVersion"); + public static final Name DATABASE_PRODUCT_NAME = new BasicName(Namespace.URI, "databaseProductName"); + public static final Name DATABASE_PRODUCT_VERSION = new BasicName(Namespace.URI, "databaseProductVersion"); + public static final Name DATABASE_ROOT = new BasicName(Namespace.URI, "databaseRoot"); // Mixin type for root node + public static final Name DECIMAL_DIGITS = new BasicName(Namespace.URI, "decimalDigits"); + public static final Name DEFAULT_VALUE = new BasicName(Namespace.URI, "defaultValue"); + public static final Name DESCRIPTION = new BasicName(Namespace.URI, "description"); + public static final Name JDBC_DATA_TYPE = new BasicName(Namespace.URI, "jdbcDataType"); + public static final Name NULLABLE = new BasicName(Namespace.URI, "nullable"); + public static final Name LENGTH = new BasicName(Namespace.URI, "length"); + public static final Name ORDINAL_POSITION = new BasicName(Namespace.URI, "ordinalPosition"); + public static final Name PROCEDURE = new BasicName(Namespace.URI, "procedure"); + public static final Name PROCEDURES = new BasicName(Namespace.URI, "procedures"); + public static final Name PROCEDURE_RETURN_TYPE = new BasicName(Namespace.URI, "procedureReturnType"); + public static final Name RADIX = new BasicName(Namespace.URI, "radix"); + public static final Name REFERENCE_GENERATION_STRATEGY_NAME = new BasicName(Namespace.URI, "referenceGenerationStrategyName"); + public static final Name SCHEMA = new BasicName(Namespace.URI, "schema"); + public static final Name SCOPE_CATALOG_NAME = new BasicName(Namespace.URI, "scopeCatalogName"); + public static final Name SCOPE_SCHEMA_NAME = new BasicName(Namespace.URI, "scopeSchemaName"); + public static final Name SCOPE_TABLE_NAME = new BasicName(Namespace.URI, "scopeTableName"); + public static final Name SELF_REFERENCING_COLUMN_NAME = new BasicName(Namespace.URI, "selfReferencingColumnName"); + public static final Name SOURCE_JDBC_DATA_TYPE = new BasicName(Namespace.URI, "sourceJdbcDataType"); + public static final Name TABLE = new BasicName(Namespace.URI, "table"); + public static final Name TABLES = new BasicName(Namespace.URI, "tables"); + public static final Name TABLE_TYPE = new BasicName(Namespace.URI, "tableType"); + public static final Name TYPE_NAME = new BasicName(Namespace.URI, "typeName"); + public static final Name TYPE_CATALOG_NAME = new BasicName(Namespace.URI, "typeCatalogName"); + public static final Name TYPE_SCHEMA_NAME = new BasicName(Namespace.URI, "typeSchemaName"); +} Property changes on: extensions\dna-connector-jdbc-metadata\src\main\java\org\jboss\dna\connector\meta\jdbc\JdbcMetadataLexicon.java ___________________________________________________________________ Added: svn:keywords + Id Revision Added: svn:eol-style + LF Index: extensions/dna-connector-jdbc-metadata/src/main/java/org/jboss/dna/connector/meta/jdbc/JdbcMetadataRepository.java =================================================================== --- extensions/dna-connector-jdbc-metadata/src/main/java/org/jboss/dna/connector/meta/jdbc/JdbcMetadataRepository.java (revision 0) +++ extensions/dna-connector-jdbc-metadata/src/main/java/org/jboss/dna/connector/meta/jdbc/JdbcMetadataRepository.java (revision 0) @@ -0,0 +1,770 @@ +/* + * JBoss DNA (http://www.jboss.org/dna) + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. Some portions may be licensed + * to Red Hat, Inc. under one or more contributor license agreements. + * See the AUTHORS.txt file in the distribution for a full listing of + * individual contributors. + * + * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA + * is licensed to you under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * JBoss DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.jboss.dna.connector.meta.jdbc; + +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import net.jcip.annotations.ThreadSafe; +import org.jboss.dna.common.util.Logger; +import org.jboss.dna.graph.DnaLexicon; +import org.jboss.dna.graph.ExecutionContext; +import org.jboss.dna.graph.JcrLexicon; +import org.jboss.dna.graph.JcrNtLexicon; +import org.jboss.dna.graph.connector.LockFailedException; +import org.jboss.dna.graph.connector.RepositorySourceException; +import org.jboss.dna.graph.connector.path.DefaultPathNode; +import org.jboss.dna.graph.connector.path.PathNode; +import org.jboss.dna.graph.connector.path.PathRepository; +import org.jboss.dna.graph.connector.path.PathWorkspace; +import org.jboss.dna.graph.property.Name; +import org.jboss.dna.graph.property.NameFactory; +import org.jboss.dna.graph.property.Path; +import org.jboss.dna.graph.property.PathFactory; +import org.jboss.dna.graph.property.PathNotFoundException; +import org.jboss.dna.graph.property.Property; +import org.jboss.dna.graph.property.PropertyFactory; +import org.jboss.dna.graph.property.Path.Segment; +import org.jboss.dna.graph.query.QueryResults; +import org.jboss.dna.graph.request.AccessQueryRequest; +import org.jboss.dna.graph.request.LockBranchRequest.LockScope; + +@ThreadSafe +public class JdbcMetadataRepository extends PathRepository { + + public final static String TABLES_SEGMENT_NAME = "tables"; + public final static String PROCEDURES_SEGMENT_NAME = "procedures"; + + private final Logger log = Logger.getLogger(JdbcMetadataRepository.class); + private final JdbcMetadataSource source; + private Map rootNodeProperties; + private String databaseProductName; + private String databaseProductVersion; + private int databaseMajorVersion; + private int databaseMinorVersion; + + public JdbcMetadataRepository( JdbcMetadataSource source ) { + super(source.getName(), source.getRootUuid(), source.getDefaultWorkspaceName()); + this.source = source; + initialize(); + } + + @Override + protected synchronized void initialize() { + if (!this.workspaces.isEmpty()) return; + + String defaultWorkspaceName = getDefaultWorkspaceName(); + this.workspaces.put(defaultWorkspaceName, new JdbcMetadataWorkspace(defaultWorkspaceName)); + + ExecutionContext context = source.getRepositoryContext().getExecutionContext(); + PropertyFactory propFactory = context.getPropertyFactory(); + this.rootNodeProperties = new HashMap(); + + Connection conn = getConnection(); + try { + Name propName; + DatabaseMetaData dmd = conn.getMetaData(); + + databaseProductName = dmd.getDatabaseProductName(); + databaseProductVersion = dmd.getDatabaseProductVersion(); + databaseMajorVersion = dmd.getDatabaseMajorVersion(); + databaseMinorVersion = dmd.getDatabaseMinorVersion(); + + propName = JdbcMetadataLexicon.DATABASE_PRODUCT_NAME; + rootNodeProperties.put(propName, propFactory.create(propName, databaseProductName)); + propName = JdbcMetadataLexicon.DATABASE_PRODUCT_VERSION; + rootNodeProperties.put(propName, propFactory.create(propName, databaseProductVersion)); + propName = JdbcMetadataLexicon.DATABASE_MAJOR_VERSION; + rootNodeProperties.put(propName, propFactory.create(propName, databaseMajorVersion)); + propName = JdbcMetadataLexicon.DATABASE_MINOR_VERSION; + rootNodeProperties.put(propName, propFactory.create(propName, databaseMinorVersion)); + + rootNodeProperties.put(JcrLexicon.PRIMARY_TYPE, propFactory.create(JcrLexicon.PRIMARY_TYPE, DnaLexicon.ROOT)); + rootNodeProperties.put(JcrLexicon.MIXIN_TYPES, propFactory.create(JcrLexicon.PRIMARY_TYPE, + JdbcMetadataLexicon.DATABASE_ROOT)); + + rootNodeProperties = Collections.unmodifiableMap(rootNodeProperties); + } catch (SQLException se) { + throw new IllegalStateException(JdbcMetadataI18n.couldNotGetDatabaseMetadata.text(), se); + } finally { + closeConnection(conn); + } + } + + Connection getConnection() { + try { + return source.getDataSource().getConnection(); + } catch (SQLException se) { + throw new IllegalStateException(JdbcMetadataI18n.errorObtainingConnection.text(), se); + } + } + + void closeConnection( Connection connection ) { + assert connection != null; + try { + connection.close(); + } catch (SQLException se) { + log.error(se, JdbcMetadataI18n.errorClosingConnection); + } + } + + @ThreadSafe + private class JdbcMetadataWorkspace implements PathWorkspace { + + private final String name; + + JdbcMetadataWorkspace( String name ) { + this.name = name; + } + + public Path getLowestExistingPath( Path path ) { + PathFactory pathFactory = source.getRepositoryContext().getExecutionContext().getValueFactories().getPathFactory(); + + Path lastWorkingPath = pathFactory.createRootPath(); + + for (Segment segment : path.getSegmentsList()) { + Path newPathToTry = pathFactory.create(lastWorkingPath, segment); + + try { + getNode(newPathToTry); + } catch (PathNotFoundException pnfe) { + return lastWorkingPath; + } + } + + // If we got here, someone called getLowestExistingPath on a path that was invalid but now isn't. + return path; + } + + public String getName() { + return this.name; + } + + public PathNode getNode( Path path ) { + assert path != null; + + Segment[] segments = path.getSegmentsArray(); + switch (segments.length) { + case 0: + return getRoot(); + case 1: + return catalogNodeFor(segments); + case 2: + return schemaNodeFor(segments); + case 3: + if (TABLES_SEGMENT_NAME.equals(segments[2].getName().getLocalName())) { + return tablesNodeFor(segments); + } else if (PROCEDURES_SEGMENT_NAME.equals(segments[2].getName().getLocalName())) { + return proceduresNodeFor(segments); + } + + return null; + case 4: + if (TABLES_SEGMENT_NAME.equals(segments[2].getName().getLocalName())) { + return tableNodeFor(segments); + } else if (PROCEDURES_SEGMENT_NAME.equals(segments[2].getName().getLocalName())) { + return procedureNodeFor(segments); + } + return null; + case 5: + if (TABLES_SEGMENT_NAME.equals(segments[2].getName().getLocalName())) { + return columnNodeFor(segments); + } + default: + return null; + } + } + + private PathNode catalogNodeFor( Segment[] segments ) throws RepositorySourceException { + assert segments != null; + assert segments.length == 1; + + List schemaNames = new LinkedList(); + ExecutionContext context = source.getRepositoryContext().getExecutionContext(); + PathFactory pathFactory = context.getValueFactories().getPathFactory(); + PropertyFactory propFactory = context.getPropertyFactory(); + + Path nodePath = pathFactory.createAbsolutePath(segments); + + Connection conn = getConnection(); + String catalogName = segments[0].getName().getLocalName(); + if (catalogName.equals(source.getDefaultCatalogName())) catalogName = null; + + try { + MetadataCollector meta = source.getMetadataCollector(); + + // Make sure that this is a valid catalog for this database + List catalogNames = meta.getCatalogNames(conn); + + /* + * If a "real" (not default) catalog name is provided but it is not a valid + * catalog name for this database OR if the default catalog name is being used + * but this database uses real catalog names, then no catalog with that name exists. + */ + if ((catalogName != null && !catalogNames.contains(catalogName)) + || (catalogName == null && !catalogNames.isEmpty())) { + return null; + } + + List schemaNamesFromMeta = new ArrayList(meta.getSchemaNames(conn, catalogName)); + if (schemaNamesFromMeta.isEmpty()) { + schemaNamesFromMeta.add(source.getDefaultSchemaName()); + } + + for (String schemaName : schemaNamesFromMeta) { + schemaNames.add(pathFactory.createSegment(schemaName)); + } + + Map properties = new HashMap(); + properties.put(JcrLexicon.PRIMARY_TYPE, propFactory.create(JcrLexicon.PRIMARY_TYPE, JcrNtLexicon.UNSTRUCTURED)); + properties.put(JcrLexicon.MIXIN_TYPES, propFactory.create(JcrLexicon.MIXIN_TYPES, JdbcMetadataLexicon.CATALOG)); + + return new DefaultPathNode(nodePath, properties, schemaNames); + } catch (JdbcMetadataException se) { + throw new RepositorySourceException(JdbcMetadataI18n.couldNotGetSchemaNames.text(catalogName), se); + } finally { + closeConnection(conn); + } + } + + private PathNode schemaNodeFor( Segment[] segments ) throws RepositorySourceException { + assert segments != null; + assert segments.length == 2; + + ExecutionContext context = source.getRepositoryContext().getExecutionContext(); + PathFactory pathFactory = context.getValueFactories().getPathFactory(); + PropertyFactory propFactory = context.getPropertyFactory(); + + Path nodePath = pathFactory.createAbsolutePath(segments); + + Connection conn = getConnection(); + String catalogName = segments[0].getName().getLocalName(); + if (catalogName.equals(source.getDefaultCatalogName())) catalogName = null; + + String schemaName = segments[1].getName().getLocalName(); + if (schemaName.equals(source.getDefaultSchemaName())) schemaName = null; + + try { + MetadataCollector meta = source.getMetadataCollector(); + + // Make sure that the schema exists in the given catalog + List schemaNames = meta.getSchemaNames(conn, catalogName); + + /* + * If a "real" (not default) catalog name is provided but it is not a valid + * catalog name for this database OR if the default catalog name is being used + * but this database uses real catalog names, then no catalog with that name exists. + */ + if ((schemaName != null && !schemaNames.contains(schemaName)) || (schemaName == null && !schemaNames.isEmpty())) { + return null; + } + + Map properties = new HashMap(); + properties.put(JcrLexicon.PRIMARY_TYPE, propFactory.create(JcrLexicon.PRIMARY_TYPE, JcrNtLexicon.UNSTRUCTURED)); + properties.put(JcrLexicon.MIXIN_TYPES, propFactory.create(JcrLexicon.MIXIN_TYPES, JdbcMetadataLexicon.SCHEMA)); + + Segment[] children = new Segment[] {pathFactory.createSegment(TABLES_SEGMENT_NAME), + pathFactory.createSegment(PROCEDURES_SEGMENT_NAME)}; + + return new DefaultPathNode(nodePath, properties, Arrays.asList(children)); + } catch (JdbcMetadataException se) { + throw new RepositorySourceException(JdbcMetadataI18n.couldNotGetSchemaNames.text(catalogName), se); + } finally { + closeConnection(conn); + } + } + + private PathNode tablesNodeFor( Segment[] segments ) throws RepositorySourceException { + assert segments != null; + assert segments.length == 3; + assert TABLES_SEGMENT_NAME.equals(segments[2].getName().getLocalName()); + + ExecutionContext context = source.getRepositoryContext().getExecutionContext(); + PathFactory pathFactory = context.getValueFactories().getPathFactory(); + PropertyFactory propFactory = context.getPropertyFactory(); + + Path nodePath = pathFactory.createAbsolutePath(segments); + + Connection conn = getConnection(); + String catalogName = segments[0].getName().getLocalName(); + if (catalogName.equals(source.getDefaultCatalogName())) catalogName = null; + + String schemaName = segments[1].getName().getLocalName(); + if (schemaName.equals(source.getDefaultSchemaName())) schemaName = null; + + try { + MetadataCollector meta = source.getMetadataCollector(); + + // Make sure that the schema exists in the given catalog + List schemaNames = meta.getSchemaNames(conn, catalogName); + + /* + * If a "real" (not default) catalog name is provided but it is not a valid + * catalog name for this database OR if the default catalog name is being used + * but this database uses real catalog names, then no catalog with that name exists. + */ + if ((schemaName != null && !schemaNames.contains(schemaName)) || (schemaName == null && !schemaNames.isEmpty())) { + return null; + } + + Map properties = new HashMap(); + properties.put(JcrLexicon.PRIMARY_TYPE, propFactory.create(JcrLexicon.PRIMARY_TYPE, JcrNtLexicon.UNSTRUCTURED)); + properties.put(JcrLexicon.MIXIN_TYPES, propFactory.create(JcrLexicon.MIXIN_TYPES, JdbcMetadataLexicon.TABLES)); + + List tables = meta.getTables(conn, catalogName, schemaName, null); + List children = new ArrayList(tables.size()); + + for (TableMetadata table : tables) { + children.add(pathFactory.createSegment(table.getName())); + } + + return new DefaultPathNode(nodePath, properties, children); + } catch (JdbcMetadataException se) { + throw new RepositorySourceException(JdbcMetadataI18n.couldNotGetTableNames.text(catalogName, schemaName), se); + } finally { + closeConnection(conn); + } + } + + private PathNode tableNodeFor( Segment[] segments ) throws RepositorySourceException { + assert segments != null; + assert segments.length == 4; + assert TABLES_SEGMENT_NAME.equals(segments[2].getName().getLocalName()); + + ExecutionContext context = source.getRepositoryContext().getExecutionContext(); + PathFactory pathFactory = context.getValueFactories().getPathFactory(); + PropertyFactory propFactory = context.getPropertyFactory(); + + Path nodePath = pathFactory.createAbsolutePath(segments); + + Connection conn = getConnection(); + String catalogName = segments[0].getName().getLocalName(); + if (catalogName.equals(source.getDefaultCatalogName())) catalogName = null; + + String schemaName = segments[1].getName().getLocalName(); + if (schemaName.equals(source.getDefaultSchemaName())) schemaName = null; + + String tableName = segments[3].getName().getLocalName(); + + try { + MetadataCollector meta = source.getMetadataCollector(); + + List tables = meta.getTables(conn, catalogName, schemaName, tableName); + + // Make sure that the table exists in the given catalog and schema + if (tables.isEmpty()) { + return null; + } + assert tables.size() == 1; + TableMetadata table = tables.get(0); + + Map properties = new HashMap(); + Name propName; + propName = JcrLexicon.PRIMARY_TYPE; + properties.put(propName, propFactory.create(propName, JcrNtLexicon.UNSTRUCTURED)); + propName = JcrLexicon.MIXIN_TYPES; + properties.put(propName, propFactory.create(propName, JdbcMetadataLexicon.TABLE)); + + if (table.getType() != null) { + propName = JdbcMetadataLexicon.TABLE_TYPE; + properties.put(propName, propFactory.create(propName, table.getType())); + } + if (table.getDescription() != null) { + propName = JdbcMetadataLexicon.DESCRIPTION; + properties.put(propName, propFactory.create(propName, table.getDescription())); + } + if (table.getTypeCatalogName() != null) { + propName = JdbcMetadataLexicon.TYPE_CATALOG_NAME; + properties.put(propName, propFactory.create(propName, table.getTypeCatalogName())); + } + if (table.getTypeSchemaName() != null) { + propName = JdbcMetadataLexicon.TYPE_SCHEMA_NAME; + properties.put(propName, propFactory.create(propName, table.getTypeSchemaName())); + } + if (table.getTypeName() != null) { + propName = JdbcMetadataLexicon.TYPE_NAME; + properties.put(propName, propFactory.create(propName, table.getTypeName())); + } + if (table.getSelfReferencingColumnName() != null) { + propName = JdbcMetadataLexicon.SELF_REFERENCING_COLUMN_NAME; + properties.put(propName, propFactory.create(propName, table.getSelfReferencingColumnName())); + } + if (table.getReferenceGenerationStrategyName() != null) { + propName = JdbcMetadataLexicon.REFERENCE_GENERATION_STRATEGY_NAME; + properties.put(propName, propFactory.create(propName, table.getReferenceGenerationStrategyName())); + } + + List columns = meta.getColumns(conn, catalogName, schemaName, tableName, null); + List children = new ArrayList(columns.size()); + + for (ColumnMetadata column : columns) { + children.add(pathFactory.createSegment(column.getName())); + } + + return new DefaultPathNode(nodePath, properties, children); + } catch (JdbcMetadataException se) { + throw new RepositorySourceException(JdbcMetadataI18n.couldNotGetTable.text(catalogName, schemaName, tableName), + se); + } finally { + closeConnection(conn); + } + } + + private PathNode proceduresNodeFor( Segment[] segments ) throws RepositorySourceException { + assert segments != null; + assert segments.length == 3; + assert PROCEDURES_SEGMENT_NAME.equals(segments[2].getName().getLocalName()); + + ExecutionContext context = source.getRepositoryContext().getExecutionContext(); + PathFactory pathFactory = context.getValueFactories().getPathFactory(); + PropertyFactory propFactory = context.getPropertyFactory(); + + Path nodePath = pathFactory.createAbsolutePath(segments); + + Connection conn = getConnection(); + String catalogName = segments[0].getName().getLocalName(); + if (catalogName.equals(source.getDefaultCatalogName())) catalogName = null; + + String schemaName = segments[1].getName().getLocalName(); + if (schemaName.equals(source.getDefaultSchemaName())) schemaName = null; + + try { + MetadataCollector meta = source.getMetadataCollector(); + + // Make sure that the schema exists in the given catalog + List schemaNames = meta.getSchemaNames(conn, catalogName); + + /* + * If a "real" (not default) catalog name is provided but it is not a valid + * catalog name for this database OR if the default catalog name is being used + * but this database uses real catalog names, then no catalog with that name exists. + */ + if ((schemaName != null && !schemaNames.contains(schemaName)) || (schemaName == null && !schemaNames.isEmpty())) { + return null; + } + + Map properties = new HashMap(); + properties.put(JcrLexicon.PRIMARY_TYPE, propFactory.create(JcrLexicon.PRIMARY_TYPE, JcrNtLexicon.UNSTRUCTURED)); + properties.put(JcrLexicon.MIXIN_TYPES, propFactory.create(JcrLexicon.MIXIN_TYPES, JdbcMetadataLexicon.PROCEDURES)); + + List procedures = meta.getProcedures(conn, catalogName, schemaName, null); + List children = new ArrayList(procedures.size()); + + for (ProcedureMetadata procedure : procedures) { + children.add(pathFactory.createSegment(procedure.getName())); + } + + return new DefaultPathNode(nodePath, properties, children); + } catch (JdbcMetadataException se) { + throw new RepositorySourceException(JdbcMetadataI18n.couldNotGetProcedureNames.text(catalogName, schemaName), se); + } finally { + closeConnection(conn); + } + } + + private PathNode procedureNodeFor( Segment[] segments ) throws RepositorySourceException { + assert segments != null; + assert segments.length == 4; + assert PROCEDURES_SEGMENT_NAME.equals(segments[2].getName().getLocalName()); + + ExecutionContext context = source.getRepositoryContext().getExecutionContext(); + PathFactory pathFactory = context.getValueFactories().getPathFactory(); + PropertyFactory propFactory = context.getPropertyFactory(); + + Path nodePath = pathFactory.createAbsolutePath(segments); + + Connection conn = getConnection(); + String catalogName = segments[0].getName().getLocalName(); + if (catalogName.equals(source.getDefaultCatalogName())) catalogName = null; + + String schemaName = segments[1].getName().getLocalName(); + if (schemaName.equals(source.getDefaultSchemaName())) schemaName = null; + + String procedureName = segments[3].getName().getLocalName(); + + try { + MetadataCollector meta = source.getMetadataCollector(); + + List procedures = meta.getProcedures(conn, catalogName, schemaName, procedureName); + + // Make sure that the table exists in the given catalog and schema + if (procedures.isEmpty()) { + return null; + } + + /* + * Some RDMSes support overloaded procedures and thus can return multiple records for the + * same procedure name in the same catalog and schema (e.g., HSQLDB and the Math.abs procedure). + * + * That means that: + * 1. CollectorMetadata.getProcedures(...) needs to consider overloaded procedures when determining + * the stable order in which the procedures should be returned + * 2. Procedure nodes can have an SNS index > 1 + */ + if (segments[3].getIndex() > procedures.size()) { + return null; + } + + ProcedureMetadata procedure = procedures.get(segments[3].getIndex() - 1); + + Map properties = new HashMap(); + Name propName; + propName = JcrLexicon.PRIMARY_TYPE; + properties.put(propName, propFactory.create(propName, JcrNtLexicon.UNSTRUCTURED)); + propName = JcrLexicon.MIXIN_TYPES; + properties.put(propName, propFactory.create(propName, JdbcMetadataLexicon.PROCEDURE)); + + if (procedure.getDescription() != null) { + propName = JdbcMetadataLexicon.DESCRIPTION; + properties.put(propName, propFactory.create(propName, procedure.getDescription())); + } + propName = JdbcMetadataLexicon.PROCEDURE_RETURN_TYPE; + properties.put(propName, propFactory.create(propName, procedure.getType())); + + return new DefaultPathNode(nodePath, properties, Collections.emptyList()); + } catch (JdbcMetadataException se) { + throw new RepositorySourceException( + JdbcMetadataI18n.couldNotGetProcedure.text(catalogName, schemaName, procedureName), + se); + } finally { + closeConnection(conn); + } + } + + private PathNode columnNodeFor( Segment[] segments ) throws RepositorySourceException { + assert segments != null; + assert segments.length == 5; + assert TABLES_SEGMENT_NAME.equals(segments[2].getName().getLocalName()); + + ExecutionContext context = source.getRepositoryContext().getExecutionContext(); + PathFactory pathFactory = context.getValueFactories().getPathFactory(); + PropertyFactory propFactory = context.getPropertyFactory(); + + Path nodePath = pathFactory.createAbsolutePath(segments); + + Connection conn = getConnection(); + String catalogName = segments[0].getName().getLocalName(); + if (catalogName.equals(source.getDefaultCatalogName())) catalogName = null; + + String schemaName = segments[1].getName().getLocalName(); + if (schemaName.equals(source.getDefaultSchemaName())) schemaName = null; + + String tableName = segments[3].getName().getLocalName(); + String columnName = segments[4].getName().getLocalName(); + + try { + MetadataCollector meta = source.getMetadataCollector(); + + List columns = meta.getColumns(conn, catalogName, schemaName, tableName, columnName); + + // Make sure that the column exists in the given table, catalog, and schema + if (columns.isEmpty()) { + return null; + } + + assert columns.size() == 1 : "Duplicate column named " + columnName; + ColumnMetadata column = columns.get(0); + + Map properties = new HashMap(); + Name propName; + propName = JcrLexicon.PRIMARY_TYPE; + properties.put(propName, propFactory.create(propName, JcrNtLexicon.UNSTRUCTURED)); + propName = JcrLexicon.MIXIN_TYPES; + properties.put(propName, propFactory.create(propName, JdbcMetadataLexicon.COLUMN)); + + propName = JdbcMetadataLexicon.JDBC_DATA_TYPE; + properties.put(propName, propFactory.create(propName, column.getJdbcDataType())); + propName = JdbcMetadataLexicon.TYPE_NAME; + properties.put(propName, propFactory.create(propName, column.getTypeName())); + propName = JdbcMetadataLexicon.COLUMN_SIZE; + properties.put(propName, propFactory.create(propName, column.getColumnSize())); + propName = JdbcMetadataLexicon.DECIMAL_DIGITS; + properties.put(propName, propFactory.create(propName, column.getDecimalDigits())); + propName = JdbcMetadataLexicon.RADIX; + properties.put(propName, propFactory.create(propName, column.getRadix())); + if (column.getNullable() != null) { + propName = JdbcMetadataLexicon.NULLABLE; + properties.put(propName, propFactory.create(propName, column.getNullable())); + } + if (column.getDescription() != null) { + propName = JdbcMetadataLexicon.DESCRIPTION; + properties.put(propName, propFactory.create(propName, column.getDescription())); + } + if (column.getDefaultValue() != null) { + propName = JdbcMetadataLexicon.DEFAULT_VALUE; + properties.put(propName, propFactory.create(propName, column.getDefaultValue())); + } + propName = JdbcMetadataLexicon.LENGTH; + properties.put(propName, propFactory.create(propName, column.getLength())); + propName = JdbcMetadataLexicon.ORDINAL_POSITION; + properties.put(propName, propFactory.create(propName, column.getOrdinalPosition())); + if (column.getScopeCatalogName() != null) { + propName = JdbcMetadataLexicon.SCOPE_CATALOG_NAME; + + properties.put(propName, propFactory.create(propName, column.getScopeCatalogName())); + } + if (column.getScopeSchemaName() != null) { + propName = JdbcMetadataLexicon.SCOPE_SCHEMA_NAME; + properties.put(propName, propFactory.create(propName, column.getScopeSchemaName())); + } + if (column.getScopeTableName() != null) { + propName = JdbcMetadataLexicon.SCOPE_TABLE_NAME; + properties.put(propName, propFactory.create(propName, column.getScopeTableName())); + } + if (column.getSourceJdbcDataType() != null) { + propName = JdbcMetadataLexicon.SOURCE_JDBC_DATA_TYPE; + properties.put(propName, propFactory.create(propName, column.getSourceJdbcDataType())); + } + return new DefaultPathNode(nodePath, properties, Collections.emptyList()); + } catch (JdbcMetadataException se) { + throw new RepositorySourceException(JdbcMetadataI18n.couldNotGetColumn.text(catalogName, + schemaName, + tableName, + columnName), se); + } finally { + closeConnection(conn); + } + } + + public PathNode getRoot() throws RepositorySourceException { + List catalogNames = new LinkedList(); + ExecutionContext context = source.getRepositoryContext().getExecutionContext(); + PathFactory pathFactory = context.getValueFactories().getPathFactory(); + + Connection conn = getConnection(); + try { + MetadataCollector meta = source.getMetadataCollector(); + + for (String catalogName : meta.getCatalogNames(conn)) { + catalogNames.add(pathFactory.createSegment(catalogName)); + } + + if (catalogNames.isEmpty()) { + // This database must not support catalogs + catalogNames.add(pathFactory.createSegment(source.getDefaultCatalogName())); + } + + return new RootNode(catalogNames); + } catch (JdbcMetadataException se) { + throw new RepositorySourceException(JdbcMetadataI18n.couldNotGetCatalogNames.text(), se); + } finally { + closeConnection(conn); + } + } + + /** + * This connector does not support connector-level, persistent locking of nodes. + * + * @param node + * @param lockScope + * @param lockTimeoutInMillis + * @throws LockFailedException + */ + public void lockNode( PathNode node, + LockScope lockScope, + long lockTimeoutInMillis ) throws LockFailedException { + // Locking is not supported by this connector + } + + /** + * This connector does not support connector-level, persistent locking of nodes. + * + * @param node the node to be unlocked + */ + public void unlockNode( PathNode node ) { + // Locking is not supported by this connector + } + + /** + * {@inheritDoc} + * + * @see org.jboss.dna.graph.connector.map.MapWorkspace#query(org.jboss.dna.graph.ExecutionContext, + * org.jboss.dna.graph.request.AccessQueryRequest) + */ + public QueryResults query( ExecutionContext context, + AccessQueryRequest accessQuery ) { + throw new UnsupportedOperationException(); + } + + /** + * {@inheritDoc} + * + * @see org.jboss.dna.graph.connector.map.MapWorkspace#search(org.jboss.dna.graph.ExecutionContext, java.lang.String) + */ + public QueryResults search( ExecutionContext context, + String fullTextSearchExpression ) { + return null; + } + } + + private class RootNode implements PathNode { + private final List catalogNames; + + private RootNode( List catalogNames ) { + this.catalogNames = catalogNames; + } + + public List getChildSegments() { + return catalogNames; + } + + public Path getPath() { + ExecutionContext context = source.getRepositoryContext().getExecutionContext(); + return context.getValueFactories().getPathFactory().createRootPath(); + } + + public Map getProperties() { + return rootNodeProperties; + } + + public Property getProperty( ExecutionContext context, + String name ) { + NameFactory nameFactory = context.getValueFactories().getNameFactory(); + return rootNodeProperties.get(nameFactory.create(name)); + } + + public Property getProperty( Name name ) { + return rootNodeProperties.get(name); + } + + public Set getUniqueChildNames() { + Set childNames = new HashSet(catalogNames.size()); + + for (Segment catalogName : catalogNames) { + childNames.add(catalogName.getName()); + } + return childNames; + } + } + +} Property changes on: extensions\dna-connector-jdbc-metadata\src\main\java\org\jboss\dna\connector\meta\jdbc\JdbcMetadataRepository.java ___________________________________________________________________ Added: svn:keywords + Id Revision Added: svn:eol-style + LF Index: extensions/dna-connector-jdbc-metadata/src/main/java/org/jboss/dna/connector/meta/jdbc/JdbcMetadataSource.java =================================================================== --- extensions/dna-connector-jdbc-metadata/src/main/java/org/jboss/dna/connector/meta/jdbc/JdbcMetadataSource.java (revision 0) +++ extensions/dna-connector-jdbc-metadata/src/main/java/org/jboss/dna/connector/meta/jdbc/JdbcMetadataSource.java (revision 0) @@ -0,0 +1,756 @@ +/* + * JBoss DNA (http://www.jboss.org/dna) + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. Some portions may be licensed + * to Red Hat, Inc. under one or more contributor license agreements. + * See the AUTHORS.txt file in the distribution for a full listing of + * individual contributors. + * + * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA + * is licensed to you under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * JBoss DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.jboss.dna.connector.meta.jdbc; + +import java.beans.PropertyVetoException; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Hashtable; +import java.util.Map; +import java.util.UUID; +import javax.naming.Context; +import javax.naming.InitialContext; +import javax.naming.NamingException; +import javax.naming.RefAddr; +import javax.naming.Reference; +import javax.naming.StringRefAddr; +import javax.naming.spi.ObjectFactory; +import javax.sql.DataSource; +import net.jcip.annotations.ThreadSafe; +import org.jboss.dna.common.i18n.I18n; +import org.jboss.dna.common.util.Logger; +import org.jboss.dna.graph.ExecutionContext; +import org.jboss.dna.graph.cache.CachePolicy; +import org.jboss.dna.graph.connector.RepositoryConnection; +import org.jboss.dna.graph.connector.RepositoryContext; +import org.jboss.dna.graph.connector.RepositorySourceCapabilities; +import org.jboss.dna.graph.connector.RepositorySourceException; +import org.jboss.dna.graph.connector.path.PathRepositoryConnection; +import org.jboss.dna.graph.connector.path.PathRepositorySource; +import com.mchange.v2.c3p0.ComboPooledDataSource; + +@ThreadSafe +public class JdbcMetadataSource implements PathRepositorySource, ObjectFactory { + + private static final long serialVersionUID = 1L; + + private final Logger log = Logger.getLogger(JdbcMetadataSource.class); + + protected static final String SOURCE_NAME = "sourceName"; + protected static final String ROOT_NODE_UUID = "rootNodeUuid"; + protected static final String DATA_SOURCE_JNDI_NAME = "dataSourceJndiName"; + protected static final String USERNAME = "username"; + protected static final String PASSWORD = "password"; + protected static final String URL = "url"; + protected static final String DRIVER_CLASS_NAME = "driverClassName"; + protected static final String DRIVER_CLASSLOADER_NAME = "driverClassloaderName"; + protected static final String MAXIMUM_CONNECTIONS_IN_POOL = "maximumConnectionsInPool"; + protected static final String MINIMUM_CONNECTIONS_IN_POOL = "minimumConnectionsInPool"; + protected static final String MAXIMUM_CONNECTION_IDLE_TIME_IN_SECONDS = "maximumConnectionIdleTimeInSeconds"; + protected static final String MAXIMUM_SIZE_OF_STATEMENT_CACHE = "maximumSizeOfStatementCache"; + protected static final String NUMBER_OF_CONNECTIONS_TO_BE_ACQUIRED_AS_NEEDED = "numberOfConnectionsToBeAcquiredAsNeeded"; + protected static final String IDLE_TIME_IN_SECONDS_BEFORE_TESTING_CONNECTIONS = "idleTimeInSecondsBeforeTestingConnections"; + protected static final String CACHE_TIME_TO_LIVE_IN_MILLISECONDS = "cacheTimeToLiveInMilliseconds"; + protected static final String RETRY_LIMIT = "retryLimit"; + protected static final String DEFAULT_WORKSPACE = "defaultWorkspace"; + protected static final String DEFAULT_CATALOG_NAME = "defaultCatalogName"; + protected static final String DEFAULT_SCHEMA_NAME = "defaultSchemaName"; + protected static final String METADATA_COLLECTOR_CLASS_NAME = "metadataCollectorClassName"; + + /** + * This source does not support events. + */ + protected static final boolean SUPPORTS_EVENTS = false; + /** + * This source does support same-name-siblings for procedure nodes. + */ + protected static final boolean SUPPORTS_SAME_NAME_SIBLINGS = true; + /** + * This source does not support creating references. + */ + protected static final boolean SUPPORTS_REFERENCES = false; + /** + * This source does not support updates. + */ + public static final boolean SUPPORTS_UPDATES = false; + /** + * This source does not support creating workspaces. + */ + public static final boolean SUPPORTS_CREATING_WORKSPACES = false; + + /** + * The default UUID that is used for root nodes in a store. + */ + public static final String DEFAULT_ROOT_NODE_UUID = "cafebabe-cafe-babe-cafe-babecafebabe"; + + /** + * The initial {@link #getDefaultWorkspaceName() name of the default workspace} is "{@value} ", unless otherwise specified. + */ + public static final String DEFAULT_NAME_OF_DEFAULT_WORKSPACE = "default"; + + /** + * The initial {@link #getDefaultCatalogName() catalog name for databases that do not support catalogs} is "{@value} ", unless + * otherwise specified. + */ + public static final String DEFAULT_NAME_OF_DEFAULT_CATALOG = "default"; + + /** + * The initial {@link #getDefaultSchemaName() schema name for databases that do not support schemas} is "{@value} ", unless + * otherwise specified. + */ + public static final String DEFAULT_NAME_OF_DEFAULT_SCHEMA = "default"; + + private static final int DEFAULT_RETRY_LIMIT = 0; + private static final int DEFAULT_CACHE_TIME_TO_LIVE_IN_SECONDS = 60 * 5; // 5 minutes + private static final int DEFAULT_MAXIMUM_CONNECTIONS_IN_POOL = 5; + private static final int DEFAULT_MINIMUM_CONNECTIONS_IN_POOL = 0; + private static final int DEFAULT_MAXIMUM_CONNECTION_IDLE_TIME_IN_SECONDS = 60 * 10; // 10 minutes + private static final int DEFAULT_MAXIMUM_NUMBER_OF_STATEMENTS_TO_CACHE = 100; + private static final int DEFAULT_NUMBER_OF_CONNECTIONS_TO_ACQUIRE_AS_NEEDED = 1; + private static final int DEFAULT_IDLE_TIME_IN_SECONDS_BEFORE_TESTING_CONNECTIONS = 60 * 3; // 3 minutes + private static final MetadataCollector DEFAULT_METADATA_COLLECTOR = new JdbcMetadataCollector(); + + private volatile String name; + private volatile String dataSourceJndiName; + private volatile String username; + private volatile String password; + private volatile String url; + private volatile String driverClassName; + private volatile String driverClassloaderName; + private volatile String rootNodeUuid = DEFAULT_ROOT_NODE_UUID; + private volatile int maximumConnectionsInPool = DEFAULT_MAXIMUM_CONNECTIONS_IN_POOL; + private volatile int minimumConnectionsInPool = DEFAULT_MINIMUM_CONNECTIONS_IN_POOL; + private volatile int maximumConnectionIdleTimeInSeconds = DEFAULT_MAXIMUM_CONNECTION_IDLE_TIME_IN_SECONDS; + private volatile int maximumSizeOfStatementCache = DEFAULT_MAXIMUM_NUMBER_OF_STATEMENTS_TO_CACHE; + private volatile int numberOfConnectionsToAcquireAsNeeded = DEFAULT_NUMBER_OF_CONNECTIONS_TO_ACQUIRE_AS_NEEDED; + private volatile int idleTimeInSecondsBeforeTestingConnections = DEFAULT_IDLE_TIME_IN_SECONDS_BEFORE_TESTING_CONNECTIONS; + private volatile int retryLimit = DEFAULT_RETRY_LIMIT; + private volatile int cacheTimeToLiveInMilliseconds = DEFAULT_CACHE_TIME_TO_LIVE_IN_SECONDS * 1000; + private volatile String defaultWorkspace = DEFAULT_NAME_OF_DEFAULT_WORKSPACE; + private volatile String defaultCatalogName = DEFAULT_NAME_OF_DEFAULT_CATALOG; + private volatile String defaultSchemaName = DEFAULT_NAME_OF_DEFAULT_SCHEMA; + private volatile String metadataCollectorClassName = DEFAULT_METADATA_COLLECTOR.getClass().getName(); + + private volatile RepositorySourceCapabilities capabilities = new RepositorySourceCapabilities(SUPPORTS_SAME_NAME_SIBLINGS, + SUPPORTS_UPDATES, + SUPPORTS_EVENTS, + SUPPORTS_CREATING_WORKSPACES, + SUPPORTS_REFERENCES); + private transient DataSource dataSource; + private transient CachePolicy cachePolicy; + private transient JdbcMetadataRepository repository; + private transient RepositoryContext repositoryContext; + private transient UUID rootUuid = UUID.fromString(rootNodeUuid); + private transient MetadataCollector metadataCollector = DEFAULT_METADATA_COLLECTOR; + + final JdbcMetadataRepository repository() { + return this.repository; + } + + /** + * Set the time in milliseconds that content returned from this source may used while in the cache. + * + * @param cacheTimeToLive the time to live, in milliseconds; 0 if the time to live is not specified by this source; or a + * negative number for the default value + */ + public synchronized void setCacheTimeToLiveInMilliseconds( int cacheTimeToLive ) { + if (cacheTimeToLive < 0) cacheTimeToLive = DEFAULT_CACHE_TIME_TO_LIVE_IN_SECONDS; + this.cacheTimeToLiveInMilliseconds = cacheTimeToLive; + if (this.cacheTimeToLiveInMilliseconds == 0) { + this.cachePolicy = null; + } else { + final int ttl = this.cacheTimeToLiveInMilliseconds; + this.cachePolicy = new CachePolicy() { + + private static final long serialVersionUID = 1L; + + public long getTimeToLive() { + return ttl; + } + }; + } + } + + public long getCacheTimeToLiveInMilliseconds() { + return this.cacheTimeToLiveInMilliseconds; + } + + public CachePolicy getDefaultCachePolicy() { + return this.cachePolicy; + } + + public RepositoryContext getRepositoryContext() { + return this.repositoryContext; + } + + public void close() { + if (this.dataSource instanceof ComboPooledDataSource) { + ((ComboPooledDataSource)this.dataSource).close(); + } + } + + /** + * @return the datasource that corresponds to the login information provided to this source + * @see #setUsername(String) + * @see #setPassword(String) + * @see #setDriverClassName(String) + * @see #setDriverClassloaderName(String) + * @see #setUrl(String) + * @see #setDataSourceJndiName(String) + */ + DataSource getDataSource() { + if (this.dataSource == null) { + loadDataSource(); + } + return this.dataSource; + } + + public RepositorySourceCapabilities getCapabilities() { + return this.capabilities; + } + + /* + * Synchronized to avoid race conditions with setters of datasource-related properties + */ + private synchronized void loadDataSource() throws RepositorySourceException { + // Now set the mandatory information, overwriting anything that the subclasses may have tried ... + if (this.dataSource == null && this.dataSourceJndiName != null) { + // Try to load the DataSource from JNDI ... + try { + Context context = new InitialContext(); + dataSource = (DataSource)context.lookup(this.dataSourceJndiName); + } catch (Throwable t) { + log.error(t, JdbcMetadataI18n.errorFindingDataSourceInJndi, name, dataSourceJndiName); + } + } + + if (this.dataSource == null) { + // Set the context class loader, so that the driver could be found ... + if (this.repositoryContext != null && this.driverClassloaderName != null) { + try { + ExecutionContext context = this.repositoryContext.getExecutionContext(); + ClassLoader loader = context.getClassLoader(this.driverClassloaderName); + if (loader != null) { + Thread.currentThread().setContextClassLoader(loader); + } + } catch (Throwable t) { + I18n msg = JdbcMetadataI18n.errorSettingContextClassLoader; + log.error(t, msg, name, driverClassloaderName); + } + } + + if (this.driverClassName == null || this.url == null) { + throw new RepositorySourceException(JdbcMetadataI18n.driverClassNameAndUrlAreRequired.text(driverClassName, url)); + } + + ComboPooledDataSource cpds = new ComboPooledDataSource(); + + try { + cpds.setDriverClass(this.driverClassName); + cpds.setJdbcUrl(this.url); + cpds.setUser(this.username); + cpds.setPassword(this.password); + cpds.setMaxStatements(this.maximumSizeOfStatementCache); + cpds.setAcquireRetryAttempts(retryLimit); + cpds.setMaxIdleTime(this.maximumConnectionIdleTimeInSeconds); + cpds.setMinPoolSize(this.minimumConnectionsInPool); + cpds.setMaxPoolSize(this.maximumConnectionsInPool); + cpds.setAcquireIncrement(this.numberOfConnectionsToAcquireAsNeeded); + cpds.setIdleConnectionTestPeriod(this.idleTimeInSecondsBeforeTestingConnections); + + } catch (PropertyVetoException pve) { + throw new IllegalStateException(JdbcMetadataI18n.couldNotSetDriverProperties.text(), pve); + } + + this.dataSource = cpds; + } + + } + + public RepositoryConnection getConnection() throws RepositorySourceException { + if (this.name == null || this.name.trim().length() == 0) { + throw new RepositorySourceException(JdbcMetadataI18n.repositorySourceMustHaveName.text()); + } + + if (repository == null) { + repository = new JdbcMetadataRepository(this); + } + + return new PathRepositoryConnection(this, repository); + } + + /* + * (non-Javadoc) + * @see org.jboss.dna.graph.connector.RepositorySource#getName() + */ + public String getName() { + return this.name; + } + + public void setName( String name ) { + this.name = name; + } + + /* + * (non-Javadoc) + * @see org.jboss.dna.graph.connector.RepositorySource#getRetryLimit() + */ + public int getRetryLimit() { + return this.retryLimit; + } + + /* + * (non-Javadoc) + * @see org.jboss.dna.graph.connector.RepositorySource#initialize(org.jboss.dna.graph.connector.RepositoryContext) + */ + public void initialize( RepositoryContext context ) throws RepositorySourceException { + this.repositoryContext = context; + + } + + /* + * (non-Javadoc) + * @see org.jboss.dna.graph.connector.RepositorySource#setRetryLimit(int) + */ + public void setRetryLimit( int limit ) { + this.retryLimit = limit; + + } + + public Reference getReference() throws NamingException { + String className = getClass().getName(); + String factoryClassName = this.getClass().getName(); + Reference ref = new Reference(className, factoryClassName, null); + + ref.add(new StringRefAddr(SOURCE_NAME, getName())); + ref.add(new StringRefAddr(ROOT_NODE_UUID, getRootNodeUuid())); + ref.add(new StringRefAddr(DATA_SOURCE_JNDI_NAME, getDataSourceJndiName())); + ref.add(new StringRefAddr(USERNAME, getUsername())); + ref.add(new StringRefAddr(PASSWORD, getPassword())); + ref.add(new StringRefAddr(URL, getUrl())); + ref.add(new StringRefAddr(DRIVER_CLASS_NAME, getDriverClassName())); + ref.add(new StringRefAddr(DRIVER_CLASSLOADER_NAME, getDriverClassloaderName())); + ref.add(new StringRefAddr(MAXIMUM_CONNECTIONS_IN_POOL, Integer.toString(getMaximumConnectionsInPool()))); + ref.add(new StringRefAddr(MINIMUM_CONNECTIONS_IN_POOL, Integer.toString(getMinimumConnectionsInPool()))); + ref.add(new StringRefAddr(MAXIMUM_CONNECTION_IDLE_TIME_IN_SECONDS, + Integer.toString(getMaximumConnectionIdleTimeInSeconds()))); + ref.add(new StringRefAddr(MAXIMUM_SIZE_OF_STATEMENT_CACHE, Integer.toString(getMaximumSizeOfStatementCache()))); + ref.add(new StringRefAddr(NUMBER_OF_CONNECTIONS_TO_BE_ACQUIRED_AS_NEEDED, + Integer.toString(getNumberOfConnectionsToAcquireAsNeeded()))); + ref.add(new StringRefAddr(IDLE_TIME_IN_SECONDS_BEFORE_TESTING_CONNECTIONS, + Integer.toString(getIdleTimeInSecondsBeforeTestingConnections()))); + ref.add(new StringRefAddr(CACHE_TIME_TO_LIVE_IN_MILLISECONDS, Long.toString(getCacheTimeToLiveInMilliseconds()))); + ref.add(new StringRefAddr(DEFAULT_WORKSPACE, getDefaultWorkspaceName())); + ref.add(new StringRefAddr(RETRY_LIMIT, Integer.toString(getRetryLimit()))); + + ref.add(new StringRefAddr(DEFAULT_CATALOG_NAME, getDefaultCatalogName())); + ref.add(new StringRefAddr(DEFAULT_SCHEMA_NAME, getDefaultSchemaName())); + ref.add(new StringRefAddr(METADATA_COLLECTOR_CLASS_NAME, getMetadataCollectorClassName())); + + return ref; + } + + public Object getObjectInstance( Object obj, + javax.naming.Name name, + Context nameCtx, + Hashtable environment ) throws Exception { + if (!(obj instanceof Reference)) { + return null; + } + + Map values = new HashMap(); + Reference ref = (Reference)obj; + Enumeration en = ref.getAll(); + while (en.hasMoreElements()) { + RefAddr subref = (RefAddr)en.nextElement(); + if (subref instanceof StringRefAddr) { + String key = subref.getType(); + Object value = subref.getContent(); + if (value != null) values.put(key, value.toString()); + } + } + String sourceName = values.get(SOURCE_NAME); + String rootNodeUuid = values.get(ROOT_NODE_UUID); + String dataSourceJndiName = values.get(DATA_SOURCE_JNDI_NAME); + String username = values.get(USERNAME); + String password = values.get(PASSWORD); + String url = values.get(URL); + String driverClassName = values.get(DRIVER_CLASS_NAME); + String driverClassloaderName = values.get(DRIVER_CLASSLOADER_NAME); + String maxConnectionsInPool = values.get(MAXIMUM_CONNECTIONS_IN_POOL); + String minConnectionsInPool = values.get(MINIMUM_CONNECTIONS_IN_POOL); + String maxConnectionIdleTimeInSec = values.get(MAXIMUM_CONNECTION_IDLE_TIME_IN_SECONDS); + String maxSizeOfStatementCache = values.get(MAXIMUM_SIZE_OF_STATEMENT_CACHE); + String acquisitionIncrement = values.get(NUMBER_OF_CONNECTIONS_TO_BE_ACQUIRED_AS_NEEDED); + String idleTimeInSeconds = values.get(IDLE_TIME_IN_SECONDS_BEFORE_TESTING_CONNECTIONS); + String cacheTtlInMillis = values.get(CACHE_TIME_TO_LIVE_IN_MILLISECONDS); + String retryLimit = values.get(RETRY_LIMIT); + String defaultWorkspace = values.get(DEFAULT_WORKSPACE); + String defaultCatalogName = values.get(DEFAULT_CATALOG_NAME); + String defaultSchemaName = values.get(DEFAULT_SCHEMA_NAME); + String metadataCollectorClassName = values.get(METADATA_COLLECTOR_CLASS_NAME); + + // Create the source instance ... + JdbcMetadataSource source = new JdbcMetadataSource(); + if (sourceName != null) source.setName(sourceName); + if (rootNodeUuid != null) source.setRootNodeUuid(rootNodeUuid); + if (dataSourceJndiName != null) source.setDataSourceJndiName(dataSourceJndiName); + if (username != null) source.setUsername(username); + if (password != null) source.setPassword(password); + if (url != null) source.setUrl(url); + if (driverClassName != null) source.setDriverClassName(driverClassName); + if (driverClassloaderName != null) source.setDriverClassloaderName(driverClassloaderName); + if (maxConnectionsInPool != null) source.setMaximumConnectionsInPool(Integer.parseInt(maxConnectionsInPool)); + if (minConnectionsInPool != null) source.setMinimumConnectionsInPool(Integer.parseInt(minConnectionsInPool)); + if (maxConnectionIdleTimeInSec != null) source.setMaximumConnectionIdleTimeInSeconds(Integer.parseInt(maxConnectionIdleTimeInSec)); + if (maxSizeOfStatementCache != null) source.setMaximumSizeOfStatementCache(Integer.parseInt(maxSizeOfStatementCache)); + if (acquisitionIncrement != null) source.setNumberOfConnectionsToAcquireAsNeeded(Integer.parseInt(acquisitionIncrement)); + if (idleTimeInSeconds != null) source.setIdleTimeInSecondsBeforeTestingConnections(Integer.parseInt(idleTimeInSeconds)); + if (cacheTtlInMillis != null) source.setCacheTimeToLiveInMilliseconds(Integer.parseInt(cacheTtlInMillis)); + if (retryLimit != null) source.setRetryLimit(Integer.parseInt(retryLimit)); + if (defaultWorkspace != null) source.setDefaultWorkspaceName(defaultWorkspace); + if (defaultCatalogName != null) source.setDefaultCatalogName(defaultCatalogName); + if (defaultSchemaName != null) source.setDefaultCatalogName(defaultSchemaName); + if (metadataCollectorClassName != null) source.setMetadataCollectorClassName(metadataCollectorClassName); + + return source; + + } + + /** + * @return dataSourceJndiName + */ + public String getDataSourceJndiName() { + return dataSourceJndiName; + } + + /** + * @param dataSourceJndiName Sets dataSourceJndiName to the specified value. + */ + public void setDataSourceJndiName( String dataSourceJndiName ) { + if (dataSourceJndiName != null && dataSourceJndiName.trim().length() == 0) dataSourceJndiName = null; + this.dataSourceJndiName = dataSourceJndiName; + } + + /** + * @return driverClassName + */ + public String getDriverClassName() { + return driverClassName; + } + + /** + * @param driverClassName Sets driverClassName to the specified value. + */ + public synchronized void setDriverClassName( String driverClassName ) { + if (driverClassName != null && driverClassName.trim().length() == 0) driverClassName = null; + this.driverClassName = driverClassName; + } + + /** + * @return driverClassloaderName + */ + public String getDriverClassloaderName() { + return driverClassloaderName; + } + + /** + * @param driverClassloaderName Sets driverClassloaderName to the specified value. + */ + public synchronized void setDriverClassloaderName( String driverClassloaderName ) { + if (driverClassloaderName != null && driverClassloaderName.trim().length() == 0) driverClassloaderName = null; + this.driverClassloaderName = driverClassloaderName; + } + + /** + * @return username + */ + public String getUsername() { + return username; + } + + /** + * @param username Sets username to the specified value. + */ + public synchronized void setUsername( String username ) { + this.username = username; + } + + /** + * @return password + */ + public String getPassword() { + return password; + } + + /** + * @param password Sets password to the specified value. + */ + public synchronized void setPassword( String password ) { + this.password = password; + } + + /** + * @return url + */ + public String getUrl() { + return url; + } + + /** + * @param url Sets url to the specified value. + */ + public synchronized void setUrl( String url ) { + if (url != null && url.trim().length() == 0) url = null; + this.url = url; + } + + /** + * @return maximumConnectionsInPool + */ + public int getMaximumConnectionsInPool() { + return maximumConnectionsInPool; + } + + /** + * @param maximumConnectionsInPool Sets maximumConnectionsInPool to the specified value. + */ + public synchronized void setMaximumConnectionsInPool( int maximumConnectionsInPool ) { + if (maximumConnectionsInPool < 0) maximumConnectionsInPool = DEFAULT_MAXIMUM_CONNECTIONS_IN_POOL; + this.maximumConnectionsInPool = maximumConnectionsInPool; + } + + /** + * @return minimumConnectionsInPool + */ + public int getMinimumConnectionsInPool() { + return minimumConnectionsInPool; + } + + /** + * @param minimumConnectionsInPool Sets minimumConnectionsInPool to the specified value. + */ + public synchronized void setMinimumConnectionsInPool( int minimumConnectionsInPool ) { + if (minimumConnectionsInPool < 0) minimumConnectionsInPool = DEFAULT_MINIMUM_CONNECTIONS_IN_POOL; + this.minimumConnectionsInPool = minimumConnectionsInPool; + } + + /** + * @return maximumConnectionIdleTimeInSeconds + */ + public int getMaximumConnectionIdleTimeInSeconds() { + return maximumConnectionIdleTimeInSeconds; + } + + /** + * @param maximumConnectionIdleTimeInSeconds Sets maximumConnectionIdleTimeInSeconds to the specified value. + */ + public synchronized void setMaximumConnectionIdleTimeInSeconds( int maximumConnectionIdleTimeInSeconds ) { + if (maximumConnectionIdleTimeInSeconds < 0) maximumConnectionIdleTimeInSeconds = DEFAULT_MAXIMUM_CONNECTION_IDLE_TIME_IN_SECONDS; + this.maximumConnectionIdleTimeInSeconds = maximumConnectionIdleTimeInSeconds; + } + + /** + * @return maximumSizeOfStatementCache + */ + public int getMaximumSizeOfStatementCache() { + return maximumSizeOfStatementCache; + } + + /** + * @param maximumSizeOfStatementCache Sets maximumSizeOfStatementCache to the specified value. + */ + public synchronized void setMaximumSizeOfStatementCache( int maximumSizeOfStatementCache ) { + if (maximumSizeOfStatementCache < 0) maximumSizeOfStatementCache = DEFAULT_MAXIMUM_NUMBER_OF_STATEMENTS_TO_CACHE; + this.maximumSizeOfStatementCache = maximumSizeOfStatementCache; + } + + /** + * @return numberOfConnectionsToAcquireAsNeeded + */ + public int getNumberOfConnectionsToAcquireAsNeeded() { + return numberOfConnectionsToAcquireAsNeeded; + } + + /** + * @param numberOfConnectionsToAcquireAsNeeded Sets numberOfConnectionsToAcquireAsNeeded to the specified value. + */ + public synchronized void setNumberOfConnectionsToAcquireAsNeeded( int numberOfConnectionsToAcquireAsNeeded ) { + if (numberOfConnectionsToAcquireAsNeeded < 0) numberOfConnectionsToAcquireAsNeeded = DEFAULT_NUMBER_OF_CONNECTIONS_TO_ACQUIRE_AS_NEEDED; + this.numberOfConnectionsToAcquireAsNeeded = numberOfConnectionsToAcquireAsNeeded; + } + + /** + * @return idleTimeInSecondsBeforeTestingConnections + */ + public int getIdleTimeInSecondsBeforeTestingConnections() { + return idleTimeInSecondsBeforeTestingConnections; + } + + /** + * @param idleTimeInSecondsBeforeTestingConnections Sets idleTimeInSecondsBeforeTestingConnections to the specified value. + */ + public synchronized void setIdleTimeInSecondsBeforeTestingConnections( int idleTimeInSecondsBeforeTestingConnections ) { + if (idleTimeInSecondsBeforeTestingConnections < 0) idleTimeInSecondsBeforeTestingConnections = DEFAULT_IDLE_TIME_IN_SECONDS_BEFORE_TESTING_CONNECTIONS; + this.idleTimeInSecondsBeforeTestingConnections = idleTimeInSecondsBeforeTestingConnections; + } + + /** + * Set the {@link DataSource} instance that this source should use. + * + * @param dataSource the data source; may be null + * @see #getDataSource() + * @see #setDataSourceJndiName(String) + */ + /*package*/synchronized void setDataSource( DataSource dataSource ) { + this.dataSource = dataSource; + } + + /** + * @return rootNodeUuid + */ + public String getRootNodeUuid() { + return rootNodeUuid; + } + + /** + * @return rootUuid + */ + public UUID getRootUuid() { + return rootUuid; + } + + /** + * @param rootNodeUuid Sets rootNodeUuid to the specified value. + * @throws IllegalArgumentException if the string value cannot be converted to UUID + */ + public void setRootNodeUuid( String rootNodeUuid ) { + if (rootNodeUuid != null && rootNodeUuid.trim().length() == 0) rootNodeUuid = DEFAULT_ROOT_NODE_UUID; + this.rootUuid = UUID.fromString(rootNodeUuid); + this.rootNodeUuid = rootNodeUuid; + } + + /** + * Get the name of the default workspace. + * + * @return the name of the workspace that should be used by default, or null if there is no default workspace + */ + public String getDefaultWorkspaceName() { + return defaultWorkspace; + } + + /** + * Set the name of the workspace that should be used when clients don't specify a workspace. + * + * @param nameOfDefaultWorkspace the name of the workspace that should be used by default, or null if the + * {@link #DEFAULT_NAME_OF_DEFAULT_WORKSPACE default name} should be used + */ + public synchronized void setDefaultWorkspaceName( String nameOfDefaultWorkspace ) { + this.defaultWorkspace = nameOfDefaultWorkspace != null ? nameOfDefaultWorkspace : DEFAULT_NAME_OF_DEFAULT_WORKSPACE; + } + + /** + * Get the name of the default catalog. + * + * @return the name that should be used as the catalog name when the database does not support catalogs + */ + public String getDefaultCatalogName() { + return defaultCatalogName; + } + + /** + * Set the name of the catalog that should be used when the database does not support catalogs. + * + * @param defaultCatalogName the name that should be used as the catalog name by default, or null if the + * {@link #DEFAULT_NAME_OF_DEFAULT_CATALOG default name} should be used + */ + public void setDefaultCatalogName( String defaultCatalogName ) { + this.defaultCatalogName = defaultCatalogName == null ? DEFAULT_NAME_OF_DEFAULT_CATALOG : defaultCatalogName; + } + + /** + * Get the name of the default schema. + * + * @return the name that should be used as the schema name when the database does not support schemas + */ + public String getDefaultSchemaName() { + return defaultSchemaName; + } + + /** + * Set the name of the schema that should be used when the database does not support schemas. + * + * @param defaultSchemaName the name that should be used as the schema name by default, or null if the + * {@link #DEFAULT_NAME_OF_DEFAULT_SCHEMA default name} should be used + */ + public void setDefaultSchemaName( String defaultSchemaName ) { + this.defaultSchemaName = defaultSchemaName == null ? DEFAULT_NAME_OF_DEFAULT_SCHEMA : defaultSchemaName; + } + + /** + * Get the class name of the metadata collector. + * + * @return the name the class name of the metadata collector + */ + public String getMetadataCollectorClassName() { + return metadataCollectorClassName; + } + + /** + * Set the class name of the metadata collector and instantiates a new metadata collector object for that class + * + * @param metadataCollectorClassName the class name for the metadata collector, or null if the + * {@link #DEFAULT_METADATA_COLLECTOR default metadata collector} should be used + * @throws ClassNotFoundException if the the named metadata collector class cannot be located + * @throws IllegalAccessException if the metadata collector class or its nullary constructor is not accessible. + * @throws InstantiationException if the metadata collector class represents an abstract class, an interface, an array class, + * a primitive type, or void; or if the class has no nullary constructor; or if the instantiation fails for some other + * reason. + * @throws ClassCastException if the given class cannot be cast to {@link MetadataCollector}. + * @see Class#forName(String) + * @see Class#newInstance() + */ + @SuppressWarnings( "unchecked" ) + public synchronized void setMetadataCollectorClassName( String metadataCollectorClassName ) + throws ClassNotFoundException, IllegalAccessException, InstantiationException { + if (metadataCollectorClassName == null) { + this.metadataCollectorClassName = DEFAULT_METADATA_COLLECTOR.getClass().getName(); + this.metadataCollector = DEFAULT_METADATA_COLLECTOR; + } else { + Class newCollectorClass = Class.forName(metadataCollectorClassName); + this.metadataCollector = (MetadataCollector)newCollectorClass.newInstance(); + this.metadataCollectorClassName = metadataCollectorClassName; + } + } + + /** + * Returns the metadata collector instance + * + * @return the metadata collector + */ + public synchronized MetadataCollector getMetadataCollector() { + return metadataCollector; + } + +} Property changes on: extensions\dna-connector-jdbc-metadata\src\main\java\org\jboss\dna\connector\meta\jdbc\JdbcMetadataSource.java ___________________________________________________________________ Added: svn:keywords + Id Revision Added: svn:eol-style + LF Index: extensions/dna-connector-jdbc-metadata/src/main/java/org/jboss/dna/connector/meta/jdbc/MetadataCollector.java =================================================================== --- extensions/dna-connector-jdbc-metadata/src/main/java/org/jboss/dna/connector/meta/jdbc/MetadataCollector.java (revision 0) +++ extensions/dna-connector-jdbc-metadata/src/main/java/org/jboss/dna/connector/meta/jdbc/MetadataCollector.java (revision 0) @@ -0,0 +1,147 @@ +/* + * JBoss DNA (http://www.jboss.org/dna) + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. Some portions may be licensed + * to Red Hat, Inc. under one or more contributor license agreements. + * See the AUTHORS.txt file in the distribution for a full listing of + * individual contributors. + * + * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA + * is licensed to you under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * JBoss DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.jboss.dna.connector.meta.jdbc; + +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.util.List; + +/** + * The {@code MetadataCollector} provides hooks for DBMS-specific implementations of metadata retrieval methods. These methods + * largely duplicate what is provided in {@link DatabaseMetaData the JDBC metadata interface}, but allow a pluggable way to work + * around JDBC driver-specific shortcomings. + *

+ * For convenience, a {@link JdbcMetadataCollector} default implementation} of this interface is provided that is based on + * {@link DatabaseMetaData}. + *

+ * + * @see JdbcMetadataCollector + */ +public interface MetadataCollector { + + /** + * Return the list of catalog names that currently exist in the database to which {@code connection} is connected. The names + * must be sorted in a manner that is stable between successive calls to this method. + * + * @param conn the connection to the database; must not be non-null and must be open. This connection should not be closed by + * this method. + * @return An ordered list of the catalogs in the database, or an empty list if no catalogs exist; may not be null + * @throws JdbcMetadataException if the catalog names cannot be retrieved + * @see DatabaseMetaData#getCatalogs() + */ + List getCatalogNames( Connection conn ) throws JdbcMetadataException; + + /** + * Return the list of schema names that currently exist in the database to which {@code connection} is connected within the + * named catalog. If {@code catalogName} is null, then all schema names should be returned regardless of the catalog with + * which they are associated. The schema names must be sorted in a manner that is stable between successive calls to this + * method. + * + * @param conn the connection to the database; must not be non-null and must be open. This connection should not be closed by + * this method. + * @param catalogName the name of the catalog to which returned schemas must belong, or null if all schemas are to be returned + * @return An ordered list of the schemas in the database, or an empty list if no schemas exist; may not be null + * @throws JdbcMetadataException if the schema names cannot be retrieved + * @see DatabaseMetaData#getSchemas() + */ + List getSchemaNames( Connection conn, + String catalogName ) throws JdbcMetadataException; + + /** + * Return the list of tables that currently exist in the database to which {@code connection} is connected within the named + * catalog (if {@code catalogName} is non-null) and named schema (if {@code schemaName} is non-null). If {@code tableName} is + * null, then all tables which conform to the catalog and schema restriction noted previously should be returned. If {@code + * tableName} is non-null, then only the table(s) that exactly match that name should be returned. The table metadata must be + * sorted in a manner that is stable between successive calls to this method. + * + * @param conn the connection to the database; must not be non-null and must be open. This connection should not be closed by + * this method. + * @param catalogName the name of the catalog to which returned tables must belong, or null if tables are to be returned + * without regard to their catalog + * @param schemaName the name of the schema to which returned tables must belong, or null if tables are to be returned without + * regard to their schema + * @param tableName the name of the table to be returned, or null if all tables within the given catalog and schema are to be + * returned + * @return An ordered list of the tables in the database that match the given constraints, or an empty list if no tables exist + * that match the given constraints; may not be null + * @throws JdbcMetadataException if the table metadata cannot be retrieved + * @see DatabaseMetaData#getTables(String, String, String, String[]) + */ + List getTables( Connection conn, + String catalogName, + String schemaName, + String tableName ) throws JdbcMetadataException; + + /** + * Return the list of columns that currently exist in the database to which {@code connection} is connected within the named + * catalog (if {@code catalogName} is non-null), named schema (if {@code schemaName} is non-null), and named table. If {@code + * columnName} is null, then all columns which conform to the catalog, schema, and table restrictions noted previously should + * be returned. If {@code columnName} is non-null, then only the column that exactly matches that name should be returned. The + * column metadata must be sorted in a manner that is stable between successive calls to this method. + * + * @param conn the connection to the database; must not be non-null and must be open. This connection should not be closed by + * this method. + * @param catalogName the name of the catalog to which returned columns must belong, or null if columns are to be returned + * without regard to their catalog + * @param schemaName the name of the schema to which returned columns must belong, or null if columns are to be returned + * without regard to their schema + * @param tableName the name of the table to which returned columns must belong; may not be null + * @param columnName the name of the column to be returned, or null if all columns within the given catalog, schema, and table + * are to be returned + * @return An ordered list of the columns in the database that match the given constraints, or an empty list if no columns + * exist that match the given constraints; may not be null + * @throws JdbcMetadataException if the column metadata cannot be retrieved + * @see DatabaseMetaData#getColumns(String, String, String, String) + */ + List getColumns( Connection conn, + String catalogName, + String schemaName, + String tableName, + String columnName ) throws JdbcMetadataException; + + /** + * Return the list of procedures that currently exist in the database to which {@code connection} is connected within the + * named catalog (if {@code catalogName} is non-null) and named schema (if {@code schemaName} is non-null). If {@code + * procedureName} is null, then all procedures which conform to the catalog and schema restriction noted previously should be + * returned. If {@code procedureName} is non-null, then only the procedure(s) that exactly match that name should be returned. + * The procedure metadata must be sorted in a manner that is stable between successive calls to this method. + * + * @param conn the connection to the database; must not be non-null and must be open. This connection should not be closed by + * this method. + * @param catalogName the name of the catalog to which returned procedures must belong, or null if procedures are to be + * returned without regard to their catalog + * @param schemaName the name of the schema to which returned procedures must belong, or null if procedures are to be returned + * without regard to their schema + * @param procedureName the name of the procedure(s) to be returned, or null if all procedures within the given catalog and + * schema are to be returned + * @return An ordered list of the procedures in the database that match the given constraints, or an empty list if no + * procedures exist that match the given constraints; may not be null + * @throws JdbcMetadataException if the procedure metadata cannot be retrieved + */ + List getProcedures( Connection conn, + String catalogName, + String schemaName, + String procedureName ) throws JdbcMetadataException; + +} Property changes on: extensions\dna-connector-jdbc-metadata\src\main\java\org\jboss\dna\connector\meta\jdbc\MetadataCollector.java ___________________________________________________________________ Added: svn:keywords + Id Revision Added: svn:eol-style + LF Index: extensions/dna-connector-jdbc-metadata/src/main/java/org/jboss/dna/connector/meta/jdbc/ProcedureMetadata.java =================================================================== --- extensions/dna-connector-jdbc-metadata/src/main/java/org/jboss/dna/connector/meta/jdbc/ProcedureMetadata.java (revision 0) +++ extensions/dna-connector-jdbc-metadata/src/main/java/org/jboss/dna/connector/meta/jdbc/ProcedureMetadata.java (revision 0) @@ -0,0 +1,71 @@ +/* + * JBoss DNA (http://www.jboss.org/dna) + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. Some portions may be licensed + * to Red Hat, Inc. under one or more contributor license agreements. + * See the AUTHORS.txt file in the distribution for a full listing of + * individual contributors. + * + * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA + * is licensed to you under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * JBoss DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.jboss.dna.connector.meta.jdbc; + +import java.sql.DatabaseMetaData; + +/** + * Container for column-level metadata. The fields in this class roughly parallel the information returned from the + * {@link DatabaseMetaData#getProcedures(String, String, String)} method. + */ +public class ProcedureMetadata { + + private final String name; + private final String description; + private final int type; + + public ProcedureMetadata( String name, + String description, + int type ) { + super(); + this.name = name; + this.description = description; + this.type = type; + } + + /** + * @return the procedure name (PROCEDURE_NAME in the {@link DatabaseMetaData#getProcedures(String, String, String)} result + * set). + */ + public String getName() { + return name; + } + + /** + * @return the procedure description (REMARKS in the {@link DatabaseMetaData#getProcedures(String, String, String)} result + * set). + */ + public String getDescription() { + return description; + } + + /** + * @return the kind of procedure (PROCEDURE_TYPE in the {@link DatabaseMetaData#getProcedures(String, String, String)} result + * set). + */ + public int getType() { + return type; + } + +} Property changes on: extensions\dna-connector-jdbc-metadata\src\main\java\org\jboss\dna\connector\meta\jdbc\ProcedureMetadata.java ___________________________________________________________________ Added: svn:keywords + Id Revision Added: svn:eol-style + LF Index: extensions/dna-connector-jdbc-metadata/src/main/java/org/jboss/dna/connector/meta/jdbc/TableMetadata.java =================================================================== --- extensions/dna-connector-jdbc-metadata/src/main/java/org/jboss/dna/connector/meta/jdbc/TableMetadata.java (revision 0) +++ extensions/dna-connector-jdbc-metadata/src/main/java/org/jboss/dna/connector/meta/jdbc/TableMetadata.java (revision 0) @@ -0,0 +1,126 @@ +/* + * JBoss DNA (http://www.jboss.org/dna) + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. Some portions may be licensed + * to Red Hat, Inc. under one or more contributor license agreements. + * See the AUTHORS.txt file in the distribution for a full listing of + * individual contributors. + * + * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA + * is licensed to you under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * JBoss DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.jboss.dna.connector.meta.jdbc; + +import java.sql.DatabaseMetaData; +import net.jcip.annotations.Immutable; + +/** + * Container for table-level metadata. The fields in this class roughly parallel the information returned from the + * {@link DatabaseMetaData#getTables(String, String, String, String[])} method. + */ +@Immutable +public class TableMetadata { + + private final String name; + private final String type; + private final String description; + private final String typeCatalogName; + private final String typeSchemaName; + private final String typeName; + private final String selfReferencingColumnName; + private final String referenceGenerationStrategyName; + + public TableMetadata( String name, + String type, + String description, + String typeCatalogName, + String typeSchemaName, + String typeName, + String selfReferencingColumnName, + String referenceGenerationStrategyName ) { + super(); + this.name = name; + this.type = type; + this.description = description; + this.typeCatalogName = typeCatalogName; + this.typeSchemaName = typeSchemaName; + this.typeName = typeName; + this.selfReferencingColumnName = selfReferencingColumnName; + this.referenceGenerationStrategyName = referenceGenerationStrategyName; + } + + /** + * @return the table name (TABLE_NAME in the {@link DatabaseMetaData#getTables(String, String, String, String[])} result set). + */ + public String getName() { + return name; + } + + /** + * @return the table type (TABLE_TYPE in the {@link DatabaseMetaData#getTables(String, String, String, String[])} result set). + */ + public String getType() { + return type; + } + + /** + * @return the table description (REMARKS in the {@link DatabaseMetaData#getTables(String, String, String, String[])} result + * set). + */ + public String getDescription() { + return description; + } + + /** + * @return the table types catalog name (TYPE_CAT in the {@link DatabaseMetaData#getTables(String, String, String, String[])} + * result set). + */ + public String getTypeCatalogName() { + return typeCatalogName; + } + + /** + * @return the table types schema name (TYPE_SCHEM in the {@link DatabaseMetaData#getTables(String, String, String, String[])} + * result set). + */ + public String getTypeSchemaName() { + return typeSchemaName; + } + + /** + * @return the table type name (TYPE_NAME in the {@link DatabaseMetaData#getTables(String, String, String, String[])} result + * set). + */ + public String getTypeName() { + return typeName; + } + + /** + * @return per the Javadoc for the DatabaseMetaData method, "the name of the designated 'identifier' column of a typed table" + * (SELF_REFERENCING_COL_NAME in the {@link DatabaseMetaData#getTables(String, String, String, String[])} result set). + */ + public String getSelfReferencingColumnName() { + return selfReferencingColumnName; + } + + /** + * @return the strategy for creating the values in the self-referencing column (REF_GENERATION in the + * {@link DatabaseMetaData#getTables(String, String, String, String[])} result set). + */ + public String getReferenceGenerationStrategyName() { + return referenceGenerationStrategyName; + } + +} Property changes on: extensions\dna-connector-jdbc-metadata\src\main\java\org\jboss\dna\connector\meta\jdbc\TableMetadata.java ___________________________________________________________________ Added: svn:keywords + Id Revision Added: svn:eol-style + LF Index: extensions/dna-connector-jdbc-metadata/src/main/resources/org/jboss/dna/connector/meta/jdbc/JdbcMetadataI18n.properties =================================================================== --- extensions/dna-connector-jdbc-metadata/src/main/resources/org/jboss/dna/connector/meta/jdbc/JdbcMetadataI18n.properties (revision 0) +++ extensions/dna-connector-jdbc-metadata/src/main/resources/org/jboss/dna/connector/meta/jdbc/JdbcMetadataI18n.properties (revision 0) @@ -0,0 +1,42 @@ +# +# JBoss DNA (http://www.jboss.org/dna) +# See the COPYRIGHT.txt file distributed with this work for information +# regarding copyright ownership. Some portions may be licensed +# to Red Hat, Inc. under one or more contributor license agreements. +# See the AUTHORS.txt file in the distribution for a full listing of +# individual contributors. +# +# JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA +# is licensed to you under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation; either version 2.1 of +# the License, or (at your option) any later version. +# +# JBoss DNA is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this software; if not, write to the Free +# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA, or see the FSF site: http://www.fsf.org. +# + +errorClosingConnection = Error closing SQL connection +errorObtainingConnection = Error obtaining SQL connection + +couldNotGetDatabaseMetadata = Could not obtain database-level metadata +couldNotGetCatalogNames = Could not obtain catalog names for database +couldNotGetSchemaNames = Could not obtain schema names for catalog "{0}" +couldNotGetTableNames = Could not get the table names for schema "{1}" in catalog "{0}" +couldNotGetTable = Could not get metadata for the table named "{2}" in schema "{1}" in catalog "{0}" +couldNotGetColumn = Could not get metadata for the column named "{3}" in the table named "{2}" in schema "{1}" in catalog "{0}" +duplicateTablesWithSameName = Multiple tables named "{2}" in catalog "{0}" and schema "{1}" +couldNotGetProcedureNames = Could not get the procedure names for schema "{1}" in catalog "{0}" +couldNotGetProcedure = Could not get metadata for the procedure named "{2}" in schema "{1}" in catalog "{0}" + +repositorySourceMustHaveName = The JDBC Metadata Store repository source must have a name +errorFindingDataSourceInJndi = JDBC Metadata repository source {0} unable to find DataSource in JNDI at {1} +errorSettingContextClassLoader = Error while setting the current context class loader for JDBC Metadata repository source {0} to classloader name {1} +driverClassNameAndUrlAreRequired = Since no valid JNDI name for a data source was provided, a JDBC driver class name ({0}) and a JDBC driver URL ({1}) must both be provided +couldNotSetDriverProperties = Could not set driver properties on c3p0 data source Index: extensions/dna-connector-jdbc-metadata/src/test/java/org/jboss/dna/connector/meta/jdbc/JdbcMetadataConnectorTest.java =================================================================== --- extensions/dna-connector-jdbc-metadata/src/test/java/org/jboss/dna/connector/meta/jdbc/JdbcMetadataConnectorTest.java (revision 0) +++ extensions/dna-connector-jdbc-metadata/src/test/java/org/jboss/dna/connector/meta/jdbc/JdbcMetadataConnectorTest.java (revision 0) @@ -0,0 +1,72 @@ +/* + * JBoss DNA (http://www.jboss.org/dna) + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. Some portions may be licensed + * to Red Hat, Inc. under one or more contributor license agreements. + * See the AUTHORS.txt file in the distribution for a full listing of + * individual contributors. + * + * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA + * is licensed to you under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * JBoss DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.jboss.dna.connector.meta.jdbc; + +import java.io.IOException; +import javax.naming.NamingException; +import org.jboss.dna.graph.Graph; +import org.jboss.dna.graph.connector.RepositorySource; +import org.jboss.dna.graph.connector.test.ReadableConnectorTest; +import org.junit.After; +import org.xml.sax.SAXException; + +public class JdbcMetadataConnectorTest extends ReadableConnectorTest { + + private JdbcMetadataSource source; + + /** + * {@inheritDoc} + * + * @see org.jboss.dna.graph.connector.test.AbstractConnectorTest#setUpSource() + */ + @Override + protected RepositorySource setUpSource() throws NamingException { + this.source = TestEnvironment.configureJdbcMetadataSource("Test Repository", this); + + return source; + } + + /** + * {@inheritDoc} + * + * @throws SAXException + * @throws IOException + * @see org.jboss.dna.graph.connector.test.AbstractConnectorTest#initializeContent(org.jboss.dna.graph.Graph) + */ + @Override + protected void initializeContent( Graph graph ) throws Exception { + TestEnvironment.executeDdl(this.source.getDataSource(), "/create.ddl"); + + graph = Graph.create(source, context); + } + + @Override + @After + public void afterEach() throws Exception { + TestEnvironment.executeDdl(this.source.getDataSource(), "/drop.ddl"); + + this.source.close(); + } + +} Property changes on: extensions\dna-connector-jdbc-metadata\src\test\java\org\jboss\dna\connector\meta\jdbc\JdbcMetadataConnectorTest.java ___________________________________________________________________ Added: svn:keywords + Id Revision Added: svn:eol-style + LF Index: extensions/dna-connector-jdbc-metadata/src/test/java/org/jboss/dna/connector/meta/jdbc/JdbcMetadataI18nTest.java =================================================================== --- extensions/dna-connector-jdbc-metadata/src/test/java/org/jboss/dna/connector/meta/jdbc/JdbcMetadataI18nTest.java (revision 0) +++ extensions/dna-connector-jdbc-metadata/src/test/java/org/jboss/dna/connector/meta/jdbc/JdbcMetadataI18nTest.java (revision 0) @@ -0,0 +1,34 @@ +/* + * JBoss DNA (http://www.jboss.org/dna) + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. Some portions may be licensed + * to Red Hat, Inc. under one or more contributor license agreements. + * See the AUTHORS.txt file in the distribution for a full listing of + * individual contributors. + * + * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA + * is licensed to you under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * JBoss DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.jboss.dna.connector.meta.jdbc; + + +import org.jboss.dna.common.AbstractI18nTest; + +public class JdbcMetadataI18nTest extends AbstractI18nTest { + + public JdbcMetadataI18nTest() { + super(JdbcMetadataI18nTest.class); + } +} Property changes on: extensions\dna-connector-jdbc-metadata\src\test\java\org\jboss\dna\connector\meta\jdbc\JdbcMetadataI18nTest.java ___________________________________________________________________ Added: svn:keywords + Id Revision Added: svn:eol-style + LF Index: extensions/dna-connector-jdbc-metadata/src/test/java/org/jboss/dna/connector/meta/jdbc/JdbcMetadataRepositoryTest.java =================================================================== --- extensions/dna-connector-jdbc-metadata/src/test/java/org/jboss/dna/connector/meta/jdbc/JdbcMetadataRepositoryTest.java (revision 0) +++ extensions/dna-connector-jdbc-metadata/src/test/java/org/jboss/dna/connector/meta/jdbc/JdbcMetadataRepositoryTest.java (revision 0) @@ -0,0 +1,487 @@ +/* + * JBoss DNA (http://www.jboss.org/dna) + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. Some portions may be licensed + * to Red Hat, Inc. under one or more contributor license agreements. + * See the AUTHORS.txt file in the distribution for a full listing of + * individual contributors. + * + * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA + * is licensed to you under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * JBoss DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.jboss.dna.connector.meta.jdbc; + +import static org.hamcrest.core.Is.is; +import static org.hamcrest.core.IsNull.notNullValue; +import static org.hamcrest.core.IsNull.nullValue; +import static org.junit.Assert.assertThat; +import static org.mockito.Mockito.stub; +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.ResultSet; +import java.sql.Types; +import java.util.Map; +import java.util.Set; +import javax.sql.DataSource; +import org.jboss.dna.graph.DnaLexicon; +import org.jboss.dna.graph.ExecutionContext; +import org.jboss.dna.graph.JcrLexicon; +import org.jboss.dna.graph.JcrNtLexicon; +import org.jboss.dna.graph.connector.RepositoryContext; +import org.jboss.dna.graph.connector.path.PathNode; +import org.jboss.dna.graph.connector.path.PathWorkspace; +import org.jboss.dna.graph.property.Name; +import org.jboss.dna.graph.property.NameFactory; +import org.jboss.dna.graph.property.Path; +import org.jboss.dna.graph.property.PathFactory; +import org.jboss.dna.graph.property.Property; +import org.jboss.dna.graph.property.ValueFactory; +import org.jboss.dna.graph.property.Path.Segment; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.mockito.MockitoAnnotations; +import org.mockito.MockitoAnnotations.Mock; + +public class JdbcMetadataRepositoryTest { + + private JdbcMetadataSource source; + @Mock + private RepositoryContext repositoryContext; + private ExecutionContext context; + private JdbcMetadataRepository repository; + private PathWorkspace workspace; + private PathFactory pathFactory; + private NameFactory nameFactory; + private ValueFactory longFactory; + private ValueFactory stringFactory; + + /* + * The catalog in schema into which the test DDL was loaded + */ + private String loadedCatalogName; + private String loadedSchemaName; + + @Before + public void beforeEach() throws Exception { + MockitoAnnotations.initMocks(this); + + context = new ExecutionContext(); + pathFactory = context.getValueFactories().getPathFactory(); + nameFactory = context.getValueFactories().getNameFactory(); + longFactory = context.getValueFactories().getLongFactory(); + stringFactory = context.getValueFactories().getStringFactory(); + + stub(repositoryContext.getExecutionContext()).toReturn(context); + + // Set the connection properties using the environment defined in the POM files ... + this.source = TestEnvironment.configureJdbcMetadataSource("Test Repository", this); + this.source.initialize(repositoryContext); + + source.getConnection().close(); // Need to call this once to instantiate the repository + this.repository = source.repository(); + workspace = repository.getWorkspace(source.getDefaultWorkspaceName()); + assertThat(workspace, is(notNullValue())); + + TestEnvironment.executeDdl(this.source.getDataSource(), "/create.ddl"); + + DataSource dataSource = source.getDataSource(); + Connection conn = dataSource.getConnection(); + DatabaseMetaData dmd = conn.getMetaData(); + + // Look up one of the tables that was just loaded to figure out which catalog and schema it's in + ResultSet rs = dmd.getTables(null, null, "DISTRICT", null); + + try { + if (!rs.next()) { + throw new IllegalStateException("Table creation failed -- Can't determine which catalog and schema to use"); + } + + loadedCatalogName = rs.getString("TABLE_CAT"); + if (rs.wasNull()) loadedCatalogName = null; + + loadedSchemaName = rs.getString("TABLE_SCHEM"); + if (rs.wasNull()) loadedSchemaName = null; + + if (rs.next()) { + throw new IllegalStateException( + "There is more than one table named DISTRICT in this database -- Can't determine which catalog and schema to use"); + } + } finally { + rs.close(); + conn.close(); + } + + } + + @After + public void afterEach() throws Exception { + TestEnvironment.executeDdl(this.source.getDataSource(), "/drop.ddl"); + + this.source.close(); + } + + @Test + public void shouldOnlyHaveDefaultWorkspace() { + Set workspaceNames = repository.getWorkspaceNames(); + + assertThat(workspaceNames, is(notNullValue())); + assertThat(workspaceNames.size(), is(1)); + assertThat(workspaceNames.iterator().next(), is(source.getDefaultWorkspaceName())); + + } + + @Test + public void shouldNotReturnInvalidWorkspace() { + workspace = repository.getWorkspace(source.getDefaultWorkspaceName() + "Invalid"); + assertThat(workspace, is(nullValue())); + } + + @Test + public void shouldReturnRootNode() { + Path rootPath = pathFactory.createRootPath(); + PathNode rootNode = workspace.getNode(rootPath); + Map properties = rootNode.getProperties(); + + assertThat(rootNode.getPath(), is(rootPath)); + assertThat(properties, is(notNullValue())); + assertThat(properties.size(), is(6)); + assertThat(nameFor(properties.get(JcrLexicon.PRIMARY_TYPE)), is(DnaLexicon.ROOT)); + assertThat(nameFor(properties.get(JcrLexicon.MIXIN_TYPES)), is(JdbcMetadataLexicon.DATABASE_ROOT)); + assertThat(properties.get(JdbcMetadataLexicon.DATABASE_PRODUCT_NAME), is(notNullValue())); + assertThat(properties.get(JdbcMetadataLexicon.DATABASE_PRODUCT_VERSION), is(notNullValue())); + assertThat(properties.get(JdbcMetadataLexicon.DATABASE_MAJOR_VERSION), is(notNullValue())); + assertThat(properties.get(JdbcMetadataLexicon.DATABASE_MINOR_VERSION), is(notNullValue())); + + assertThat(rootNode.getChildSegments().isEmpty(), is(false)); + } + + @Test + public void shouldReturnCatalogNode() { + Path rootPath = pathFactory.createRootPath(); + PathNode rootNode = workspace.getNode(rootPath); + + Segment catalogSegment = rootNode.getChildSegments().get(0); + Path catalogPath = pathFactory.createAbsolutePath(catalogSegment); + PathNode catalogNode = workspace.getNode(catalogPath); + + Map properties = catalogNode.getProperties(); + + assertThat(catalogNode.getPath(), is(catalogPath)); + assertThat(properties, is(notNullValue())); + assertThat(properties.size(), is(2)); + assertThat(nameFor(properties.get(JcrLexicon.PRIMARY_TYPE)), is(JcrNtLexicon.UNSTRUCTURED)); + assertThat(nameFor(properties.get(JcrLexicon.MIXIN_TYPES)), is(JdbcMetadataLexicon.CATALOG)); + + assertThat(rootNode.getChildSegments().isEmpty(), is(false)); + } + + @Test + public void shouldNotReturnInvalidCatalogNode() { + Path rootPath = pathFactory.createRootPath(); + PathNode rootNode = workspace.getNode(rootPath); + Segment catalogSegment = rootNode.getChildSegments().get(0); + + Name invalidCatalogName = nameFactory.create(catalogSegment.getName().getLocalName() + "-InvalidCatalog"); + Path catalogPath = pathFactory.createAbsolutePath(invalidCatalogName); + assertThat(workspace.getNode(catalogPath), is(nullValue())); + } + + @Test + public void shouldReturnSchemaNode() { + Path rootPath = pathFactory.createRootPath(); + PathNode rootNode = workspace.getNode(rootPath); + + Segment catalogSegment = rootNode.getChildSegments().get(0); + Path catalogPath = pathFactory.createAbsolutePath(catalogSegment); + PathNode catalogNode = workspace.getNode(catalogPath); + + Segment schemaSegment = catalogNode.getChildSegments().get(0); + Path schemaPath = pathFactory.createAbsolutePath(catalogSegment, schemaSegment); + PathNode schemaNode = workspace.getNode(schemaPath); + + Map properties = schemaNode.getProperties(); + + assertThat(schemaNode.getPath(), is(schemaPath)); + assertThat(properties, is(notNullValue())); + assertThat(properties.size(), is(2)); + assertThat(nameFor(properties.get(JcrLexicon.PRIMARY_TYPE)), is(JcrNtLexicon.UNSTRUCTURED)); + assertThat(nameFor(properties.get(JcrLexicon.MIXIN_TYPES)), is(JdbcMetadataLexicon.SCHEMA)); + + assertThat(rootNode.getChildSegments().isEmpty(), is(false)); + } + + @Test + public void shouldNotReturnInvalidSchemaNode() { + Path rootPath = pathFactory.createRootPath(); + PathNode rootNode = workspace.getNode(rootPath); + + Segment catalogSegment = rootNode.getChildSegments().get(0); + Path catalogPath = pathFactory.createAbsolutePath(catalogSegment); + PathNode catalogNode = workspace.getNode(catalogPath); + + Segment schemaSegment = catalogNode.getChildSegments().get(0); + Name invalidSchemaName = nameFactory.create(schemaSegment.getName().getLocalName() + "-InvalidSchema"); + Path invalidSchemaPath = pathFactory.createAbsolutePath(catalogSegment.getName(), invalidSchemaName); + assertThat(workspace.getNode(invalidSchemaPath), is(nullValue())); + + } + + @Test + public void shouldReturnTablesNode() { + String nullSafeCatalogName = loadedCatalogName == null ? source.getDefaultCatalogName() : loadedCatalogName; + String nullSafeSchemaName = loadedSchemaName == null ? source.getDefaultSchemaName() : loadedSchemaName; + + Path tablesPath = pathFactory.createAbsolutePath(pathFactory.createSegment(nullSafeCatalogName), + pathFactory.createSegment(nullSafeSchemaName), + pathFactory.createSegment(JdbcMetadataRepository.TABLES_SEGMENT_NAME)); + PathNode tablesNode = workspace.getNode(tablesPath); + + Map properties = tablesNode.getProperties(); + + assertThat(tablesNode.getPath(), is(tablesPath)); + assertThat(properties, is(notNullValue())); + assertThat(properties.size(), is(2)); + assertThat(nameFor(properties.get(JcrLexicon.PRIMARY_TYPE)), is(JcrNtLexicon.UNSTRUCTURED)); + assertThat(nameFor(properties.get(JcrLexicon.MIXIN_TYPES)), is(JdbcMetadataLexicon.TABLES)); + + assertThat(tablesNode.getChildSegments().isEmpty(), is(false)); + } + + @Test + public void shouldNotReturnTablesNodeForInvalidSchema() { + Path rootPath = pathFactory.createRootPath(); + PathNode rootNode = workspace.getNode(rootPath); + + Segment catalogSegment = rootNode.getChildSegments().get(0); + Path catalogPath = pathFactory.createAbsolutePath(catalogSegment); + PathNode catalogNode = workspace.getNode(catalogPath); + + Segment schemaSegment = catalogNode.getChildSegments().get(0); + Name invalidSchemaName = nameFactory.create(schemaSegment.getName().getLocalName() + "-InvalidSchema"); + Path invalidSchemaPath = pathFactory.createAbsolutePath(catalogSegment.getName(), + invalidSchemaName, + nameFactory.create(JdbcMetadataRepository.TABLES_SEGMENT_NAME)); + assertThat(workspace.getNode(invalidSchemaPath), is(nullValue())); + } + + @Test + public void shouldReturnTableNode() { + String nullSafeCatalogName = loadedCatalogName == null ? source.getDefaultCatalogName() : loadedCatalogName; + String nullSafeSchemaName = loadedSchemaName == null ? source.getDefaultSchemaName() : loadedSchemaName; + + Path tablePath = pathFactory.createAbsolutePath(pathFactory.createSegment(nullSafeCatalogName), + pathFactory.createSegment(nullSafeSchemaName), + pathFactory.createSegment(JdbcMetadataRepository.TABLES_SEGMENT_NAME), + pathFactory.createSegment("SALES")); + PathNode tableNode = workspace.getNode(tablePath); + + Map properties = tableNode.getProperties(); + + assertThat(tableNode.getPath(), is(tablePath)); + assertThat(properties, is(notNullValue())); + assertThat(properties.size() >= 2, is(true)); + assertThat(properties.size() <= 9, is(true)); + assertThat(nameFor(properties.get(JcrLexicon.PRIMARY_TYPE)), is(JcrNtLexicon.UNSTRUCTURED)); + assertThat(nameFor(properties.get(JcrLexicon.MIXIN_TYPES)), is(JdbcMetadataLexicon.TABLE)); + + assertThat(tableNode.getChildSegments().size(), is(4)); + } + + @Test + public void shouldNotReturnTableNodeForInvalidSchema() { + Path rootPath = pathFactory.createRootPath(); + PathNode rootNode = workspace.getNode(rootPath); + + Segment catalogSegment = rootNode.getChildSegments().get(0); + Path catalogPath = pathFactory.createAbsolutePath(catalogSegment); + PathNode catalogNode = workspace.getNode(catalogPath); + + Segment schemaSegment = catalogNode.getChildSegments().get(0); + Name invalidSchemaName = nameFactory.create(schemaSegment.getName().getLocalName() + "-InvalidSchema"); + Path invalidSchemaPath = pathFactory.createAbsolutePath(catalogSegment.getName(), + invalidSchemaName, + nameFactory.create(JdbcMetadataRepository.TABLES_SEGMENT_NAME), + nameFactory.create("SALES")); + assertThat(workspace.getNode(invalidSchemaPath), is(nullValue())); + } + + @Test + public void shouldNotReturnInvalidTableNode() { + String nullSafeCatalogName = loadedCatalogName == null ? source.getDefaultCatalogName() : loadedCatalogName; + String nullSafeSchemaName = loadedSchemaName == null ? source.getDefaultSchemaName() : loadedSchemaName; + + Path invalidTablePath = pathFactory.createAbsolutePath(pathFactory.createSegment(nullSafeCatalogName), + pathFactory.createSegment(nullSafeSchemaName), + pathFactory.createSegment(JdbcMetadataRepository.TABLES_SEGMENT_NAME), + pathFactory.createSegment("NOT_A_VALID_TABLE")); + + assertThat(workspace.getNode(invalidTablePath), is(nullValue())); + } + + @Test + public void shouldReturnColumnNode() { + String nullSafeCatalogName = loadedCatalogName == null ? source.getDefaultCatalogName() : loadedCatalogName; + String nullSafeSchemaName = loadedSchemaName == null ? source.getDefaultSchemaName() : loadedSchemaName; + + Path columnPath = pathFactory.createAbsolutePath(pathFactory.createSegment(nullSafeCatalogName), + pathFactory.createSegment(nullSafeSchemaName), + pathFactory.createSegment(JdbcMetadataRepository.TABLES_SEGMENT_NAME), + pathFactory.createSegment("SALES"), + pathFactory.createSegment("AMOUNT")); + PathNode columnNode = workspace.getNode(columnPath); + + Map properties = columnNode.getProperties(); + + assertThat(columnNode.getPath(), is(columnPath)); + assertThat(properties, is(notNullValue())); + assertThat(properties.size() >= 9, is(true)); + assertThat(properties.size() <= 16, is(true)); + assertThat(nameFor(properties.get(JcrLexicon.PRIMARY_TYPE)), is(JcrNtLexicon.UNSTRUCTURED)); + assertThat(nameFor(properties.get(JcrLexicon.MIXIN_TYPES)), is(JdbcMetadataLexicon.COLUMN)); + + assertThat(longFor(properties.get(JdbcMetadataLexicon.JDBC_DATA_TYPE)), is((long)Types.NUMERIC)); + assertThat(stringFor(properties.get(JdbcMetadataLexicon.TYPE_NAME)), is(notNullValue())); + assertThat(longFor(properties.get(JdbcMetadataLexicon.COLUMN_SIZE)), is(notNullValue())); + assertThat(longFor(properties.get(JdbcMetadataLexicon.DECIMAL_DIGITS)), is(notNullValue())); + assertThat(longFor(properties.get(JdbcMetadataLexicon.RADIX)), is(notNullValue())); + assertThat(longFor(properties.get(JdbcMetadataLexicon.LENGTH)), is(notNullValue())); + assertThat(longFor(properties.get(JdbcMetadataLexicon.ORDINAL_POSITION)), is(4L)); + + assertThat(columnNode.getChildSegments().isEmpty(), is(true)); + } + + @Test + public void shouldNotReturnColumnNodeForInvalidSchema() { + Path rootPath = pathFactory.createRootPath(); + PathNode rootNode = workspace.getNode(rootPath); + + Segment catalogSegment = rootNode.getChildSegments().get(0); + Path catalogPath = pathFactory.createAbsolutePath(catalogSegment); + PathNode catalogNode = workspace.getNode(catalogPath); + + Segment schemaSegment = catalogNode.getChildSegments().get(0); + Name invalidSchemaName = nameFactory.create(schemaSegment.getName().getLocalName() + "-InvalidSchema"); + Path invalidSchemaPath = pathFactory.createAbsolutePath(catalogSegment.getName(), + invalidSchemaName, + nameFactory.create(JdbcMetadataRepository.TABLES_SEGMENT_NAME), + nameFactory.create("SALES"), + nameFactory.create("AMOUNT")); + assertThat(workspace.getNode(invalidSchemaPath), is(nullValue())); + } + + @Test + public void shouldNotReturnColumnNodeForInvalidTable() { + String nullSafeCatalogName = loadedCatalogName == null ? source.getDefaultCatalogName() : loadedCatalogName; + String nullSafeSchemaName = loadedSchemaName == null ? source.getDefaultSchemaName() : loadedSchemaName; + + Path invalidTablePath = pathFactory.createAbsolutePath(pathFactory.createSegment(nullSafeCatalogName), + pathFactory.createSegment(nullSafeSchemaName), + pathFactory.createSegment(JdbcMetadataRepository.TABLES_SEGMENT_NAME), + pathFactory.createSegment("INVALID_TABLE_NAME"), + pathFactory.createSegment("ID")); + + assertThat(workspace.getNode(invalidTablePath), is(nullValue())); + } + + @Test + public void shouldNotReturnInvalidColumnNode() { + String nullSafeCatalogName = loadedCatalogName == null ? source.getDefaultCatalogName() : loadedCatalogName; + String nullSafeSchemaName = loadedSchemaName == null ? source.getDefaultSchemaName() : loadedSchemaName; + + Path invalidColumnPath = pathFactory.createAbsolutePath(pathFactory.createSegment(nullSafeCatalogName), + pathFactory.createSegment(nullSafeSchemaName), + pathFactory.createSegment(JdbcMetadataRepository.TABLES_SEGMENT_NAME), + pathFactory.createSegment("SALES"), + pathFactory.createSegment("INVALID_COLUMN_NAME")); + + assertThat(workspace.getNode(invalidColumnPath), is(nullValue())); + } + + @Test + public void shouldReturnProceduresNode() { + String nullSafeCatalogName = loadedCatalogName == null ? source.getDefaultCatalogName() : loadedCatalogName; + String nullSafeSchemaName = loadedSchemaName == null ? source.getDefaultSchemaName() : loadedSchemaName; + + Path tablesPath = pathFactory.createAbsolutePath(pathFactory.createSegment(nullSafeCatalogName), + pathFactory.createSegment(nullSafeSchemaName), + pathFactory.createSegment(JdbcMetadataRepository.PROCEDURES_SEGMENT_NAME)); + PathNode tablesNode = workspace.getNode(tablesPath); + + Map properties = tablesNode.getProperties(); + + assertThat(tablesNode.getPath(), is(tablesPath)); + assertThat(properties, is(notNullValue())); + assertThat(properties.size(), is(2)); + assertThat(nameFor(properties.get(JcrLexicon.PRIMARY_TYPE)), is(JcrNtLexicon.UNSTRUCTURED)); + assertThat(nameFor(properties.get(JcrLexicon.MIXIN_TYPES)), is(JdbcMetadataLexicon.PROCEDURES)); + + assertThat(tablesNode.getChildSegments().isEmpty(), is(false)); + } + + @Test + public void shouldNotReturnProceduresNodeForInvalidSchema() { + Path rootPath = pathFactory.createRootPath(); + PathNode rootNode = workspace.getNode(rootPath); + + Segment catalogSegment = rootNode.getChildSegments().get(0); + Path catalogPath = pathFactory.createAbsolutePath(catalogSegment); + PathNode catalogNode = workspace.getNode(catalogPath); + + Segment schemaSegment = catalogNode.getChildSegments().get(0); + Name invalidSchemaName = nameFactory.create(schemaSegment.getName().getLocalName() + "-InvalidSchema"); + Path invalidSchemaPath = pathFactory.createAbsolutePath(catalogSegment.getName(), + invalidSchemaName, + nameFactory.create(JdbcMetadataRepository.PROCEDURES_SEGMENT_NAME)); + assertThat(workspace.getNode(invalidSchemaPath), is(nullValue())); + } + + private Name nameFor( Property property ) { + if (property == null) { + return null; + } + + if (property.isEmpty()) { + return null; + } + + return nameFactory.create(property.getFirstValue()); + } + + private Long longFor( Property property ) { + if (property == null) { + return null; + } + + if (property.isEmpty()) { + return null; + } + + return longFactory.create(property.getFirstValue()); + } + + private String stringFor( Property property ) { + if (property == null) { + return null; + } + + if (property.isEmpty()) { + return null; + } + + return stringFactory.create(property.getFirstValue()); + } + +} Property changes on: extensions\dna-connector-jdbc-metadata\src\test\java\org\jboss\dna\connector\meta\jdbc\JdbcMetadataRepositoryTest.java ___________________________________________________________________ Added: svn:keywords + Id Revision Added: svn:eol-style + LF Index: extensions/dna-connector-jdbc-metadata/src/test/java/org/jboss/dna/connector/meta/jdbc/JdbcMetadataSourceTest.java =================================================================== --- extensions/dna-connector-jdbc-metadata/src/test/java/org/jboss/dna/connector/meta/jdbc/JdbcMetadataSourceTest.java (revision 0) +++ extensions/dna-connector-jdbc-metadata/src/test/java/org/jboss/dna/connector/meta/jdbc/JdbcMetadataSourceTest.java (revision 0) @@ -0,0 +1,102 @@ +/* + * JBoss DNA (http://www.jboss.org/dna) + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. Some portions may be licensed + * to Red Hat, Inc. under one or more contributor license agreements. + * See the AUTHORS.txt file in the distribution for a full listing of + * individual contributors. + * + * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA + * is licensed to you under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * JBoss DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.jboss.dna.connector.meta.jdbc; + +import static org.hamcrest.core.Is.is; +import static org.hamcrest.core.IsNull.notNullValue; +import static org.junit.Assert.assertThat; +import static org.mockito.Mockito.stub; +import java.util.ArrayList; +import java.util.List; +import org.jboss.dna.graph.ExecutionContext; +import org.jboss.dna.graph.connector.RepositoryConnection; +import org.jboss.dna.graph.connector.RepositoryContext; +import org.jboss.dna.graph.connector.RepositorySourceException; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.mockito.MockitoAnnotations; +import org.mockito.MockitoAnnotations.Mock; + +public class JdbcMetadataSourceTest { + + private JdbcMetadataSource source; + private RepositoryConnection connection; + @Mock + private RepositoryContext repositoryContext; + + @Before + public void beforeEach() throws Exception { + MockitoAnnotations.initMocks(this); + + stub(repositoryContext.getExecutionContext()).toReturn(new ExecutionContext()); + + // Set the connection properties using the environment defined in the POM files ... + this.source = TestEnvironment.configureJdbcMetadataSource("Test Repository", this); + this.source.initialize(repositoryContext); + } + + @After + public void afterEach() throws Exception { + if (this.connection != null) { + this.connection.close(); + } + } + + @Test( expected = RepositorySourceException.class ) + public void shouldFailToCreateConnectionIfSourceHasNoName() { + source.setName(null); + source.getConnection(); + } + + @Test + public void shouldCreateConnection() throws Exception { + connection = source.getConnection(); + assertThat(connection, is(notNullValue())); + } + + @Test + public void shouldAllowMultipleConnectionsToBeOpenAtTheSameTime() throws Exception { + List connections = new ArrayList(); + try { + for (int i = 0; i != 10; ++i) { + RepositoryConnection conn = source.getConnection(); + assertThat(conn, is(notNullValue())); + connections.add(conn); + } + } finally { + // Close all open connections ... + for (RepositoryConnection conn : connections) { + if (conn != null) { + try { + conn.close(); + } catch (Throwable t) { + t.printStackTrace(); + } + } + } + } + } + +} Property changes on: extensions\dna-connector-jdbc-metadata\src\test\java\org\jboss\dna\connector\meta\jdbc\JdbcMetadataSourceTest.java ___________________________________________________________________ Added: svn:keywords + Id Revision Added: svn:eol-style + LF Index: extensions/dna-connector-jdbc-metadata/src/test/java/org/jboss/dna/connector/meta/jdbc/TestEnvironment.java =================================================================== --- extensions/dna-connector-jdbc-metadata/src/test/java/org/jboss/dna/connector/meta/jdbc/TestEnvironment.java (revision 0) +++ extensions/dna-connector-jdbc-metadata/src/test/java/org/jboss/dna/connector/meta/jdbc/TestEnvironment.java (revision 0) @@ -0,0 +1,128 @@ +/* + * JBoss DNA (http://www.jboss.org/dna) + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. Some portions may be licensed + * to Red Hat, Inc. under one or more contributor license agreements. + * See the AUTHORS.txt file in the distribution for a full listing of + * individual contributors. + * + * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA + * is licensed to you under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * JBoss DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.jboss.dna.connector.meta.jdbc; + +import java.io.IOException; +import java.io.InputStream; +import java.sql.Connection; +import java.sql.Statement; +import java.util.Properties; +import javax.sql.DataSource; +import org.jboss.dna.common.util.IoUtil; +import org.jboss.dna.connector.meta.jdbc.JdbcMetadataSource; + +public class TestEnvironment { + + public static JdbcMetadataSource configureJdbcMetadataSource( String sourceName, + Object testCase ) { + Properties properties = new Properties(); + ClassLoader loader = testCase instanceof Class ? ((Class)testCase).getClassLoader() : testCase.getClass().getClassLoader(); + try { + properties.load(loader.getResourceAsStream("database.properties")); + } catch (IOException e) { + throw new RuntimeException(e); + } + + JdbcMetadataSource source = new JdbcMetadataSource(); + source.setName(sourceName); + source.setDriverClassName(properties.getProperty("jpaSource.driverClassName")); + source.setUsername(properties.getProperty("jpaSource.username")); + source.setPassword(properties.getProperty("jpaSource.password")); + source.setUrl(properties.getProperty("jpaSource.url")); + + String value = properties.getProperty("jpaSource.maximumConnectionsInPool"); + if (isValue(value)) source.setMaximumConnectionsInPool(Integer.parseInt(value)); + + value = properties.getProperty("jpaSource.minimumConnectionsInPool"); + if (isValue(value)) source.setMinimumConnectionsInPool(Integer.parseInt(value)); + + value = properties.getProperty("jpaSource.maximumSizeOfStatementCache"); + if (isValue(value)) source.setMaximumSizeOfStatementCache(Integer.parseInt(value)); + + value = properties.getProperty("jpaSource.maximumConnectionIdleTimeInSeconds"); + if (isValue(value)) source.setMaximumConnectionIdleTimeInSeconds(Integer.parseInt(value)); + + value = properties.getProperty("jpaSource.cacheTimeToLiveInMilliseconds"); + if (isValue(value)) source.setCacheTimeToLiveInMilliseconds(Integer.parseInt(value)); + + value = properties.getProperty("jpaSource.defaultWorkspaceName"); + if (isValue(value)) source.setDefaultWorkspaceName(value); + + value = properties.getProperty("jpaSource.numberOfConnectionsToAcquireAsNeeded"); + if (isValue(value)) source.setNumberOfConnectionsToAcquireAsNeeded(Integer.parseInt(value)); + + value = properties.getProperty("jpaSource.retryLimit"); + if (isValue(value)) source.setRetryLimit(Integer.parseInt(value)); + + value = properties.getProperty("jpaSource.rootNodeUuid"); + if (isValue(value)) source.setRootNodeUuid(value); + + return source; + } + + protected static boolean isValue( String value ) { + return value != null && value.trim().length() != 0; + } + + protected static String[] splitValues( String value ) { + String[] results = value.split(", "); + for (int i = 0; i != results.length; ++i) { + results[i] = results[i].trim(); + // Remove leading and trailing quotes, if there are any ... + results[i] = results[i].replaceFirst("^['\"]+", "").replaceAll("['\"]+$", "").trim(); + } + return results; + } + + public static void executeDdl( DataSource dataSource, + String pathToDdl ) throws Exception { + Connection conn = null; + Statement stmt = null; + InputStream is = null; + + + try { + conn = dataSource.getConnection(); + is = TestEnvironment.class.getResourceAsStream(pathToDdl); + String ddl = IoUtil.read(is); + + stmt = conn.createStatement(); + stmt.execute(ddl); + + } finally { + if (stmt != null) try { + stmt.close(); + } catch (Exception ignore) { + } + if (conn != null) try { + conn.close(); + } catch (Exception ignore) { + } + if (is != null) try { + is.close(); + } catch (Exception ignore) { + } + } + } +} Property changes on: extensions\dna-connector-jdbc-metadata\src\test\java\org\jboss\dna\connector\meta\jdbc\TestEnvironment.java ___________________________________________________________________ Added: svn:keywords + Id Revision Added: svn:eol-style + LF Index: extensions/dna-connector-jdbc-metadata/src/test/resources/create.ddl =================================================================== --- extensions/dna-connector-jdbc-metadata/src/test/resources/create.ddl (revision 0) +++ extensions/dna-connector-jdbc-metadata/src/test/resources/create.ddl (revision 0) @@ -0,0 +1,33 @@ +-- JBoss DNA (http://www.jboss.org/dna) +-- See the COPYRIGHT.txt file distributed with this work for information +-- regarding copyright ownership. Some portions may be licensed +-- to Red Hat, Inc. under one or more contributor license agreements. +-- See the AUTHORS.txt file in the distribution for a full listing of +-- individual contributors. +-- +-- JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA +-- is licensed to you under the terms of the GNU Lesser General Public License as +-- published by the Free Software Foundation; either version 2.1 of +-- the License, or (at your option) any later version. +-- +-- JBoss DNA is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +-- Lesser General Public License for more details. +-- +-- You should have received a copy of the GNU Lesser General Public +-- License along with this software; if not, write to the Free +-- Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +-- 02110-1301 USA, or see the FSF site: http://www.fsf.org. + +CREATE TABLE CHAIN (ID NUMERIC NOT NULL PRIMARY KEY, NAME VARCHAR(30) NOT NULL) +CREATE TABLE AREA (ID NUMERIC NOT NULL PRIMARY KEY, NAME VARCHAR(30) NOT NULL, CHAIN_ID NUMERIC NOT NULL) +CREATE TABLE REGION (ID NUMERIC NOT NULL PRIMARY KEY, NAME VARCHAR(30) NOT NULL, AREA_ID NUMERIC NOT NULL) +CREATE TABLE DISTRICT (ID NUMERIC NOT NULL PRIMARY KEY, NAME VARCHAR(30) NOT NULL, REGION_ID NUMERIC NOT NULL) + +CREATE TABLE SALES (ID NUMERIC NOT NULL, SALES_DATE DATETIME NOT NULL, DISTRICT_ID NUMERIC NOT NULL, AMOUNT NUMERIC(10, 2) NULL) +ALTER TABLE SALES ADD CONSTRAINT PK_SALES PRIMARY KEY (ID, SALES_DATE) + +ALTER TABLE AREA ADD CONSTRAINT FK_CHAIN FOREIGN KEY(CHAIN_ID) REFERENCES CHAIN(ID) ON DELETE CASCADE +ALTER TABLE REGION ADD CONSTRAINT FK_AREA FOREIGN KEY(AREA_ID) REFERENCES AREA(ID) ON DELETE CASCADE +ALTER TABLE DISTRICT ADD CONSTRAINT FK_REGION FOREIGN KEY(REGION_ID) REFERENCES REGION(ID) ON DELETE CASCADE Index: extensions/dna-connector-jdbc-metadata/src/test/resources/database.properties =================================================================== --- extensions/dna-connector-jdbc-metadata/src/test/resources/database.properties (revision 0) +++ extensions/dna-connector-jdbc-metadata/src/test/resources/database.properties (revision 0) @@ -0,0 +1,42 @@ +# +# JBoss DNA (http://www.jboss.org/dna) +# See the COPYRIGHT.txt file distributed with this work for information +# regarding copyright ownership. Some portions may be licensed +# to Red Hat, Inc. under one or more contributor license agreements. +# See the AUTHORS.txt file in the distribution for a full listing of +# individual contributors. +# +# JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA +# is licensed to you under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation; either version 2.1 of +# the License, or (at your option) any later version. +# +# JBoss DNA is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this software; if not, write to the Free +# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA, or see the FSF site: http://www.fsf.org. +# + +# All of these properties are or can be set in the parent POM in the different profiles. +# The property names are designed to match those used in the POM. +# Any property that does not have a non-empty value set by Maven will not be set on the JpaSource. +jpaSource.driverClassName = ${jpaSource.driverClassName} +jpaSource.url = ${jpaSource.url} +jpaSource.username = ${jpaSource.username} +jpaSource.password = ${jpaSource.password} +jpaSource.maximumConnectionsInPool = ${jpaSource.maximumConnectionsInPool} +jpaSource.minimumConnectionsInPool = ${jpaSource.minimumConnectionsInPool} +jpaSource.numberOfConnectionsToAcquireAsNeeded = ${jpaSource.numberOfConnectionsToAcquireAsNeeded} +jpaSource.maximumSizeOfStatementCache = ${jpaSource.maximumSizeOfStatementCache} +jpaSource.maximumConnectionIdleTimeInSeconds = ${jpaSource.maximumConnectionIdleTimeInSeconds} +jpaSource.cacheTimeToLiveInMilliseconds = ${jpaSource.cacheTimeToLiveInMilliseconds} +jpaSource.defaultWorkspaceName = ${jpaSource.defaultWorkspaceName} +jpaSource.numberOfConnectionsToAcquireAsNeeded = ${jpaSource.numberOfConnectionsToAcquireAsNeeded} +jpaSource.retryLimit = ${jpaSource.retryLimit} +jpaSource.rootNodeUuid = ${jpaSource.rootNodeUuid} + Index: extensions/dna-connector-jdbc-metadata/src/test/resources/drop.ddl =================================================================== --- extensions/dna-connector-jdbc-metadata/src/test/resources/drop.ddl (revision 0) +++ extensions/dna-connector-jdbc-metadata/src/test/resources/drop.ddl (revision 0) @@ -0,0 +1,27 @@ +-- JBoss DNA (http://www.jboss.org/dna) +-- See the COPYRIGHT.txt file distributed with this work for information +-- regarding copyright ownership. Some portions may be licensed +-- to Red Hat, Inc. under one or more contributor license agreements. +-- See the AUTHORS.txt file in the distribution for a full listing of +-- individual contributors. +-- +-- JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA +-- is licensed to you under the terms of the GNU Lesser General Public License as +-- published by the Free Software Foundation; either version 2.1 of +-- the License, or (at your option) any later version. +-- +-- JBoss DNA is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +-- Lesser General Public License for more details. +-- +-- You should have received a copy of the GNU Lesser General Public +-- License along with this software; if not, write to the Free +-- Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +-- 02110-1301 USA, or see the FSF site: http://www.fsf.org. + +DROP TABLE SALES +DROP TABLE DISTRICT +DROP TABLE REGION +DROP TABLE AREA +DROP TABLE CHAIN