1 /*
2 * Copyright 2002,2004 The Apache Software Foundation.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package org.apache.commons.jelly.tags.sql;
18
19 import java.sql.Connection;
20 import java.sql.PreparedStatement;
21 import java.sql.ResultSet;
22 import java.sql.SQLException;
23 import java.sql.Statement;
24
25 import javax.servlet.jsp.jstl.sql.Result;
26
27 import org.apache.commons.jelly.JellyTagException;
28 import org.apache.commons.jelly.XMLOutput;
29 import org.apache.commons.jelly.tags.Resources;
30 import org.apache.commons.logging.Log;
31 import org.apache.commons.logging.LogFactory;
32
33
34 /***
35 * <p>Tag handler for <Query> in JSTL.
36 *
37 * @author Hans Bergsten
38 * @author Justyna Horwat
39 */
40
41 public class QueryTag extends SqlTagSupport {
42
43 /*** The Log to which logging calls will be made. */
44 private static final Log log = LogFactory.getLog(QueryTag.class);
45
46
47
48
49
50
51 protected int maxRows = -1;
52 protected boolean maxRowsSpecified;
53 protected int startRow;
54
55
56
57
58 private Connection conn;
59
60 //**********************************************************************
61 // Constructor and initialization
62
63 public QueryTag() {
64 }
65
66 //*********************************************************************
67 // Accessor methods
68
69 /**
70 * The index of the first row returned can be
71 * specified using startRow.
72 */
73 public void setStartRow(int startRow) {
74 this.startRow = startRow;
75 }
76
77 /***
78 * Query result can be limited by specifying
79 * the maximum number of rows returned.
80 */
81 public void setMaxRows(int maxRows) {
82 this.maxRows = maxRows;
83 this.maxRowsSpecified = true;
84 }
85
86 //**********************************************************************
87 // Tag logic
88
89 /**
90 * <p>Execute the SQL statement, set either through the <code>sql</code>
91 * attribute or as the body, and save the result as a variable
92 * named by the <code>var</code> attribute in the scope specified
93 * by the <code>scope</code> attribute, as an object that implements
94 * the Result interface.
95 *
96 * <p>The connection used to execute the statement comes either
97 * from the <code>DataSource</code> specified by the
98 * <code>dataSource</code> attribute, provided by a parent action
99 * element, or is retrieved from a JSP scope attribute
100 * named <code>javax.servlet.jstl.sql.dataSource</code>.
101 */
102 public void doTag(XMLOutput output) throws JellyTagException {
103
104 if (!maxRowsSpecified) {
105 Object obj = context.getVariable("org.apache.commons.jelly.sql.maxRows");
106 if (obj != null) {
107 if (obj instanceof Integer) {
108 maxRows = ((Integer) obj).intValue();
109 }
110 else if (obj instanceof String) {
111 try {
112 maxRows = Integer.parseInt((String) obj);
113 }
114 catch (NumberFormatException nfe) {
115 throw new JellyTagException(
116 Resources.getMessage("SQL_MAXROWS_PARSE_ERROR", (String) obj),
117 nfe);
118 }
119 }
120 else {
121 throw new JellyTagException(Resources.getMessage("SQL_MAXROWS_INVALID"));
122 }
123 }
124 }
125
126 Result result = null;
127 String sqlStatement = null;
128
129 log.debug( "About to lookup connection" );
130
131 ResultSet rs = null;
132 Statement statement = null;
133 try {
134 conn = getConnection();
135
136
137
138
139
140 if (sql != null) {
141 sqlStatement = sql;
142 }
143 else {
144 sqlStatement = getBodyText();
145 }
146 if (sqlStatement == null || sqlStatement.trim().length() == 0) {
147 throw new JellyTagException(Resources.getMessage("SQL_NO_STATEMENT"));
148 }
149
150
151
152 if ((startRow < 0) || (maxRows < -1)) {
153 throw new JellyTagException(Resources.getMessage("PARAM_BAD_VALUE"));
154 }
155
156
157
158
159
160
161
162
163 if ( log.isDebugEnabled() ) {
164 log.debug( "About to execute query: " + sqlStatement );
165 }
166
167 if ( hasParameters() ) {
168 PreparedStatement ps = conn.prepareStatement(sqlStatement);
169 statement = ps;
170 setParameters(ps);
171 rs = ps.executeQuery();
172 }
173 else {
174 statement = conn.createStatement();
175 rs = statement.executeQuery(sqlStatement);
176 }
177
178 result = new ResultImpl(rs, startRow, maxRows);
179 context.setVariable(var, result);
180
181
182
183
184
185
186 ResultSet tempRs = rs;
187 rs = null;
188 tempRs.close();
189 Statement tempStatement = statement;
190 statement = null;
191 tempStatement.close();
192 }
193 catch (SQLException e) {
194 throw new JellyTagException(sqlStatement + ": " + e.getMessage(), e);
195 }
196 finally {
197 if (rs != null) {
198 try {
199 rs.close();
200 }
201 catch (SQLException e) {
202 log.error("Caught exception while closing result set: " + e, e);
203 }
204 }
205 if (statement != null) {
206 try {
207 statement.close();
208 }
209 catch (SQLException e) {
210 log.error("Caught exception while closing statement: " + e, e);
211 }
212 }
213 if (conn != null && !isPartOfTransaction) {
214 try {
215 conn.close();
216 }
217 catch (SQLException e) {
218 log.error("Caught exception while closing connection: " + e, e);
219 }
220 conn = null;
221 }
222 clearParameters();
223 }
224 }
225 }