org.mule.module.db.internal.metadata.AbstractQueryMetadataProvider Maven / Gradle / Ivy
/*
* Copyright (c) MuleSoft, Inc. All rights reserved. http://www.mulesoft.com
* The software in this package is published under the terms of the CPAL v1.0
* license, a copy of which has been included with this distribution in the
* LICENSE.txt file.
*/
package org.mule.module.db.internal.metadata;
import org.mule.common.DefaultResult;
import org.mule.common.FailureType;
import org.mule.common.Result;
import org.mule.common.metadata.DefaultDefinedMapMetaDataModel;
import org.mule.common.metadata.DefaultListMetaDataModel;
import org.mule.common.metadata.DefaultMetaData;
import org.mule.common.metadata.DefaultPojoMetaDataModel;
import org.mule.common.metadata.DefaultSimpleMetaDataModel;
import org.mule.common.metadata.DefaultUnknownMetaDataModel;
import org.mule.common.metadata.MetaData;
import org.mule.common.metadata.MetaDataModel;
import org.mule.common.metadata.datatype.DataType;
import org.mule.module.db.internal.domain.connection.DbConnection;
import org.mule.module.db.internal.domain.database.DbConfig;
import org.mule.module.db.internal.domain.param.InputQueryParam;
import org.mule.module.db.internal.domain.query.Query;
import org.mule.module.db.internal.domain.transaction.TransactionalAction;
import org.mule.module.db.internal.resolver.database.DbConfigResolver;
import java.net.URL;
import java.sql.Blob;
import java.sql.Clob;
import java.sql.Date;
import java.sql.ParameterMetaData;
import java.sql.PreparedStatement;
import java.sql.Ref;
import java.sql.RowId;
import java.sql.SQLException;
import java.sql.SQLXML;
import java.sql.Struct;
import java.sql.Time;
import java.sql.Timestamp;
import java.sql.Types;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Base class for {@link QueryMetadataProvider} implementations
*/
public abstract class AbstractQueryMetadataProvider implements QueryMetadataProvider
{
protected final Query query;
protected final DbConfigResolver dbConfigResolver;
private Map dbToMetaDataType;
public AbstractQueryMetadataProvider(DbConfigResolver dbConfigResolver, Query query)
{
this.dbConfigResolver = dbConfigResolver;
this.query = query;
}
/**
*
* @return output metadata for a type of query. Can be null
*/
protected abstract Result getStaticOutputMetadata();
/**
* Calculates the dynamic output metadata from a statement
*
* @param statement statement used to calculate the metadata
*
* @return output metadata for the statement. Can be null
*/
protected abstract Result getDynamicOutputMetadata(PreparedStatement statement);
/**
* Calculates the input metadata for a statement
*
* @param statement statement used to calculate the metadata
* @param query query that will be executed in the statement
* @return
*/
protected Result getDynamicInputMetadata(PreparedStatement statement, Query query)
{
List inputParams = query.getQueryTemplate().getInputParams();
// No metadata when no input parameters
if (inputParams.size() == 0)
{
return null;
}
List fieldNames = new ArrayList();
for (InputQueryParam inputParam : inputParams)
{
String field = getReferencedField(inputParam);
if (field == null)
{
return null;
}
fieldNames.add(field);
}
try
{
return getInputMetadataUsingStatementMetadata(statement, fieldNames);
}
catch (SQLException e)
{
return getStaticInputMetadata(fieldNames);
}
}
private Result getStaticInputMetadata(List fieldNames)
{
Map recordModels = new HashMap();
for (String fieldName : fieldNames)
{
recordModels.put(fieldName, getDataTypeMetadataModel(Types.VARCHAR));
}
DefaultDefinedMapMetaDataModel recordModel = new DefaultDefinedMapMetaDataModel(recordModels);
DefaultMetaData defaultMetaData = new DefaultMetaData(recordModel);
return new DefaultResult(defaultMetaData);
}
private Result getInputMetadataUsingStatementMetadata(PreparedStatement statement, List fieldNames) throws SQLException
{
ParameterMetaData parameterMetaData = statement.getParameterMetaData();
Map recordModels = new HashMap();
int i = 1;
for (String fieldName : fieldNames)
{
int dataType = parameterMetaData.getParameterType(i++);
recordModels.put(fieldName, getDataTypeMetadataModel(dataType));
}
DefaultDefinedMapMetaDataModel recordModel = new DefaultDefinedMapMetaDataModel(recordModels);
DefaultMetaData defaultMetaData = new DefaultMetaData(recordModel);
return new DefaultResult(defaultMetaData);
}
private String getReferencedField(InputQueryParam inputParam)
{
if (inputParam.getValue() == null || !(inputParam.getValue() instanceof String))
{
return null;
}
String value = (String) inputParam.getValue();
if (value.startsWith("#[") && value.endsWith("]"))
{
value = value.substring(2, value.length() - 1);
if (value.startsWith("payload."))
{
value = value.substring(8);
if (isValidIdentifier(value))
{
return value;
}
}
else if ((value.startsWith("payload['") && value.endsWith("']")) || (value.startsWith("payload[\"") && value.endsWith("\"]")))
{
value = value.substring(9, value.length() - 2);
if (isValidIdentifier(value))
{
return value;
}
}
}
return null;
}
private boolean isValidIdentifier(String value)
{
for (char c : value.toCharArray())
{
if (!Character.isJavaIdentifierPart(c))
{
return false;
}
}
return true;
}
protected MetaDataModel getDataTypeMetadataModel(int columnTypeName)
{
if (dbToMetaDataType == null)
{
synchronized (this)
{
if (dbToMetaDataType == null)
{
initializeDbToMetaDataType();
}
}
}
MetaDataModel metaDataModel = dbToMetaDataType.get(columnTypeName);
if (metaDataModel != null)
{
return metaDataModel;
}
else
{
return new DefaultUnknownMetaDataModel();
}
}
private void initializeDbToMetaDataType()
{
dbToMetaDataType = new HashMap();
dbToMetaDataType.put(Types.BIT, new DefaultSimpleMetaDataModel(DataType.BOOLEAN));
dbToMetaDataType.put(Types.TINYINT, new DefaultSimpleMetaDataModel(DataType.BYTE));
dbToMetaDataType.put(Types.SMALLINT, new DefaultSimpleMetaDataModel(DataType.SHORT));
dbToMetaDataType.put(Types.INTEGER, new DefaultSimpleMetaDataModel(DataType.INTEGER));
dbToMetaDataType.put(Types.BIGINT, new DefaultSimpleMetaDataModel(DataType.LONG));
dbToMetaDataType.put(Types.FLOAT, new DefaultSimpleMetaDataModel(DataType.FLOAT));
dbToMetaDataType.put(Types.REAL, new DefaultSimpleMetaDataModel(DataType.FLOAT));
dbToMetaDataType.put(Types.DOUBLE, new DefaultSimpleMetaDataModel(DataType.DOUBLE));
dbToMetaDataType.put(Types.NUMERIC, new DefaultSimpleMetaDataModel(DataType.DECIMAL));
dbToMetaDataType.put(Types.DECIMAL, new DefaultSimpleMetaDataModel(DataType.DECIMAL));
dbToMetaDataType.put(Types.CHAR, new DefaultSimpleMetaDataModel(DataType.STRING));
dbToMetaDataType.put(Types.VARCHAR, new DefaultSimpleMetaDataModel(DataType.STRING));
dbToMetaDataType.put(Types.LONGNVARCHAR, new DefaultSimpleMetaDataModel(DataType.STRING));
DefaultSimpleMetaDataModel dateMetaDataModel = new DefaultSimpleMetaDataModel(DataType.DATE);
dateMetaDataModel.setImplementationClass(Date.class.getName());
dbToMetaDataType.put(Types.DATE, dateMetaDataModel);
DefaultSimpleMetaDataModel timeMetaDataModel = new DefaultSimpleMetaDataModel(DataType.DATE_TIME);
timeMetaDataModel.setImplementationClass(Time.class.getName());
dbToMetaDataType.put(Types.TIME, timeMetaDataModel);
DefaultSimpleMetaDataModel timestampMetaDataModel = new DefaultSimpleMetaDataModel(DataType.DATE_TIME);
timeMetaDataModel.setImplementationClass(Timestamp.class.getName());
dbToMetaDataType.put(Types.TIMESTAMP, timestampMetaDataModel);
MetaDataModel binaryMetaDataModel = new DefaultListMetaDataModel(new DefaultSimpleMetaDataModel(DataType.BYTE), true);
dbToMetaDataType.put(Types.BINARY, binaryMetaDataModel);
MetaDataModel varBinaryMetaDataModel = new DefaultListMetaDataModel(new DefaultSimpleMetaDataModel(DataType.BYTE), true);
dbToMetaDataType.put(Types.VARBINARY, varBinaryMetaDataModel);
MetaDataModel longVarBinaryMetaDataModel = new DefaultListMetaDataModel(new DefaultSimpleMetaDataModel(DataType.BYTE), true);
dbToMetaDataType.put(Types.LONGVARBINARY, longVarBinaryMetaDataModel);
dbToMetaDataType.put(Types.NULL, new DefaultUnknownMetaDataModel());
dbToMetaDataType.put(Types.OTHER, new DefaultUnknownMetaDataModel());
dbToMetaDataType.put(Types.JAVA_OBJECT, new DefaultPojoMetaDataModel(Object.class));
dbToMetaDataType.put(Types.DISTINCT, new DefaultUnknownMetaDataModel());
dbToMetaDataType.put(Types.STRUCT, new DefaultPojoMetaDataModel(Struct.class));
dbToMetaDataType.put(Types.ARRAY, new DefaultListMetaDataModel(new DefaultUnknownMetaDataModel(), true));
dbToMetaDataType.put(Types.BLOB, new DefaultPojoMetaDataModel(Blob.class));
dbToMetaDataType.put(Types.CLOB, new DefaultPojoMetaDataModel(Clob.class));
dbToMetaDataType.put(Types.REF, new DefaultPojoMetaDataModel(Ref.class));
dbToMetaDataType.put(Types.DATALINK, new DefaultPojoMetaDataModel(URL.class));
dbToMetaDataType.put(Types.BOOLEAN, new DefaultSimpleMetaDataModel(DataType.BOOLEAN));
dbToMetaDataType.put(Types.ROWID, new DefaultPojoMetaDataModel(RowId.class));
dbToMetaDataType.put(Types.NCHAR, new DefaultSimpleMetaDataModel(DataType.STRING));
dbToMetaDataType.put(Types.NVARCHAR, new DefaultSimpleMetaDataModel(DataType.STRING));
dbToMetaDataType.put(Types.LONGNVARCHAR, new DefaultSimpleMetaDataModel(DataType.STRING));
dbToMetaDataType.put(Types.NCLOB, new DefaultSimpleMetaDataModel(DataType.STRING));
dbToMetaDataType.put(Types.SQLXML, new DefaultPojoMetaDataModel(SQLXML.class));
}
@Override
public Result getInputMetaData()
{
if (query.isDynamic())
{
return new DefaultResult(null, Result.Status.FAILURE, "Cannot obtain metadata from a dynamic SQL");
}
else
{
return getMetaDataResult(query, new InputMetadataResolver());
}
}
@Override
public Result getOutputMetaData(MetaData metaData)
{
if (query.isDynamic())
{
Result staticMetadata = getStaticOutputMetadata();
if (staticMetadata != null)
{
return staticMetadata;
}
else
{
return new DefaultResult(null, Result.Status.FAILURE, "Cannot obtain metadata from a dynamic SQL");
}
}
else
{
return getMetaDataResult(query, new OutputMetadataResolver());
}
}
private Result getMetaDataResult(Query query, MetadataResolver metadataResolver)
{
DbConnection connection = null;
DbConfig dbConfig = dbConfigResolver.resolve(null);
try
{
try
{
connection = dbConfig.getConnectionFactory().createConnection(TransactionalAction.NOT_SUPPORTED);
}
catch (SQLException e)
{
return new DefaultResult(null, Result.Status.FAILURE, e.getMessage(), FailureType.CONNECTION_FAILURE, e);
}
PreparedStatement preparedStatement;
try
{
preparedStatement = connection.prepareStatement(query.getQueryTemplate().getSqlText());
}
catch (SQLException e)
{
return new DefaultResult(null, Result.Status.FAILURE, e.getMessage(), FailureType.INVALID_CONFIGURATION, e);
}
return metadataResolver.resolveMetaData(preparedStatement, query);
}
finally
{
dbConfig.getConnectionFactory().releaseConnection(connection);
}
}
private interface MetadataResolver
{
Result resolveMetaData(PreparedStatement statement, Query query);
}
private class OutputMetadataResolver implements MetadataResolver
{
@Override
public Result resolveMetaData(PreparedStatement statement, Query query)
{
return getDynamicOutputMetadata(statement);
}
}
private class InputMetadataResolver implements MetadataResolver
{
@Override
public Result resolveMetaData(PreparedStatement statement, Query query)
{
return getDynamicInputMetadata(statement, query);
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy