All Downloads are FREE. Search and download functionalities are using the official Maven repository.

sunlabs.brazil.sql.SqlTemplate Maven / Gradle / Ivy

The newest version!
/*
 * SqlTemplate.java
 *
 * Brazil project web application toolkit,
 * export version: 2.3 
 * Copyright (c) 2000-2005 Sun Microsystems, Inc.
 *
 * Sun Public License Notice
 *
 * The contents of this file are subject to the Sun Public License Version 
 * 1.0 (the "License"). You may not use this file except in compliance with 
 * the License. A copy of the License is included as the file "license.terms",
 * and also available at http://www.sun.com/
 * 
 * The Original Code is from:
 *    Brazil project web application toolkit release 2.3.
 * The Initial Developer of the Original Code is: suhler.
 * Portions created by suhler are Copyright (C) Sun Microsystems, Inc.
 * All Rights Reserved.
 * 
 * Contributor(s): cstevens, suhler.
 *
 * Version:  2.7
 * Created by suhler on 00/05/08
 * Last modified by suhler on 05/05/11 14:20:52
 *
 * Version Histories:
 *
 * 2.7 05/05/11-14:20:52 (suhler)
 *   - added type=query|system|update to  to run executeQuery(),
 *   execute(), and executeUpdate() respectively
 *   - added timeout=[seconds] to 
 *   - fixed "prefix" to eliminate redundant '.'s in property named
 *
 * 2.6 04/11/30-15:19:42 (suhler)
 *   fixed sccs version string
 *
 * 2.5 04/08/30-09:01:53 (suhler)
 *   "enum" became a reserved word, change to "enumer".
 *
 * 2.4 04/04/28-15:57:13 (suhler)
 *   added attributes for spedifying n/a values and 0 or 1 based indexing
 *
 * 2.3 03/08/21-12:46:28 (suhler)
 *   typo in "rowcount" property
 *
 * 2.2 03/07/07-14:45:16 (suhler)
 *   Merged changes between child workspace "/home/suhler/brazil/naws" and
 *   parent workspace "/net/mack.eng/export/ws/brazil/naws".
 *
 * 1.11.1.1 03/07/07-14:08:15 (suhler)
 *   use addClosingTag() convenience method
 *
 * 2.1 02/10/01-16:39:11 (suhler)
 *   version change
 *
 * 1.11 01/08/03-18:23:21 (suhler)
 *   remove training  ws from classnames before trying to instantiate
 *
 * 1.10 01/06/04-14:10:15 (suhler)
 *   package move
 *
 * 1.9 00/12/11-13:32:37 (suhler)
 *   add class=props for automatic property extraction
 *
 * 1.8 00/10/05-15:51:58 (cstevens)
 *   PropsTemplate.subst() and PropsTemplate.getProperty() moved to the Format
 *   class.
 *
 * 1.7 00/07/07-17:02:31 (suhler)
 *   remove System.out.println(s)
 *
 * 1.6 00/07/07-15:32:51 (suhler)
 *   doc fixes
 *
 * 1.5 00/07/06-15:49:42 (suhler)
 *   doc update
 *
 * 1.4 00/05/31-13:52:03 (suhler)
 *   name change
 *
 * 1.3 00/05/19-11:50:30 (suhler)
 *   redo of error processing - its still not right though
 *
 * 1.2 00/05/10-10:44:21 (suhler)
 *   doc updates
 *
 * 1.2 00/05/08-17:37:52 (Codemgr)
 *   SunPro Code Manager data about conflicts, renames, etc...
 *   Name history : 1 0 sql/SqlTemplate.java
 *
 * 1.1 00/05/08-17:37:51 (suhler)
 *   date and time created 00/05/08 17:37:51 by suhler
 *
 */

package sunlabs.brazil.sql;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Enumeration;
import java.util.Properties;

import sunlabs.brazil.util.StringMap;
import sunlabs.brazil.util.Format;
import sunlabs.brazil.server.Server;
import sunlabs.brazil.template.Template;
import sunlabs.brazil.template.RewriteContext;

