You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@xalan.apache.org by dl...@locus.apache.org on 2000/03/31 20:26:52 UTC
cvs commit: xml-xalan/src/org/apache/xalan/xslt/extensions RowSetLocator.java
dleslie 00/03/31 10:26:51
Added: src/org/apache/xalan/xslt/extensions RowSetLocator.java
Log:
Extension for performing a SQL query against
a JDBC data source and constructing a <rowset>
with the query result set.
Last appeared in 0.18.5. Updated per underlying API changes.
Uses DriverManager.getConnection(String url, Properties info)
to connect to data source. A <protocol> extension element
supples the info param. Call the connect extension function
to perform the operation.
Revision Changes Path
1.1 xml-xalan/src/org/apache/xalan/xslt/extensions/RowSetLocator.java
Index: RowSetLocator.java
===================================================================
/*
* The Apache Software License, Version 1.1
*
*
* Copyright (c) 1999 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Xalan" and "Apache Software Foundation" must
* not be used to endorse or promote products derived from this
* software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache",
* nor may "Apache" appear in their name, without prior written
* permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation and was
* originally based on software copyright (c) 1999, Lotus
* Development Corporation., http://www.lotus.com. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/
package org.apache.xalan.xslt.extensions;
import org.apache.xalan.xpath.*;
import org.apache.xalan.xpath.xml.*;
import org.w3c.dom.*;
import org.apache.xerces.dom.*;
import java.util.*;
import java.sql.*;
/**
* RowSetLocator uses JDBC to connect to a database, execute a query, and return
* a result set, then returns a lazy row-set DOM. This class can ONLY be used with
* the Xerces liaison (org.apache.xalan.xpath.xdom.XercesLiaison) and Xerces XML parser,
* since it extends the Xerces DOM implementation to create a lazy row-set DOM.
*/
public class RowSetLocator extends SimpleNodeLocator
{
/**
* Create a SimpleNodeLocator object.
*/
public RowSetLocator(String driver, String dbURL)
{
super();
init(driver, dbURL);
}
/**
* A JDBC driver of the form "foo.bar.Driver".
*/
public String m_driver;
/**
* A database URL of the form jdbc:subprotocol:subname.
*/
public String m_dbURL;
/**
* Connection properties
*/
static java.util.Properties m_protocol = new Properties();
/**
* User ID
*/
public String m_userID = "";
/**
* Password
*/
public String m_password = "";
/**
* A list of arbitrary string tag/value pairs as connection
* arguments; normally at least a "user" and "password"
* property should be included.
*/
public static void protocol(org.apache.xalan.xslt.XSLProcessorContext context,
org.apache.xalan.xslt.ElemExtensionCall protocolElem)
{
org.xml.sax.AttributeList atts = protocolElem.getAttributeList(); // added dml.
int ln = atts.getLength();
for (int i = 0; i < ln; i++)
{
m_protocol.put(atts.getName(i), atts.getValue(i));
}
}
/**
* The JDBC connection.
*/
public Connection m_connection = null;
/**
* The SQL statement, which lets us execute commands against the connection.
*/
Statement m_statement = null;
/**
* Initialize.
*/
private void init(String driver, String dbURL)
{
m_driver = driver;
m_dbURL = dbURL;
// System.out.println("init completed");
}
/**
* Execute the proprietary connect() function, which returns an
* instance of XLocator. When the XPath object sees a return type
* of XLocator, it calls the locationPath function that passes
* in the connectArgs. The opPos and args params are not used
* by this function. This really is just a factory function
* for the XLocator instance, but this fact is hidden from the
* user.
* @param driver JDBC driver.
* @param dbURL database URL of the form jdbc:subprotocol:subname.
* @param sqlQuery typically a static SQL SELECT statement, which
* is normally executed by the connectToNodes function when called by the XPath object.
* @returns An XLocator object.
*/
// coming public static XLocator connect (String driver, String dbURL, String sqlQuery) rest is in m_protocol
public static XLocator connect (String driver,
String dbURL,
String sqlQuery)
{
RowSetLocator locator = null;
try
{
locator = new RowSetLocator(driver, dbURL);
// The driver is installed by loading its class.
Class.forName(locator.m_driver);
// System.out.println("about to connect");
locator.m_connection = DriverManager.getConnection(locator.m_dbURL, m_protocol);
// System.out.println("connection OK");
/*
We could also turn autocommit off by putting
;autocommit=false on the URL.
*/
locator.m_connection.setAutoCommit(false);
// Creating a statement lets us issue commands against
// the connection.
locator.m_statement = locator.m_connection.createStatement();
// System.out.println("ready to return XLocator");
}
catch (Throwable e)
{
e.printStackTrace();
}
return locator;
}
/**
* Execute a connection and process the LocationPath,
* The arguments to the static connect function
* are re-passed to this function.
* @param xpath The xpath that is executing.
* @param context The current source tree context node.
* @param opPos The current position in the xpath.m_opMap array.
* @param connectArgs The same arguments that were passed to the
* static connect function.
* @returns the result of the query in an XNodeSet object.
*/
public XNodeSet connectToNodes(XPath xpath, XPathSupport execContext, Node context,
int opPos, Vector connectArgs)
{
// System.out.println("connectToNodes called");
XNodeSet results = new XNodeSet(); //create empty XNodeSet; was new XNodeSet(xpath.m_callbacks)
MutableNodeList mnl = results.mutableNodeset();
// RowSetLocator locator = null;
try
{
// Select the rows.
String query = ((XObject)connectArgs.elementAt(2)).str();
ResultSet rowSet
= m_statement.executeQuery(query);
// System.out.println("query executed");
DocumentImpl doc = new DocumentImpl();
Element elem = new RowSetElem(doc, "row-set", rowSet, this);
doc.appendChild(elem);
if((xpath.OP_LOCATIONPATH == xpath.getOpMap()[opPos]))
{
XNodeSet xnl = xpath.locationPath(execContext, doc, opPos, null, null, false);
/* locationPath args were (doc, opPos); now takes 6 args
(XPathSupport execContext,
Node context, int opPos,
NodeCallback callback, Object callbackInfo,
boolean stopAtFirst) */
if(null != xnl)
{
mnl.addNodes(xnl.nodeset());
execContext.associateXLocatorToNode(doc, this); // was XPath method
}
}
else
{
mnl.addNode(elem);
execContext.associateXLocatorToNode(doc, this); // was XPath method
}
}
catch (Throwable e)
{
e.printStackTrace();
}
return results;
}
/**
* The RowSetElem extends the behavior of ElementImpl
* by lazily evaluating it's row children.
* TODO: We'll need some sort of garbage collection for
* large rowsets, so we can discard rows at the beginning
* of the child list, or whatever.
*/
class RowSetElem extends ElementImpl
{
/**
* The query result set.
*/
ResultSet m_rowSet;
/**
* The owning RowSetLocator.
*/
RowSetLocator m_locator;
public RowSetElem(DocumentImpl ownerDoc, String name,
ResultSet rowSet, RowSetLocator locator)
{
super(ownerDoc, name);
m_rowSet = rowSet;
m_locator = locator;
try
{
ResultSetMetaData metadata = m_rowSet.getMetaData();
if(null != metadata)
{
int nColumns = metadata.getColumnCount();
setAttribute("n-columns", Integer.toString( nColumns ));
for(int i = 1; i <= nColumns; i++)
{
Element colHeader = ownerDoc.createElement("col-header");
appendChild(colHeader);
{
String tableName = metadata.getTableName(i);
if(tableName.length() > 0)
colHeader.setAttribute("table-name", tableName);
}
{
String catalog = metadata.getCatalogName(i);
if(catalog.length() > 0)
colHeader.setAttribute("catalog", catalog);
}
{
String columnNname = metadata.getColumnName(i);
if(null != columnNname)
{
if(columnNname.length() > 0)
colHeader.setAttribute("column-name", columnNname);
}
}
{
String label = metadata.getColumnLabel(i);
if(null != label)
{
if(label.length() > 0)
colHeader.setAttribute("column-label", label);
}
}
{
int displaySize = metadata.getColumnDisplaySize(i);
colHeader.setAttribute("display-size", Integer.toString(displaySize));
}
{
int precision = metadata.getPrecision(i);
colHeader.setAttribute("precision", Integer.toString(precision));
}
{
String type = metadata.getColumnTypeName(i);
if(type.length() > 0)
colHeader.setAttribute("type", type);
}
{
String schema = metadata.getSchemaName(i);
if(schema.length() > 0)
colHeader.setAttribute("schema", schema);
}
}
}
else
{
System.out.println("Could not get metadata!!");
}
}
catch (Throwable e)
{
e.printStackTrace();
}
}
/**
* Test whether this node has any children. Convenience shorthand
* for (Node.getFirstChild()!=null)
*/
public boolean hasChildNodes()
{
return getFirstChild() != null;
}
/** The first child of this Node, or null if none. */
public Node getFirstChild()
{
while ((m_count <= 1) && createRow())
{
;
}
return super.getFirstChild();
} // getFirstChild():Node
/** The last child of this Node, or null if none. */
public Node getLastChild()
{
getLength();
return super.getLastChild();
} // getLastChild():Node
int m_count = 0;
/**
* NodeList method: Count the immediate children of this node.
* (Expensive, so try to avoid using).
* @return int
*/
public int getLength()
{
// System.out.println("getLength called: "+m_count);
while (createRow()) // Creates a RowElem and increments m_count.
{
;
}
// System.out.println("counted: "+m_count);
return m_count;
} // getLength():int
/**
* Create a row child. For now, just create all the columns,
* don't try to lazily evaluate.
*/
boolean createRow()
{
boolean didCreate = false;
try
{
didCreate = m_rowSet.next();
if(didCreate)
{
ResultSetMetaData metadata = m_rowSet.getMetaData();
Document doc = this.getOwnerDocument();
Element row = new RowElem( (DocumentImpl)doc, "row");
this.appendChild(row);
int nColumns = metadata.getColumnCount();
for(int i = 1; i <= nColumns; i++)
{
Element col = doc.createElement("col");
row.appendChild(col);
String data = m_rowSet.getString(i);
Text text = doc.createTextNode(data);
col.appendChild(text);
}
m_count++;
}
}
catch (Throwable e)
{
e.printStackTrace();
}
return didCreate;
}
/**
* NodeList method: Return the Nth immediate child of this node, or
* null if the index is out of bounds.
* @return org.w3c.dom.Node
* @param Index int
*/
public Node item(int index)
{
while ((m_count <= index) && createRow())
{
;
}
return super.item(index);
} // item(int):Node
}
/**
* Set up a derived class for rows to override getNextSibling.
*/
class RowElem extends ElementImpl
{
public RowElem(DocumentImpl ownerDoc, String name)
{
super(ownerDoc, name);
}
/** The next child of this node's parent, or null if none */
public Node getNextSibling()
{
Node next = super.getNextSibling();
if(null == next) // Row has not yet been created.
{
RowSetElem rsElem = (RowSetElem)getParentNode();
rsElem.createRow();
next = super.getNextSibling();
}
return next;
}
}
}