Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: org/apache/taglibs/standard/tag/common/sql/QueryTagSupport.java


1   /*
2    * Copyright 1999-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.taglibs.standard.tag.common.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.util.ArrayList;
24  import java.util.List;
25  
26  import javax.servlet.jsp.JspException;
27  import javax.servlet.jsp.JspTagException;
28  import javax.servlet.jsp.PageContext;
29  import javax.servlet.jsp.jstl.core.Config;
30  import javax.servlet.jsp.jstl.sql.Result;
31  import javax.servlet.jsp.jstl.sql.SQLExecutionTag;
32  import javax.servlet.jsp.tagext.BodyTagSupport;
33  import javax.servlet.jsp.tagext.TryCatchFinally;
34  import javax.sql.DataSource;
35  
36  import org.apache.taglibs.standard.resources.Resources;
37  import org.apache.taglibs.standard.tag.common.core.Util;
38  
39  
40  /**
41   * <p>Tag handler for &lt;Query&gt; in JSTL.  
42   * 
43   * @author Hans Bergsten
44   * @author Justyna Horwat
45   */
46  
47  public abstract class QueryTagSupport extends BodyTagSupport 
48      implements TryCatchFinally, SQLExecutionTag {
49  
50      private String var;
51      private int scope;
52  
53      /*
54       * The following properties take expression values, so the
55       * setter methods are implemented by the expression type
56       * specific subclasses.
57       */
58      protected Object rawDataSource;
59      protected boolean dataSourceSpecified;
60      protected String sql;
61      protected int maxRows;
62      protected boolean maxRowsSpecified;
63      protected int startRow;
64  
65      /*
66       * Instance variables that are not for attributes
67       */
68      private Connection conn;
69      private List parameters;
70      private boolean isPartOfTransaction;
71  
72  
73      //*********************************************************************
74      // Constructor and initialization
75  
76      public QueryTagSupport() {
77          super();
78          init();
79      }
80  
81      private void init() {
82          startRow = 0;
83          maxRows = -1;
84    maxRowsSpecified = dataSourceSpecified = false;
85    isPartOfTransaction = false;
86    conn = null;
87    rawDataSource = null;
88    parameters = null;
89    sql = null;
90    var = null;
91          scope = PageContext.PAGE_SCOPE;
92      }
93  
94  
95      //*********************************************************************
96      // Accessor methods
97  
98      /**
99       * Setter method for the name of the variable to hold the
100      * result.
101      */
102     public void setVar(String var) {
103   this.var = var;
104     }
105 
106     /**
107      * Setter method for the scope of the variable to hold the
108      * result.
109      */
110     public void setScope(String scopeName) {
111         scope = Util.getScope(scopeName);
112     }
113 
114     //*********************************************************************
115     // Public utility methods
116 
117     /**
118      * Called by nested parameter elements to add PreparedStatement
119      * parameter values.
120      */
121     public void addSQLParameter(Object o) {
122   if (parameters == null) {
123       parameters = new ArrayList();
124   }
125   parameters.add(o);
126     }
127 
128     //*********************************************************************
129     // Tag logic
130 
131     /**
132      * Prepares for execution by setting the initial state, such as
133      * getting the <code>Connection</code>
134      */
135     public int doStartTag() throws JspException {
136 
137         if (!maxRowsSpecified) {
138       Object obj = Config.find(pageContext, Config.SQL_MAX_ROWS);
139       if (obj != null) {
140     if (obj instanceof Integer) {
141         maxRows = ((Integer) obj).intValue();
142     } else if (obj instanceof String) {
143         try {
144       maxRows = Integer.parseInt((String) obj);
145         } catch (NumberFormatException nfe) {
146       throw new JspException(
147           Resources.getMessage("SQL_MAXROWS_PARSE_ERROR",
148              (String) obj),
149           nfe);
150         }
151     } else {
152         throw new JspException(
153                         Resources.getMessage("SQL_MAXROWS_INVALID"));
154     }
155             }
156         }
157 
158   try {
159       conn = getConnection();
160   } catch (SQLException e) {
161       throw new JspException(sql + ": " + e.getMessage(), e);
162   }
163 
164   return EVAL_BODY_BUFFERED;
165     }
166 
167     /**
168      * <p>Execute the SQL statement, set either through the <code>sql</code>
169      * attribute or as the body, and save the result as a variable
170      * named by the <code>var</code> attribute in the scope specified
171      * by the <code>scope</code> attribute, as an object that implements
172      * the Result interface.
173      *
174      * <p>The connection used to execute the statement comes either
175      * from the <code>DataSource</code> specified by the
176      * <code>dataSource</code> attribute, provided by a parent action
177      * element, or is retrieved from a JSP scope  attribute
178      * named <code>javax.servlet.jstl.sql.dataSource</code>.
179      */
180     public int doEndTag() throws JspException {
181   /*
182    * Use the SQL statement specified by the sql attribute, if any,
183    * otherwise use the body as the statement.
184    */
185   String sqlStatement = null;
186   if (sql != null) {
187       sqlStatement = sql;
188   }
189   else if (bodyContent != null) {
190       sqlStatement = bodyContent.getString();
191   }
192   if (sqlStatement == null || sqlStatement.trim().length() == 0) {
193       throw new JspTagException(
194                 Resources.getMessage("SQL_NO_STATEMENT"));
195   }
196         /*
197          * We shouldn't have a negative startRow or illegal maxrows
198          */
199         if ((startRow < 0) || (maxRows < -1)) {
200             throw new JspException(
201                 Resources.getMessage("PARAM_BAD_VALUE"));
202         }
203 
204   Result result = null;
205   /* 
206    * Note! We must not use the setMaxRows() method on the
207    * the statement to limit the number of rows, since the
208    * Result factory must be able to figure out the correct
209    * value for isLimitedByMaxRows(); there's no way to check
210    * if it was from the ResultSet.
211           */
212   try {
213       PreparedStatement ps = conn.prepareStatement(sqlStatement);
214       setParameters(ps, parameters);
215       ResultSet rs = ps.executeQuery();
216       result = new ResultImpl(rs, startRow, maxRows);
217             ps.close();
218   }
219   catch (Throwable e) {
220       throw new JspException(sqlStatement + ": " + e.getMessage(), e);
221   }
222   pageContext.setAttribute(var, result, scope);
223   return EVAL_PAGE;
224     }
225 
226     /**
227      * Just rethrows the Throwable.
228      */
229     public void doCatch(Throwable t) throws Throwable {
230   throw t;
231     }
232 
233     /**
234      * Close the <code>Connection</code>, unless this action is used
235      * as part of a transaction.
236      */
237     public void doFinally() {
238   if (conn != null && !isPartOfTransaction) {
239       try {
240     conn.close();
241       } catch (SQLException e) {} // Not much we can do
242   }
243 
244   conn = null;
245   parameters = null;
246     }
247 
248 
249     //*********************************************************************
250     // Private utility methods
251 
252     private Connection getConnection() throws JspException, SQLException {
253   // Fix: Add all other mechanisms
254   Connection conn = null;
255   isPartOfTransaction = false;
256 
257   TransactionTagSupport parent = (TransactionTagSupport) 
258       findAncestorWithClass(this, TransactionTagSupport.class);
259   if (parent != null) {
260             if (dataSourceSpecified) {
261                 throw new JspTagException(
262                     Resources.getMessage("ERROR_NESTED_DATASOURCE"));
263             }
264       conn = parent.getSharedConnection();
265             isPartOfTransaction = true;
266   } else {
267       if ((rawDataSource == null) && dataSourceSpecified) {
268     throw new JspException(
269         Resources.getMessage("SQL_DATASOURCE_NULL"));
270       }
271       DataSource dataSource = DataSourceUtil.getDataSource(rawDataSource,
272                  pageContext);
273             try {
274           conn = dataSource.getConnection();
275             } catch (Exception ex) {
276                 throw new JspException(
277                     Resources.getMessage("DATASOURCE_INVALID", 
278                                          ex.toString()));
279             }
280   }
281 
282   return conn;
283     }
284 
285     private void setParameters(PreparedStatement ps, List parameters) 
286         throws SQLException
287     {
288   if (parameters != null) {
289       for (int i = 0; i < parameters.size(); i++) {
290                 /* The first parameter has index 1.  If a null
291                  * is passed to setObject the parameter will be
292                  * set to JDBC null so an explicit call to
293                  * ps.setNull is not required.
294                  */
295     ps.setObject(i + 1, parameters.get(i));
296       }
297   }
298     }
299 }