001: /*
002: * transformica 2
003: * Code generator
004: * Copyright (C) 2004 Hammurapi Group
005: *
006: * This program is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation; either
009: * version 2 of the License, or (at your option) any later version.
010: *
011: * This program is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: *
016: * You should have received a copy of the GNU Lesser General Public
017: * License along with this library; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
019: *
020: * URL: http://www.pavelvlasov.com/pv/content/menu.show@id=products.transformica.html
021: * e-Mail: support@hammurapi.biz
022: */
023: package biz.hammurapi.transformica.jdbc;
024:
025: import java.sql.Connection;
026: import java.sql.DriverManager;
027: import java.sql.SQLException;
028: import java.sql.Statement;
029:
030: import org.apache.tools.ant.BuildException;
031: import org.apache.tools.ant.Project;
032:
033: import biz.hammurapi.transformica.TransformSession;
034: import biz.hammurapi.transformica.TransformTask;
035: import biz.hammurapi.util.Visitable;
036:
037: /**
038: * Traverses rowset produced by query. Transformations are defined by nested channel elements.
039: * Velocity template engine is used for code generation. Current row is accessible through 'element' context object.
040: * Row's class is dynamically generated and has get<Field name> method for every field in a row.
041: * Thus field NAME can be addressed in a template as ${element.name} instead of ${element.getString("NAME")} as if java.sql.ResultSet
042: * were used.
043: * 'session' context object of type biz.hammurapi.transformica.TransformSession gives access to current Ant project and provides
044: * methods to include other templates or channels and to store information.
045: * <section name="Example" suppress-description="yes">
046: <pre>
047: <taskdef name="jdbctransform" classname="biz.hammurapi.transformica.jdbc.JdbcTask"><br/>
048: <tab/><classpath><br/>
049: <tab/><tab/><fileset dir="lib" includes="*.jar"/><br/>
050: <tab/></classpath><br/>
051: </taskdef><br/>
052: <br/>
053: <jdbctransform<br/>
054: <tab/>driver="org.hsqldb.jdbcDriver"<br/>
055: <tab/>url="jdbc:hsqldb:hsql://localhost"<br/>
056: <tab/>user="sa"<br/>
057: <tab/>password=""<br/>
058: ><br/>
059: <tab/><query>SELECT * FROM MYTABLE</query><br/>
060: <tab/><channel <br/>
061: <tab/><tab/>outputDir="generated"<br/>
062: <tab/><tab/>template="templates/jdbc.java"<br/>
063: <tab/><tab/>fileNameTemplate='$${element.name}.java' <br/>
064: <tab/>><br/>
065: <tab/><tab/><filetouchdetector fileInfoFile="fileInfo.txt" genRoot="generated"/><br/>
066: <tab/></channel><br/>
067: </jdbctransform><br/>
068: </pre></section>
069: * @ant.element name="jseltransform"
070: * @author Pavel Vlasov
071: */
072: public class JdbcTask extends TransformTask {
073: private QueryEntry query;
074: private String driver;
075: private String url;
076: private String user;
077: private String password;
078:
079: /**
080: * SQL query to execute
081: * @return
082: * @throws BuildException
083: * @ant.required
084: */
085: public QueryEntry createQuery() throws BuildException {
086: if (query != null) {
087: throw new BuildException("Query already set");
088: }
089: query = new QueryEntry();
090: return query;
091: }
092:
093: /**
094: * Connection string
095: * @ant.required
096: * @param url The connectionString to set.
097: */
098: public void setURL(String url) {
099: this .url = url;
100: }
101:
102: /**
103: * JDBC Driver class name
104: * @ant.required
105: * @param driver The driver to set.
106: */
107: public void setDriver(String driver) {
108: this .driver = driver;
109: }
110:
111: /**
112: * Password
113: * @ant.non-required
114: * @param password The password to set.
115: */
116: public void setPassword(String password) {
117: this .password = password;
118: }
119:
120: /**
121: * User name
122: * @ant.non-required
123: * @param userName The userName to set.
124: */
125: public void setUser(String userName) {
126: this .user = userName;
127: }
128:
129: private Connection connection;
130: private Statement statement;
131:
132: protected Visitable getModel(TransformSession session)
133: throws BuildException {
134: if (driver == null) {
135: throw new BuildException("Driver not set");
136: }
137:
138: try {
139: Class.forName(driver);
140: if (url == null) {
141: throw new BuildException("Connection URL is not set");
142: }
143:
144: if (query == null) {
145: throw new BuildException("Query not set");
146: }
147:
148: connection = user == null ? DriverManager
149: .getConnection(url) : DriverManager.getConnection(
150: url, user, password);
151:
152: statement = connection.createStatement();
153: ResultSetInvocationHandler rsih = new ResultSetInvocationHandler(
154: this .getClass().getClassLoader(), statement
155: .executeQuery(query.getText()), this );
156: return (Visitable) rsih.getProxy();
157: } catch (ClassNotFoundException e) {
158: throw new BuildException("Driver class not found", e);
159: } catch (SQLException e) {
160: throw new BuildException(e);
161: }
162: }
163:
164: public void execute() throws BuildException {
165: try {
166: super .execute();
167: } finally {
168: if (statement != null) {
169: try {
170: statement.close();
171: } catch (SQLException e) {
172: log("Could not close JDBC statement: " + e,
173: Project.MSG_WARN);
174: e.printStackTrace();
175: }
176: }
177:
178: if (connection != null) {
179: try {
180: connection.close();
181: } catch (SQLException e) {
182: log("Could not close JDBC connection: " + e,
183: Project.MSG_WARN);
184: e.printStackTrace();
185: }
186: }
187: }
188: }
189:
190: }
|