/*
* eXist SQL Module Extension
* Copyright (C) 2006-09 Adam Retter <adam@exist-db.org>
* www.adamretter.co.uk
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program 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 program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package org.exist.xquery.modules.sql;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Set;
import org.apache.log4j.Logger;
import org.exist.xquery.AbstractInternalModule;
import org.exist.xquery.FunctionDef;
import org.exist.xquery.XQueryContext;
/**
* eXist SQL Module Extension
*
* An extension module for the eXist Native XML Database that allows queries
* against SQL Databases, returning an XML representation of the result set.
*
* @author Adam Retter <adam@exist-db.org>
* @author ljo
* @serial 2008-05-19
* @version 1.1
*
* @see org.exist.xquery.AbstractInternalModule#AbstractInternalModule(org.exist.xquery.FunctionDef[])
*/
public class SQLModule extends AbstractInternalModule {
protected final static Logger LOG = Logger.getLogger(SQLModule.class);
public final static String NAMESPACE_URI = "http://exist-db.org/xquery/sql";
public final static String PREFIX = "sql";
public final static String INCLUSION_DATE = "2006-09-25";
public final static String RELEASED_IN_VERSION = "eXist-1.2";
private final static FunctionDef[] functions = {
new FunctionDef(GetConnectionFunction.signatures[0], GetConnectionFunction.class),
new FunctionDef(GetConnectionFunction.signatures[1], GetConnectionFunction.class),
new FunctionDef(GetConnectionFunction.signatures[2], GetConnectionFunction.class),
new FunctionDef(GetJNDIConnectionFunction.signatures[0], GetJNDIConnectionFunction.class),
new FunctionDef(GetJNDIConnectionFunction.signatures[1], GetJNDIConnectionFunction.class),
new FunctionDef(ExecuteFunction.signatures[0], ExecuteFunction.class),};
private static long currentConnectionUID = System.currentTimeMillis();
public final static String CONNECTIONS_CONTEXTVAR = "_eXist_sql_connections";
public SQLModule() {
super(functions);
}
public String getNamespaceURI() {
return NAMESPACE_URI;
}
public String getDefaultPrefix() {
return PREFIX;
}
public String getDescription() {
return "A module for performing SQL queries against Databases, returning XML representations of the result sets.";
}
public String getReleaseVersion() {
return RELEASED_IN_VERSION;
}
/**
* Retrieves a previously stored Connection from the Context of an XQuery
*
* @param context
* The Context of the XQuery containing the Connection
* @param connectionUID
* The UID of the Connection to retrieve from the Context of the
* XQuery
*/
public final static Connection retrieveConnection(XQueryContext context,
long connectionUID) {
// get the existing connections map from the context
HashMap connections = (HashMap) context.getXQueryContextVar(SQLModule.CONNECTIONS_CONTEXTVAR);
if(connections == null) {
return null;
}
// get the connection
return (Connection) connections.get(new Long(connectionUID));
}
/**
* Stores a Connection in the Context of an XQuery
*
* @param context
* The Context of the XQuery to store the Connection in
* @param con
* The connection to store
*
* @return A unique ID representing the connection
*/
public final static synchronized long storeConnection(
XQueryContext context, Connection con) {
// get the existing connections map from the context
HashMap connections = (HashMap) context.getXQueryContextVar(SQLModule.CONNECTIONS_CONTEXTVAR);
if(connections == null) {
// if there is no connections map, create a new one
connections = new HashMap();
}
// get an id for the connection
long conID = getUID();
// place the connection in the connections map
connections.put(new Long(conID), con);
// store the updated connections map back in the context
context.setXQueryContextVar(SQLModule.CONNECTIONS_CONTEXTVAR,
connections);
return conID;
}
/**
* Closes all the open DB connections for the specified XQueryContext
*
* @param xqueryContext
* The context to close JDBC connections for
*/
private final static void closeAllConnections(XQueryContext xqueryContext) {
// get the existing connections map from the context
HashMap connections = (HashMap) xqueryContext.getXQueryContextVar(SQLModule.CONNECTIONS_CONTEXTVAR);
if(connections != null) {
// iterate over each connection
Set keys = connections.keySet();
for(Iterator itKeys = keys.iterator(); itKeys.hasNext();) {
// get the connection
Long conID = (Long) itKeys.next();
Connection con = (Connection) connections.get(conID);
try {
// close the connection
con.close();
} catch(SQLException se) {
LOG.debug("Unable to close JDBC connection", se);
}
}
//empty the map
connections.clear();
// update the context
xqueryContext.setXQueryContextVar(SQLModule.CONNECTIONS_CONTEXTVAR,
connections);
}
}
/**
* Returns a Unique ID based on the System Time
*
* @return The Unique ID
*/
private static synchronized long getUID() {
return currentConnectionUID++;
}
/**
* Resets the Module Context and closes any DB connections for the
* XQueryContext
*
* @param xqueryContext
* The XQueryContext
*/
public void reset(XQueryContext xqueryContext) {
// reset the module context
super.reset(xqueryContext);
// close any open connections
closeAllConnections(xqueryContext);
}
}