/**
 * Sample Template class for running SQL queries via jdbc and
 * placing the results into the request properties for further processing.
 * 

* Foreach session, a connection is made to an sql database via jdbc. * Session reconnection is attempted if the server connection breaks. * An SQL query is issued, with the results populating the request properties. * The following server properties are used: *

*
driver
The name of the jdbc driver class for the desired database. * Currently, only one driver may be specified. * (e.g. prefix.driver=org.gjt.mm.mysql.Driver). *
url
The jdbc url used to establish a connection with the * database. (e.g. * prefix.url=jdbc:mysql://host/db?user=xxx&password=yyy). *
sqlPrefix
The properties prefix for any additional parameters * that are required for this connection. For example: *
 *		 prefix.sqlPrefix=params
 *		 params.user=my_name
 *		 params.password=xxx
 *		
* All of the parameters are supplied to the jdbc connection * at connection time. *
* The driver and url parameters are required. * All of the code between <sql>...</sql> * is taken to be an SQL query, and sent to the appropriate database * for execution. The result of the query is placed into the request * properties for use by other templates, such as the * {@link sunlabs.brazil.template.BSLTemplate BSLTemplate} or * {@link sunlabs.brazil.template.PropsTemplate PropsTemplate}. *

* For a discussion of how the results map to properties, * {@link #tag_sql see below}. * * @author Stephen Uhler * @version 2.7 */ public class SqlTemplate extends Template { Connection con = null; // our connection to the database; String prefix; // our properties prefix Properties sqlProps = null; // extra properties to hand to connection boolean initialized = false; String url; // the jdbc url to connect to public boolean init(RewriteContext hr) { super.init(hr); hr.addClosingTag("sql"); if (initialized) { return (con != null); } initialized = true; prefix = hr.prefix; Properties props = hr.request.props; String driver = props.getProperty(hr.prefix + "driver"); url = props.getProperty(hr.prefix + "url"); if (driver == null || url == null) { hr.request.log(Server.LOG_WARNING, hr.prefix, " needs url and driver parameters"); return false; } // System.out.println(prefix + "url=" + url + " driver=" + driver); /* * Get the extra properties passed to each sql connection */ String pre = props.getProperty(hr.prefix + "sqlPrefix"); if (pre != null) { Enumeration enumer = props.propertyNames(); int len= pre.length(); sqlProps = new Properties(); while(enumer.hasMoreElements()) { String key = (String) enumer.nextElement(); if (key.startsWith(pre)) { sqlProps.put(key.substring(len), props.getProperty(key)); } } // System.out.println("Con props: " + sqlProps); } /* * Load the jdbc driver and create a connection. */ try { Class.forName(driver.trim()); } catch (ClassNotFoundException e) { hr.request.log(Server.LOG_WARNING, hr.prefix, e.getMessage()); return false; } con = setupSql(url, sqlProps); hr.request.log(Server.LOG_DIAGNOSTIC, hr.prefix, "Got sql connection: " + con); return (con != null); } /** * Replace the SQL query with the appropriate request properties. * Look for the following parameters: * (NOTE - This interface is preliminary, and subject to change). *

*
debug
Include diagnostics in html comments *
prefix
prefix to prepend to all results. * Defaults to template prefix *
max
The max # of rows returned (default=100) *
na
Value to reurn for NULL. Defaults to "n/a" *
type
The type of SQL command, one of "query", "system", * or "update". these values map to the JDBC calls * executeQuery(), execute() and executeUpdate() * respectively. Defaults to "query". *
timeout
The number of seconds to wait for the query * to finish. Defaults to "0": wait forever *
eval
If present, do ${...} to entire query. (see * {@link sunlabs.brazil.util.Format#getProperty getProperty}). *
zeroIndex
if true, row counts start at 0, not 1 *
index
If present, use column 1 as part of the name. * Otherwise, an index name is invented. *
* For all queries, the following properties (with the prefix prepended) * are set: *
*
columns
The number of columns returned *
rowcount
The number of rows returned *
* Foreach entry in the resultant table, its property is: * ${prefix}.${table_name}.${columname}.${key}. If * the index parameter is set, the key is the value of * the first column returned. Otherwise the key is the row number, * and the additional property ${prefix}.rows contains a * list of all the row numbers returned. */ public void tag_sql(RewriteContext hr) { debug = hr.isTrue("debug"); boolean eval = hr.isTrue("eval"); String type = hr.get("type", "query"); boolean useIndex = hr.isTrue("index"); boolean zeroIndex = hr.isTrue("zeroIndex"); String na = hr.get("na", "n/a"); String pre = hr.get("prefix"); if (pre == null) { pre = prefix; } if (!pre.equals("") && pre.endsWith(".") == false) { pre+= "."; } int max=100; try { max = Integer.decode(hr.get("max", "100")).intValue(); } catch (Exception e) {} int timeout=0; try { timeout = Integer.decode(hr.get("timeout", "0")).intValue(); } catch (Exception e) {} debug(hr); hr.accumulate(false); hr.nextToken(); String query = hr.getBody(); hr.accumulate(true); hr.nextToken(); // eat the
Properties props = hr.request.props; if (eval) { query = Format.subst(props, query); } debug(hr, query); /* * The connection to the server might have timed out. If so * the connection will fail. If that happens, try to re-open the * connection. */ Statement stmt = null; ResultSet result = null; int updateCount = -1; ResultSetMetaData meta = null; boolean retry = false; try { stmt = doSQL(query, type, timeout); result = stmt.getResultSet(); if (result != null) { meta = result.getMetaData(); } updateCount = stmt.getUpdateCount(); } catch (SQLException e) { debug(hr, "Connection failed, will retry: " + e.getMessage()); retry = true; } /* * Now run the query, stuffing the results into the properties. * This is pretty stupid right now. The first column is used as * the "index" if useIndex is set. Otherwise a counter is used. */ try { if (retry) { con = setupSql(url, sqlProps); stmt = doSQL(query, type, timeout); result = stmt.executeQuery(query); if (result != null) { meta = result.getMetaData(); } updateCount = stmt.getUpdateCount(); } props.put(pre + "updateCount", "" + updateCount); if (meta == null || result==null) { return; } int rows = 0; int count = meta.getColumnCount(); StringBuffer list = null; props.put(pre + "columns", "" + count); if (!useIndex) { list = new StringBuffer(); } while (result != null && result.next() && rows++ < max) { String first; // name of property row if (useIndex) { first = result.getString(1); } else { first = "" + (zeroIndex ? rows-1 : rows); list.append(first).append(" "); } for(int i=(useIndex?2:1); i<=count; i++) { String name = deriveName(pre, meta, first, i); String value = result.getString(i); if (value == null) { value = na; } props.put(name,value); // debug(hr,name + "=" + value); } } if (list != null) { props.put(pre + "rows", list.toString()); } props.put(pre + "rowcount", "" + rows); } catch (SQLException e) { props.put(pre + "error", e.getMessage()); debug(hr, "Failed: " + e.getMessage()); hr.request.log(Server.LOG_DIAGNOSTIC, hr.prefix, e.getMessage()); props.put(pre + "rowcount", "0"); } } public Statement doSQL(String query, String type, int timeout) throws SQLException { Statement stmt = con.createStatement(); if (timeout > 0) { stmt.setQueryTimeout(timeout); } if (type.equals("query")) { stmt.executeQuery(query); } else if (type.equals("update")) { stmt.executeUpdate(query); } else if (type.equals("system")) { stmt.execute(query); } return stmt; } /** * Convenience method for deriving props names */ String deriveName(String prefix, ResultSetMetaData meta, String suffix, int i) { String table = "n/a"; String column = "n/a"; try { table = meta.getTableName(i); } catch (SQLException e) {} try { column = meta.getColumnName(i); } catch (SQLException e) {} String result = prefix + table + "." + column + "." + suffix; // System.out.println("Getting name: " + result); return result; } public void tag_slash_sql(RewriteContext hr) { // System.out.println("Got /sql tag"); } /** * Setup a connection to an SQL server. * Assume driver is already registered. */ public Connection setupSql(String url, Properties props) { Connection con = null; try { con = DriverManager.getConnection(url, props); } catch (SQLException e) { System.out.println("SQL Exception: " + e); e.printStackTrace(); } catch (Exception e) { System.out.println("Exception in SQL setup: " + e); e.printStackTrace(); } return con; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy