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 }