/**
@class gatsDBpp::DatabaseHandles
@brief Employs the DatabaseHandles methods.
These routines establish and provide access to the database connections
that are usually established when the program initializes.
@date $Date$
@version $Rev$
@author
- Lance Deaver
@copyright
(©) Copyright 2006 by GATS Inc.
11864 Canon Blvd., Suite 101, Newport News, VA 23606
All Rights Reserved. No part of this software or publication may be
reproduced, stored in a retrieval system, or transmitted, in any form
or by any means, electronic, mechanical, photocopying, recording, or
otherwise without the prior written permission of GATS Inc.
@see gatsDBpp::DatabaseHandles.h
@see gatsDBpp::GATS_DB
@bug None known
$Id$
*/
#include "DatabaseHandles.h"
#include "CMarkup.h"
#include "GATS_Utilities.hpp"
#include "GATS_DB_mysql.h"
#include "DBTable.h"
#include "GATS_DB_Exception.h"
using namespace GATS_Utilities;
using namespace gatsDBpp;
DatabaseHandles::DatabaseHandles()
{
}
DatabaseHandles::~DatabaseHandles()
{
}
/**
* This function will add a GATS_DB database handle to the DatabaseHandles class and reference
* that connection to the provided string connectionName. If this class already has
* a connection referenced by the connectionName this class does nothing.
*
* @param[in] connectionName A string that is used to reference the GATS_DB connection handle.
* @param[in] dbhandle A GATS_DB handle to be added to the internal map.
*/
void DatabaseHandles::Add(const std::string& connectionName,GATS_DBptr dbhandle)
{
if(! HandleExists(connectionName) ) _DBMap[connectionName] = dbhandle;
}
/**
* Return a GATS_DBptr pointer to the requested database handle. If the requested name is not
* found this method will return a NULL GATS_DBptr.
*
* @param[in] connectionName The string name for the GATS_DB database handle.
* @retval gatsDBpp::GATS_DBptr The database handle as a smart pointer.
*/
GATS_DBptr DatabaseHandles::Get(const std::string& connectionName)
{
return (HandleExists(connectionName) ) ? _DBMap[connectionName] : GATS_DBptr() ;
}
/**
* Remove the database handle with the specified connectionName. If the requested name is not
* found the method does nothing.
*
* @param[in] connectionName The string name for the GATS_DB database handle.
*/
void DatabaseHandles::Remove(const std::string& connectionName)
{
std::map::iterator mapIter= _DBMap.find(connectionName);
if (mapIter != _DBMap.end() ) _DBMap.erase(mapIter);
}
void DatabaseHandles::KillAll()
{
_DBMap.clear();
}
/**
* Return the number of GATS_DB connections contained in this class.
* @retval int The number of connections contained in this class.
*/
int DatabaseHandles::NumberOfHandles() const
{
return static_cast(_DBMap.size() );
}
/**
* Indicates if a handle with a specified name exists in this class. Returns true
* if this connectionName is found.
*
* @param[in] connectionName The string name for the GATS_DB database handle.
* @retval bool A true/false value indicating if the connectionName is found in the class.
*/
bool DatabaseHandles::HandleExists(const std::string& connectionName) const
{
std::map::const_iterator mapIter= _DBMap.find(connectionName);
return (mapIter != _DBMap.end() ) ;
}
/**
* Returns a list of the database connection string names.
*
* @retval std::vector A list of the string names of the database connection handles that are in this class.
*/
std::vector DatabaseHandles::GetHandleNames() const
{
std::vector names;
for(std::map::const_iterator mapIter=_DBMap.begin();
mapIter != _DBMap.end(); ++mapIter )
names.push_back(mapIter->first);
return names;
}
void DatabaseHandles::InitTables(CMarkup* xml, const bool clearit )
{
std::string Version = xml->GetAttrib("version").c_str();
assert( ! Version.empty() && ConvertFromString(Version, std::scientific) >= 0.1) ;
if(clearit) {
_TableMap.clear();
}
xml->IntoElem(); // step into the element
while(xml->FindElem() ) {
if(strcasecmp(xml->GetTagName().c_str(), "table") ==0 ) {
std::string tableName = xml->GetAttrib("name").c_str() ;
assert( ! tableName.empty() );
std::string typeName = xml->GetAttrib("type").c_str() ;
assert( ! typeName.empty() );
xml->IntoElem() ;
std::string dbname;
std::map tableFields;
while( xml->FindElem() ) {
if(strcasecmp(xml->GetTagName().c_str(), "dbName") ==0 ) {
dbname= CMarkup::TrimString(xml->GetData() );
} else if(strcasecmp(xml->GetTagName().c_str(), "fields") ==0 ) {
while(xml->FindChildElem() ) {
if(strcasecmp(xml->GetChildTagName().c_str(), "field") !=0 ) continue;
std::string idName = xml->GetChildAttrib("id").c_str();
if(idName.empty() ) continue;
std::string fieldName = CMarkup::TrimString( xml->GetChildData() ) ;
tableFields[idName] = (fieldName.empty() ) ? idName : fieldName ;
}
}
}
_TableMap[tableName] = DBTable_ptr(new DBTable(tableName, tableFields, dbname, typeName) );
xml->OutOfElem();
}
} // end while over database connections
xml->OutOfElem();
}
/**
* This routine will parse the parameters from an XML stream and establish any
* requested database connections. An additional parameter will cause the
* class to clear any already established connections before parsing this data.
*
* @param[in] xml A pointer to a CMarkup instance that has the internal
* position set to the databaseConnections tag.
* @param[in] clearit A boolean that will indicate if any previously
* established connections will be removed before parsing the
* XML stream default value is true.
*
* @todo Add an exception throw if database type is unknown.
* @todo Remove assert convert to exception.
*/
void DatabaseHandles::Init( CMarkup* xml, const bool clearit )
{
std::string Version = xml->GetAttrib("version").c_str();
assert( ! Version.empty() && ConvertFromString(Version, std::scientific) >= 0.1) ;
if(clearit) {
_DBMap.clear();
}
xml->IntoElem(); // step into the element
while(xml->FindElem() ) {
std::string DBConnectionName;
if(strcasecmp(xml->GetTagName().c_str(), "connection") ==0 ) {
DBConnectionName = xml->GetAttrib("name").c_str() ;
assert( ! DBConnectionName.empty() );
if( strcmp(xml->GetAttrib("connect").c_str(), "true" ) != 0 ) continue;
}
std::string username, password, hostname, dbname, dbtype;
std::vector ports;
unsigned int defaultPortNo=0 ;
while(xml->FindChildElem() ) {
std::string tagName = xml->GetChildTagName() ;
std::string dataValue = CMarkup::TrimString(xml->GetChildData() );
if( strcasecmp( tagName.c_str(), "userName") ==0 && username.empty() ) {
username = dataValue;
} else if (strcasecmp( tagName.c_str(), "password") == 0 && password.empty() ) {
password = dataValue;
} else if (strcasecmp( tagName.c_str(), "serverName") == 0 && hostname.empty() ) {
std::string Port = xml->GetChildAttrib("port").c_str();
if( ! Port.empty() ) {
ports.push_back(ConvertFromString(Port, std::dec, false) );
}
hostname = dataValue;
} else if (strcasecmp( tagName.c_str(), "dbName") == 0 && dbname.empty() ) { //initial database name
dbname = dataValue;
} else if (strcasecmp( tagName.c_str(), "type") == 0 && dbtype.empty() ) { // the database type add new ones here
if (strcasecmp( dataValue.c_str(), "mysql") == 0) {
dbtype = std::string("mysql");
}
}
} //end while child elements
if(dbtype == std::string("mysql") ) {
if( hostname.empty() ) {
hostname=std::string("localhost"); // a default server
}
defaultPortNo=0;
_DBMap[DBConnectionName] = GATS_DBptr( new GATS_DB_mysql(username.c_str(),
password.c_str(),
dbname.c_str() ,
hostname.c_str(),
( ports.empty() ) ? defaultPortNo : ports.front() )) ;
} else {
std::string msg = dbtype + " is not a recognized Database type";
THROW_GATS_EXCEPTION( UnknownDatabaseType, msg.c_str() );
}
} // end while over database connections
xml->OutOfElem() ;
}
/**
* This function will create a static DatabaseHandles instance and return a
* pointer to that instance. This is a way using
* global data in a sort of safe manner and it is used to provide
* database access to a module without having to pass in all the
* handle information.
*
* @retval gatsDBpp::DatabaseHandles* A pointer to the internal instance.
*/
DatabaseHandles* gatsDBpp::GetDatabaseHandles()
{
static std::auto_ptr handlePtr(new DatabaseHandles() );
return handlePtr.get();
}