001 // Copyright 2004, 2005 The Apache Software Foundation
002 //
003 // Licensed under the Apache License, Version 2.0 (the "License");
004 // you may not use this file except in compliance with the License.
005 // You may obtain a copy of the License at
006 //
007 // http://www.apache.org/licenses/LICENSE-2.0
008 //
009 // Unless required by applicable law or agreed to in writing, software
010 // distributed under the License is distributed on an "AS IS" BASIS,
011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012 // See the License for the specific language governing permissions and
013 // limitations under the License.
014
015 package org.apache.tapestry.contrib.jdbc;
016
017 import java.sql.Connection;
018 import java.sql.SQLException;
019 import java.sql.Timestamp;
020 import java.util.ArrayList;
021 import java.util.Calendar;
022 import java.util.Date;
023 import java.util.List;
024
025 /**
026 * Class for creating and executing JDBC statements. Allows statements to be assembled
027 * incrementally (like a {@link StringBuffer}), but also tracks parameters, shielding
028 * the developer from the differences between constructing and
029 * using a JDBC
030 * {@link java.sql.Statement} and
031 * a JDBC {@link java.sql.PreparedStatement}. This class is somewhat skewed towards
032 * Oracle, which works more efficiently with prepared staments than
033 * simple SQL.
034 *
035 * <p>In addition, implements {@link #toString()} in a useful way (you can see the
036 * SQL and parameters), which is invaluable when debugging.
037 *
038 * <p>{@link #addParameter(int)} (and all overloaded versions of it for scalar types)
039 * adds a "?" to the statement and records the parameter value.
040 *
041 * <p>{@link #addParameter(Integer)} (and all overloaded version of it for wrapper
042 * types) does the same ... unless the value is null, in which case "NULL" is
043 * inserted into the statement.
044 *
045 * <p>{@link #addParameterList(int[], String)} (and all overloaded versions of it)
046 * simply invokes the appropriate {@link #addParameter(int)}, adding the
047 * separator in between parameters.
048 *
049 * @author Howard Lewis Ship
050 *
051 **/
052
053 public class StatementAssembly
054 {
055 public static final String SEP = ", ";
056
057 private static final String NULL = "NULL";
058
059 private StringBuffer _buffer = new StringBuffer();
060
061 /**
062 * List of {@link IParameter}.
063 *
064 **/
065
066 private List _parameters;
067
068 private int _lineLength;
069 private int _maxLineLength = 80;
070 private int _indent = 5;
071
072 /**
073 * Default constructor; uses a maximum line length of 80 and an indent of 5.
074 *
075 **/
076
077 public StatementAssembly()
078 {
079 }
080
081 public StatementAssembly(int maxLineLength, int indent)
082 {
083 _maxLineLength = maxLineLength;
084 _indent = indent;
085 }
086
087 /**
088 * Clears the assembly, preparing it for re-use.
089 *
090 * @since 1.0.7
091 *
092 **/
093
094 public void clear()
095 {
096 _buffer.setLength(0);
097 _lineLength = 0;
098
099 if (_parameters != null)
100 _parameters.clear();
101 }
102
103 /**
104 * Maximum length of a line.
105 *
106 **/
107
108 public int getMaxLineLength()
109 {
110 return _maxLineLength;
111 }
112
113 /**
114 * Number of spaces to indent continuation lines by.
115 *
116 **/
117
118 public int getIndent()
119 {
120 return _indent;
121 }
122
123 /**
124 * Adds text to the current line, unless that would make the line too long, in
125 * which case a new line is started (and indented) before adding the text.
126 *
127 * <p>Text is added as-is, with no concept of quoting. To add arbitrary strings
128 * (such as in a where clause), use {@link #addParameter(String)}.
129 *
130 *
131 **/
132
133 public void add(String text)
134 {
135 int textLength;
136
137 textLength = text.length();
138
139 if (_lineLength + textLength > _maxLineLength)
140 {
141 _buffer.append('\n');
142
143 for (int i = 0; i < _indent; i++)
144 _buffer.append(' ');
145
146 _lineLength = _indent;
147 }
148
149 _buffer.append(text);
150 _lineLength += textLength;
151 }
152
153 public void add(short value)
154 {
155 add(Short.toString(value));
156 }
157
158 public void add(int value)
159 {
160 add(Integer.toString(value));
161 }
162
163 public void add(long value)
164 {
165 add(Long.toString(value));
166 }
167
168 public void add(float value)
169 {
170 add(Float.toString(value));
171 }
172
173 public void add(double value)
174 {
175 add(Double.toString(value));
176 }
177
178 /**
179 * Adds a date value to a {@link StatementAssembly} converting
180 * it to a {@link java.sql.Timestamp} first.
181 *
182 **/
183
184 public void addParameter(Date date)
185 {
186 if (date == null)
187 {
188 add("NULL");
189 return;
190 }
191
192 Calendar calendar = Calendar.getInstance();
193
194 calendar.setTime(date);
195 calendar.set(Calendar.MILLISECOND, 0);
196
197 Date adjusted = calendar.getTime();
198
199 Timestamp timestamp = new Timestamp(adjusted.getTime());
200
201 addParameter(timestamp);
202 }
203
204 /**
205 * Adds a separator (usually a comma and a space) to the current line, regardless
206 * of line length. This is purely aesthetic ... it just looks odd if a separator
207 * gets wrapped to a new line by itself.
208 *
209 **/
210
211 public void addSep(String text)
212 {
213 _buffer.append(text);
214 _lineLength += text.length();
215 }
216
217 /**
218 * Starts a new line, without indenting.
219 *
220 **/
221
222 public void newLine()
223 {
224 if (_buffer.length() != 0)
225 _buffer.append('\n');
226
227 _lineLength = 0;
228 }
229
230 /**
231 * Starts a new line, then adds the given text.
232 *
233 **/
234
235 public void newLine(String text)
236 {
237 if (_buffer.length() != 0)
238 _buffer.append('\n');
239
240 _buffer.append(text);
241
242 _lineLength = text.length();
243 }
244
245 public void addList(String[] items, String separator)
246 {
247 for (int i = 0; i < items.length; i++)
248 {
249 if (i > 0)
250 addSep(separator);
251
252 add(items[i]);
253 }
254 }
255
256 public void addParameterList(int[] items, String separator)
257 {
258 for (int i = 0; i < items.length; i++)
259 {
260 if (i > 0)
261 addSep(separator);
262
263 addParameter(items[i]);
264 }
265 }
266
267 public void addParameterList(Integer[] items, String separator)
268 {
269 for (int i = 0; i < items.length; i++)
270 {
271 if (i > 0)
272 addSep(separator);
273
274 addParameter(items[i]);
275 }
276 }
277
278 public void addParameterList(long[] items, String separator)
279 {
280 for (int i = 0; i < items.length; i++)
281 {
282 if (i > 0)
283 addSep(separator);
284
285 addParameter(items[i]);
286 }
287 }
288
289 public void addParameterList(Long[] items, String separator)
290 {
291 for (int i = 0; i < items.length; i++)
292 {
293 if (i > 0)
294 addSep(separator);
295
296 addParameter(items[i]);
297 }
298 }
299
300 public void addParameterList(String[] items, String separator)
301 {
302 for (int i = 0; i < items.length; i++)
303 {
304 if (i > 0)
305 addSep(separator);
306
307 addParameter(items[i]);
308 }
309 }
310
311 public void addParameterList(double[] items, String separator)
312 {
313 for (int i = 0; i < items.length; i++)
314 {
315 if (i > 0)
316 addSep(separator);
317
318 addParameter(items[i]);
319 }
320 }
321
322 public void addParameter(Object value)
323 {
324 if (value == null)
325 add(NULL);
326 else
327 addParameter(new ObjectParameter(value));
328 }
329
330 public void addParameter(Timestamp timestamp)
331 {
332 if (timestamp == null)
333 add(NULL);
334 else
335 addParameter(new TimestampParameter(timestamp));
336 }
337
338 public void addParameter(String value)
339 {
340 if (value == null)
341 add(NULL);
342 else
343 addParameter(new StringParameter(value));
344 }
345
346 public void addParameter(int value)
347 {
348 addParameter(new IntegerParameter(value));
349 }
350
351 public void addParameter(Integer value)
352 {
353 if (value == null)
354 add(NULL);
355 else
356 addParameter(value.intValue());
357 }
358
359 public void addParameter(long value)
360 {
361 addParameter(new LongParameter(value));
362 }
363
364 public void addParameter(Long value)
365 {
366 if (value == null)
367 add(NULL);
368 else
369 addParameter(value.longValue());
370 }
371
372 public void addParameter(float value)
373 {
374 addParameter(new FloatParameter(value));
375 }
376
377 public void addParameter(Float value)
378 {
379 if (value == null)
380 add(NULL);
381 else
382 addParameter(value.floatValue());
383 }
384
385 public void addParameter(double value)
386 {
387 addParameter(new DoubleParameter(value));
388 }
389
390 public void addParameter(Double value)
391 {
392 if (value == null)
393 add(NULL);
394 else
395 addParameter(value.doubleValue());
396 }
397
398 public void addParameter(short value)
399 {
400 addParameter(new ShortParameter(value));
401 }
402
403 public void addParameter(Short value)
404 {
405 if (value == null)
406 add(NULL);
407 else
408 addParameter(value.shortValue());
409 }
410
411 public void addParameter(boolean value)
412 {
413 addParameter(value ? BooleanParameter.TRUE : BooleanParameter.FALSE);
414 }
415
416 public void addParameter(Boolean value)
417 {
418 if (value == null)
419 add(NULL);
420 else
421 addParameter(value.booleanValue());
422 }
423
424 private void addParameter(IParameter parameter)
425 {
426 if (_parameters == null)
427 _parameters = new ArrayList();
428
429 _parameters.add(parameter);
430
431 add("?");
432 }
433
434 /**
435 * Creates and returns an {@link IStatement} based on the SQL and parameters
436 * acquired.
437 *
438 **/
439
440 public IStatement createStatement(Connection connection) throws SQLException
441 {
442 String sql = _buffer.toString();
443
444 if (_parameters == null || _parameters.isEmpty())
445 return new SimpleStatement(sql, connection);
446
447 return new ParameterizedStatement(sql, connection, _parameters);
448 }
449
450 public String toString()
451 {
452 StringBuffer buffer = new StringBuffer("StatementAssembly@");
453
454 buffer.append(Integer.toHexString(hashCode()));
455 buffer.append("[SQL=\n<");
456 buffer.append(_buffer);
457 buffer.append("\n>");
458
459 if (_parameters != null)
460 {
461 int count = _parameters.size();
462 for (int i = 0; i < count; i++)
463 {
464 Object parameter = _parameters.get(i);
465
466 buffer.append(" ?");
467 buffer.append(i + 1);
468 buffer.append('=');
469
470 buffer.append(parameter);
471 }
472 }
473
474 buffer.append(']');
475
476 return buffer.toString();
477 }
478 }