Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.github.jinahya.sql.database.metadata.bind.MetadataContext Maven / Gradle / Ivy
/*
* Copyright 2015 Jin Kwon <jinahya_at_gmail.com>.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.github.jinahya.sql.database.metadata.bind;
import static java.beans.Introspector.decapitalize;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import java.util.logging.Level;
import java.util.logging.Logger;
import static java.util.logging.Logger.getLogger;
/**
* A context class for retrieving information from an instance of
* {@link java.sql.DatabaseMetaData}.
*
* @author Jin Kwon <jinahya_at_gmail.com>
*/
public class MetadataContext {
private static final Logger logger = getLogger(Metadata.class.getName());
private static String suppression(
final Class> beanClass, final Field beanField) {
return decapitalize(beanClass.getSimpleName()) + "/"
+ beanField.getName();
}
/**
* Creates a new instance with given {@code DatabaseMetaData}.
*
* @param database the {@code DatabaseMetaData} instance to hold.
*/
public MetadataContext(final DatabaseMetaData database) {
super();
if (database == null) {
throw new NullPointerException("null database");
}
this.database = database;
}
private boolean addSuppression(final String suppression) {
if (suppression == null) {
throw new NullPointerException("null suppression");
}
if (suppressions == null) {
suppressions = new TreeSet();
}
return suppressions.add(suppression);
}
/**
* Add suppression paths.
*
* @param suppression the first suppression
* @param otherSuppressions other suppressions
*
* @return this
*/
public MetadataContext addSuppressions(
final String suppression, final String... otherSuppressions) {
addSuppression(suppression);
if (otherSuppressions != null) {
for (final String otherSuppression : otherSuppressions) {
addSuppression(otherSuppression);
}
}
return this;
}
private boolean suppressed(final String suppression) {
if (suppression == null) {
throw new NullPointerException("null suppression");
}
if (suppressions == null) {
return false;
}
return suppressions.contains(suppression);
}
private void setValue(final Field field, final Object bean,
final Object value, final Object[] args)
throws ReflectiveOperationException, SQLException {
final Class> fieldType = field.getType();
if (fieldType == List.class) {
if (value == null) {
return;
}
if (!field.isAccessible()) {
field.setAccessible(true);
}
// @SuppressWarnings("unchecked")
// List list = (List) field.get(bean);
// if (list == null) {
// list = new ArrayList();
// field.set(bean, list);
// }
@SuppressWarnings("unchecked")
List list = (List) Values.get(field, bean);
if (list == null) {
list = new ArrayList();
Values.set(field, bean, list);
//field.set(bean, list);
}
final Class> type
= (Class>) ((ParameterizedType) field.getGenericType())
.getActualTypeArguments()[0];
if (ResultSet.class.isInstance(value)) {
bindAll((ResultSet) value, type, list);
// Reflections.setParent(type, list, bean);
Values.setParent(type, list, value);
return;
}
list.add(type
.getDeclaredMethod("valueOf", Object[].class, Object.class)
.invoke(null, args, value));
// Reflections.setParent(type, list, bean);
Values.setParent(type, list, value);
return;
}
Reflections.setFieldValue(field, bean, value);
}
private T bindSingle(final ResultSet resultSet,
final Class beanClass, final T beanInstance)
throws SQLException, ReflectiveOperationException {
if (resultSet != null) {
final Set resultLabels
= ResultSets.getColumnLabels(resultSet);
@SuppressWarnings("unchecked")
final List fields = Reflections.listFields(beanClass, Label.class);
for (final Field field : fields) {
final String suppression = suppression(beanClass, field);
if (suppressed(suppression)) {
continue;
}
final Label label = field.getAnnotation(Label.class);
final String labelValue = label.value();
if (!resultLabels.remove(labelValue)) {
logger.log(Level.WARNING,
"unmapped column; bean={0}, label={1}",
new Object[]{beanClass, label});
}
try {
final Object value = resultSet.getObject(labelValue);
Reflections.setFieldValue(field, beanInstance, value);
} catch (final SQLException sqle) {
logger.log(Level.SEVERE,
"failed to get value"
+ "; label=" + label
+ ", suppression=" + suppression,
sqle);
throw sqle;
} catch (final Exception e) {
logger.log(Level.SEVERE,
"failed to get value"
+ "; label=" + label
+ ", suppression=" + suppression,
e);
throw new RuntimeException(e);
}
}
if (!resultLabels.isEmpty()) {
Reflections.setUnknownResults(
beanClass, resultLabels, resultSet, beanInstance);
}
}
@SuppressWarnings("unchecked")
final List fields = Reflections.listFields(beanClass, Invocation.class);
for (final Field field : fields) {
final String suppression = suppression(beanClass, field);
if (suppressed(suppression)) {
continue;
}
final Invocation invocation = field.getAnnotation(Invocation.class);
final String name = invocation.name();
getMethodNames().remove(name);
final Class>[] types = invocation.types();
final Method method = DatabaseMetaData.class.getMethod(name, types);
for (final InvocationArgs invocationArgs : invocation.argsarr()) {
final String[] names = invocationArgs.value();
final Object[] args = Invocations.values(
beanClass, beanInstance, types, names);
try {
final Object propertyValue = method.invoke(database, args);
setValue(field, beanInstance, propertyValue, args);
} catch (final InvocationTargetException ite) {
logger.log(Level.SEVERE,
"failed to invoke"
+ "; invocation=" + invocation
+ ", suppressin=" + suppression,
ite);
throw ite;
} catch (final Exception e) {
logger.log(Level.SEVERE,
"failed to invoke"
+ "; invocation=" + invocation
+ ", suppressin=" + suppression,
e);
throw new RuntimeException(e);
} catch (final AbstractMethodError ame) {
logger.log(Level.SEVERE,
"failed to invoke"
+ "; invocation=" + invocation
+ ", suppressin=" + suppression,
ame);
throw ame;
}
}
}
if (TableDomain.class.isAssignableFrom(beanClass)) {
final List tables = ((TableDomain) beanInstance).getTables();
final List crossReferences
= getCrossReferences(tables);
((TableDomain) beanInstance).setCrossReferences(crossReferences);
}
return beanInstance;
}
private T bindSingle(final ResultSet results, final Class type)
throws SQLException, ReflectiveOperationException {
return bindSingle(results, type, type.newInstance());
}
private List super T> bindAll(final ResultSet results,
final Class type,
final List super T> list)
throws SQLException, ReflectiveOperationException {
while (results.next()) {
list.add(bindSingle(results, type, type.newInstance()));
}
return list;
}
private List super T> bindAll(final ResultSet results,
final Class type)
throws SQLException, ReflectiveOperationException {
return bindAll(results, type, new ArrayList());
}
/**
* Binds all information.
*
* @return a Metadata
*
* @throws SQLException if a database occurs.
* @throws ReflectiveOperationException if a reflection erorr occurs
*/
public Metadata getMetadata()
throws SQLException, ReflectiveOperationException {
final Metadata metadata = bindSingle(null, Metadata.class);
if (!suppressed("metadata/catalogs")) {
final List catalogs = metadata.getCatalogs();
if (catalogs.isEmpty()) {
final Catalog catalog = new Catalog();
catalog.setTableCat("");
catalog.setParent(metadata);
logger.log(Level.INFO, "adding an empty catalog: {0}",
new Object[]{catalog});
catalogs.add(catalog);
bindSingle(null, Catalog.class, catalog);
}
if (!suppressed("category/schemas")) {
for (final Catalog catalog : catalogs) {
final List schemas = catalog.getSchemas();
if (schemas.isEmpty()) {
final Schema schema = new Schema();
schema.setTableCatalog(catalog.getTableCat());
schema.setTableSchem("");
schema.setParent(catalog);
logger.log(Level.INFO, "adding an empty schema: {0}",
new Object[]{schema});
schemas.add(schema);
bindSingle(null, Schema.class, schema);
}
}
}
}
final List supportsConvert
= new ArrayList();
metadata.setSupportsConvert(supportsConvert);
supportsConvert.add(
new SDTSDTBoolean()
.fromType(null)
.toType(null)
.value(database.supportsConvert()));
final Set sqlTypes = Reflections.getSqlTypes();
for (final int fromType : sqlTypes) {
for (final int toType : sqlTypes) {
if (fromType == toType) {
// continue;
}
supportsConvert.add(
new SDTSDTBoolean()
.fromType(fromType)
.toType(toType)
.value(database.supportsConvert(fromType, toType)));
}
}
for (final String methodName : getMethodNames()) {
logger.log(Level.INFO, "method not invoked: {0}",
new Object[]{methodName});
}
return metadata;
}
public List getAttributes(final String catalog,
final String schemaPattern,
final String typeNamePattern,
final String attributeNamePattern)
throws SQLException, ReflectiveOperationException {
final List list = new ArrayList();
final ResultSet results = database.getAttributes(
catalog, schemaPattern, typeNamePattern, attributeNamePattern);
try {
bindAll(results, Attribute.class, list);
} finally {
results.close();
}
return list;
}
public List getBestRowIdentifier(
final String catalog, final String schema, final String table,
final int scope, final boolean nullable)
throws SQLException, ReflectiveOperationException {
final List list = new ArrayList();
final ResultSet results = database.getBestRowIdentifier(
catalog, schema, table, scope, nullable);
try {
bindAll(results, BestRowIdentifier.class, list);
} finally {
results.close();
}
return list;
}
public List getCatalogs()
throws SQLException, ReflectiveOperationException {
final List list = new ArrayList();
final ResultSet results = database.getCatalogs();
try {
bindAll(results, Catalog.class, list);
} finally {
results.close();
}
return list;
}
public List getClientInfoProperties()
throws SQLException, ReflectiveOperationException {
final List list
= new ArrayList();
final ResultSet results = database.getClientInfoProperties();
try {
bindAll(results, ClientInfoProperty.class, list);
} finally {
results.close();
}
return list;
}
public List getColumns(final String catalog,
final String schemaPattern,
final String tableNamePattern,
final String columnNamePattern)
throws SQLException, ReflectiveOperationException {
final List list = new ArrayList();
final ResultSet resultSet = database.getColumns(
catalog, schemaPattern, tableNamePattern, columnNamePattern);
try {
bindAll(resultSet, Column.class, list);
} finally {
resultSet.close();
}
return list;
}
public List getColumnPrivileges(
final String catalog, final String schema, final String table,
final String columnNamePattern)
throws SQLException, ReflectiveOperationException {
final List list = new ArrayList();
final ResultSet results = database.getColumnPrivileges(
catalog, schema, table, columnNamePattern);
try {
bindAll(results, ColumnPrivilege.class, list);
} finally {
results.close();
}
return list;
}
public List getCrossReferences(
final String parentCatalog, final String parentSchema,
final String parentTable,
final String foreignCatalog, final String foreignSchema,
final String foreignTable)
throws SQLException, ReflectiveOperationException {
final List list = new ArrayList();
final ResultSet results = database.getCrossReference(
parentCatalog, parentSchema, parentTable, foreignCatalog,
foreignSchema, foreignTable);
try {
bindAll(results, CrossReference.class, list);
} finally {
results.close();
}
return list;
}
public List getCrossReferences(
final Table parentTable,
final Table foreignTable)
throws SQLException, ReflectiveOperationException {
return getCrossReferences(
parentTable.getTableCat(), parentTable.getTableSchem(),
parentTable.getTableName(),
foreignTable.getTableCat(), foreignTable.getTableSchem(),
foreignTable.getTableName());
}
List getCrossReferences(final List tables)
throws SQLException, ReflectiveOperationException {
final List list = new ArrayList();
for (final Table parentTable : tables) {
for (final Table foreignTable : tables) {
list.addAll(getCrossReferences(parentTable, foreignTable));
}
}
return list;
}
public List getFunctionColumns(
final String catalog, final String schemaPattern,
final String functionNamePattern, final String columnNamePattern)
throws SQLException, ReflectiveOperationException {
final List list = new ArrayList();
final ResultSet results = database.getFunctionColumns(
catalog, schemaPattern, functionNamePattern, columnNamePattern);
try {
bindAll(results, FunctionColumn.class, list);
} finally {
results.close();
}
return list;
}
public List getFunctions(final String catalog,
final String schemaPattern,
final String functionNamePattern)
throws SQLException, ReflectiveOperationException {
final List list = new ArrayList();
final ResultSet results = database.getFunctions(
catalog, schemaPattern, functionNamePattern);
try {
bindAll(results, Function.class, list);
} finally {
results.close();
}
return list;
}
public List getExportedKeys(
final String catalog, final String schema, final String table)
throws SQLException, ReflectiveOperationException {
final List list = new ArrayList();
final ResultSet results = database.getExportedKeys(
catalog, schema, table);
try {
bindAll(results, ExportedKey.class, list);
} finally {
results.close();
}
return list;
}
public List getImportedKeys(
final String catalog, final String schema, final String table)
throws SQLException, ReflectiveOperationException {
final List list = new ArrayList();
final ResultSet results = database.getImportedKeys(
catalog, schema, table);
try {
bindAll(results, ImportedKey.class, list);
} finally {
results.close();
}
return list;
}
public List getIndexInfo(
final String catalog, final String schema, final String table,
final boolean unique, final boolean approximate)
throws SQLException, ReflectiveOperationException {
final List list = new ArrayList();
final ResultSet results = database.getIndexInfo(
catalog, schema, table, unique, approximate);
try {
bindAll(results, IndexInfo.class, list);
} finally {
results.close();
}
return list;
}
public List getPrimaryKeys(
final String catalog, final String schema, final String table)
throws SQLException, ReflectiveOperationException {
final List list = new ArrayList();
final ResultSet results = database.getPrimaryKeys(
catalog, schema, table);
try {
bindAll(results, PrimaryKey.class, list);
} finally {
results.close();
}
return list;
}
public List getProcedureColumns(
final String catalog, final String schemaPattern,
final String procedureNamePattern, final String columnNamePattern)
throws SQLException, ReflectiveOperationException {
final List list = new ArrayList();
final ResultSet results = database.getProcedureColumns(
catalog, schemaPattern, procedureNamePattern, columnNamePattern);
try {
bindAll(results, ProcedureColumn.class, list);
} finally {
results.close();
}
return list;
}
public List getProcedures(final String catalog,
final String schemaPattern,
final String procedureNamePattern)
throws SQLException, ReflectiveOperationException {
final List list = new ArrayList();
final ResultSet results = database.getProcedures(
catalog, schemaPattern, procedureNamePattern);
try {
bindAll(results, Procedure.class, list);
} finally {
results.close();
}
return list;
}
public List getPseudoColumns(final String catalog,
final String schemaPattern,
final String tableNamePattern,
final String columnNamePattern)
throws SQLException, ReflectiveOperationException {
final List list = new ArrayList();
final ResultSet results = database.getPseudoColumns(
catalog, schemaPattern, tableNamePattern, columnNamePattern);
try {
bindAll(results, PseudoColumn.class, list);
} finally {
results.close();
}
return list;
}
public List getSchemas()
throws SQLException, ReflectiveOperationException {
final List list = new ArrayList();
final ResultSet results = database.getSchemas();
try {
bindAll(results, SchemaName.class, list);
} finally {
results.close();
}
return list;
}
public List getSchemas(final String catalog,
final String schemaPattern)
throws SQLException, ReflectiveOperationException {
final List list = new ArrayList();
final ResultSet results = database.getSchemas(
catalog, schemaPattern);
try {
bindAll(results, Schema.class, list);
} finally {
results.close();
}
if (list.isEmpty()) {
final Schema schema = new Schema();
schema.setTableSchem("");
list.add(schema);
}
return list;
}
public List getTables(final String catalog,
final String schemaPattern,
final String tableNamePattern,
final String[] types)
throws SQLException, ReflectiveOperationException {
final List list = new ArrayList();
final ResultSet results = database.getTables(
catalog, schemaPattern, tableNamePattern, types);
try {
bindAll(results, Table.class, list);
} finally {
results.close();
}
return list;
}
public List getTablePrivileges(
final String catalog, final String schemaPattern,
final String tableNamePattern)
throws SQLException, ReflectiveOperationException {
final List list = new ArrayList();
final ResultSet results = database.getTablePrivileges(
catalog, schemaPattern, tableNamePattern);
try {
bindAll(results, TablePrivilege.class, list);
} finally {
results.close();
}
return list;
}
public List getTableTypes()
throws SQLException, ReflectiveOperationException {
final List list = new ArrayList();
final ResultSet results = database.getTableTypes();
try {
bindAll(results, TableType.class, list);
} finally {
results.close();
}
return list;
}
public List getTypeInfo()
throws SQLException, ReflectiveOperationException {
final List list = new ArrayList();
final ResultSet results = database.getTypeInfo();
try {
bindAll(results, TypeInfo.class, list);
} finally {
results.close();
}
return list;
}
public List getUDTs(final String catalog, final String schemaPattern,
final String typeNamePattern, final int[] types)
throws SQLException, ReflectiveOperationException {
final List list = new ArrayList();
final ResultSet results = database.getUDTs(
catalog, schemaPattern, typeNamePattern, types);
try {
bindAll(results, UDT.class, list);
} finally {
results.close();
}
return list;
}
public List getVersionColumns(final String catalog,
final String schema,
final String table)
throws SQLException, ReflectiveOperationException {
final List list = new ArrayList();
final ResultSet results = database.getVersionColumns(
catalog, schema, table);
try {
bindAll(results, VersionColumn.class, list);
} finally {
results.close();
}
return list;
}
private Set getMethodNames() {
if (methodNames == null) {
methodNames = new HashSet();
for (final Method method : DatabaseMetaData.class.getMethods()) {
if (!DatabaseMetaData.class.equals(method.getDeclaringClass())) {
continue;
}
final int modifier = method.getModifiers();
if (Modifier.isStatic(modifier)) {
continue;
}
if (!Modifier.isPublic(modifier)) {
continue;
}
methodNames.add(method.getName());
}
}
return methodNames;
}
private final DatabaseMetaData database;
private Set suppressions;
private Set methodNames;
}