/*
* Copyright (C) 2000 - 2011 TagServlet Ltd
*
* This file is part of Open BlueDragon (OpenBD) CFML Server Engine.
*
* OpenBD is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Free Software Foundation,version 3.
*
* OpenBD 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenBD. If not, see http://www.gnu.org/licenses/
*
* Additional permission under GNU GPL version 3 section 7
*
* If you modify this Program, or any covered work, by linking or combining
* it with any of the JARS listed in the README.txt (or a modified version of
* (that library), containing parts covered by the terms of that JAR, the
* licensors of this Program grant you additional permission to convey the
* resulting work.
* README.txt @ http://www.openbluedragon.org/license/README.txt
*
* http://www.openbluedragon.org/
* $Id: cfQueryImplSQL.java 2327 2013-02-10 22:26:44Z alan $
*/
package com.naryx.tagfusion.cfm.sql.platform.java;
import java.util.Enumeration;
import java.util.Vector;
import com.naryx.tagfusion.cfm.application.cfApplicationData;
import com.naryx.tagfusion.cfm.engine.cfEngine;
import com.naryx.tagfusion.cfm.engine.cfSession;
import com.naryx.tagfusion.cfm.engine.cfmRunTimeException;
import com.naryx.tagfusion.cfm.sql.cfDataSource;
import com.naryx.tagfusion.cfm.sql.cfDataSourceStatus;
import com.naryx.tagfusion.cfm.sql.cfDynamicDataSource;
import com.naryx.tagfusion.cfm.sql.cfQUERY;
import com.naryx.tagfusion.cfm.sql.cfQueryImplInterface;
import com.naryx.tagfusion.cfm.sql.cfSQLQueryData;
import com.naryx.tagfusion.cfm.sql.querySlowLog;
import com.naryx.tagfusion.cfm.sql.pool.WrappedConnection;
import com.naryx.tagfusion.cfm.tag.cfTagReturnType;
import com.naryx.tagfusion.xmlConfig.xmlCFML;
/*
* This class provides the necessary implementation specific
* for providing the hook to basic SQL feature set.
*/
public class cfQueryImplSQL extends Object implements cfQueryImplInterface {
static final long serialVersionUID = 1;
private queryBatchServer queryServer;
public cfQueryImplSQL(){}
public void init( xmlCFML configFile ){
// Setup the Batch Server [will move to the SQLImp]
queryServer = new queryBatchServer(configFile);
querySlowLog.init( configFile );
// Set the DEFAULT Validation
boolean bValidate = configFile.getBoolean( "server.cfquery.validate", true );
WrappedConnection.setValidateConnections( bValidate );
cfEngine.log( "CFQUERY Connection pool validation queries: " + ( bValidate ? "ENABLED" : "DISABLED" ) );
// set the status of all connections to "unknown"
Vector<String> V = configFile.getKeys( "server.cfquery.datasource[]" );
if ( V != null ){
Enumeration<String> E = V.elements();
while ( E.hasMoreElements() ){
String key = E.nextElement();
// Remove the status values from their old BD 6.1 and earlier location (if present)
if (configFile.getString(key + ".success") != null)
configFile.removeData( key + ".success" );
if (configFile.getString(key + ".errormessage") != null)
configFile.removeData(key + ".errormessage");
int begin = key.indexOf( '[' );
if ( begin != - 1 ){
int end = key.indexOf( ']', begin );
if ( end != - 1 ){
String dsName = key.substring( begin+1, end );
cfEngine.getDataSourceStatus().put( dsName, new cfDataSourceStatus() );
}
}
}
}
}
public cfTagReturnType render( cfQUERY tag, cfSession _Session ) throws cfmRunTimeException {
//Setup the main datasource and querydata objects
cfDataSource dataSource = getDataSource( tag, _Session );
cfSQLQueryData queryData = new cfSQLQueryData( dataSource );
queryData.setRetrieveGeneratedKeys( tag.containsAttribute("RESULT") );
//Determine the inner SQL
tag.renderInnerBody( queryData, _Session );
//Determine if this is a BACKGROUND query; we only want to background non SELECT statements, non QoQ queries
if ( tag.containsAttribute("BACKGROUND") && (queryData.getQueryType() != cfSQLQueryData.SQL_SELECT) && tag.getDynamic(_Session, "BACKGROUND").getBoolean() ){
prepareBackgroundExecution( dataSource, queryData );
return cfTagReturnType.NORMAL;
}
//Setup any cache information for this
tag.setupCache( queryData, _Session );
//Execute the query
tag.executeStatement( queryData, _Session );
return cfTagReturnType.NORMAL;
}
/*
* This query will be run at a later date, managed by a single process. We prepare
* this for later
*/
private void prepareBackgroundExecution(cfDataSource dataSource, cfSQLQueryData queryData ){
queryBatchSQL newSql = new queryBatchSQL();
newSql.setDatasourceName( dataSource.getDataSourceName() );
newSql.setDatasourceUser( dataSource.getUsername() );
newSql.setDatasourcePass( dataSource.getPassword() );
newSql.setQueryParams( queryData.getParams() );
newSql.setSqlString( queryData.getQueryString() );
queryServer.acceptSQL( newSql );
}
/*
* This method gets the datasource for this query, based on the dbtype; this lets us determine
* if the datasource is to be created dynamically or we simply use one that is already part of
* the underlying engine
*/
private cfDataSource getDataSource( cfQUERY tag, cfSession _Session ) throws cfmRunTimeException {
boolean dynamicDatasource = false;
if ( tag.containsAttribute( "DBTYPE" ) ){
String dbType = tag.getDynamic( _Session, "DBTYPE" ).getString().toLowerCase();
if ( dbType.equals("dynamic") ) {
if ( !tag.containsAttribute("CONNECTSTRING") )
throw tag.newRunTimeException( "You must specify the CONNECTSTRING attribute with DBTYPE=\"DYNAMIC\"" );
dynamicDatasource = true;
}
}
cfDataSource dataSource = null;
if ( dynamicDatasource )
dataSource = new cfDynamicDataSource( "DYNAMIC", _Session, tag.getDynamic(_Session, "CONNECTSTRING").getString());
else{
String datasource = getDataSourceValue( tag, _Session );
if ( datasource == null )
throw tag.newRunTimeException( "You must specify either the DATASOURCE attribute or 'this.datasource' in the Application.cfc setup" );
dataSource = new cfDataSource( datasource, _Session );
}
// Set any additional parameters
if ( tag.containsAttribute("USERNAME") )
dataSource.setUsername( tag.getDynamic(_Session, "USERNAME").getString() );
if ( tag.containsAttribute("PASSWORD") )
dataSource.setPassword( tag.getDynamic(_Session, "PASSWORD").getString() );
return dataSource;
}
/**
* Gets the datasource value from first the TAG attribute, and if that does not exist, then from the application data
* @param tag
* @param _Session
* @return
* @throws cfmRunTimeException
*/
private String getDataSourceValue( cfQUERY tag, cfSession _Session ) throws cfmRunTimeException {
if ( tag.containsAttribute("DATASOURCE") )
return tag.getDynamic(_Session, "DATASOURCE").getString();
else{
cfApplicationData appData = _Session.getApplicationData();
if ( appData != null )
return appData.getDataSource();
}
return null;
}
}