1 29 30 package com.caucho.amber.table; 31 32 import com.caucho.amber.AmberRuntimeException; 33 import com.caucho.amber.entity.AmberCompletion; 34 import com.caucho.amber.entity.Entity; 35 import com.caucho.amber.entity.EntityListener; 36 import com.caucho.amber.entity.TableInvalidateCompletion; 37 import com.caucho.amber.manager.AmberConnection; 38 import com.caucho.amber.manager.AmberPersistenceUnit; 39 import com.caucho.amber.type.RelatedType; 40 import com.caucho.amber.type.Type; 41 import com.caucho.config.ConfigException; 42 import com.caucho.config.LineConfigException; 43 import com.caucho.util.CharBuffer; 44 import com.caucho.util.L10N; 45 46 import javax.sql.DataSource ; 47 import java.sql.Connection ; 48 import java.sql.ResultSet ; 49 import java.sql.SQLException ; 50 import java.sql.Statement ; 51 import java.util.ArrayList ; 52 import java.util.Collections ; 53 54 57 public class Table { 58 private static final L10N L = new L10N(Table.class); 59 60 private String _name; 61 62 private String _configLocation; 63 64 private AmberPersistenceUnit _manager; 65 66 private RelatedType _type; 68 69 private ArrayList <Column> _columns = new ArrayList <Column>(); 70 71 private ArrayList <LinkColumns> _incomingLinks = new ArrayList <LinkColumns>(); 72 private ArrayList <LinkColumns> _outgoingLinks = new ArrayList <LinkColumns>(); 73 74 private ArrayList <Column> _idColumns = new ArrayList <Column>(); 75 private LinkColumns _dependentIdLink; 76 77 private boolean _isReadOnly; 78 private long _cacheTimeout = 250; 79 80 private ArrayList <EntityListener> _entityListeners 81 = new ArrayList <EntityListener>(); 82 83 private TableInvalidateCompletion _invalidateCompletion; 84 85 public Table(AmberPersistenceUnit manager, String name) 86 { 87 _manager = manager; 88 _name = name; 89 } 90 91 94 public String getName() 95 { 96 return _name; 97 } 98 99 102 public void setConfigLocation(String location) 103 { 104 _configLocation = location; 105 } 106 107 110 public String getLocation() 111 { 112 return _configLocation; 113 } 114 115 118 public AmberPersistenceUnit getAmberManager() 119 { 120 return _manager; 121 } 122 123 126 public void setType(RelatedType type) 127 { 128 if (_type == null) 129 _type = type; 130 } 131 132 135 public RelatedType getType() 136 { 137 return _type; 138 } 139 140 143 public boolean isReadOnly() 144 { 145 return _isReadOnly; 146 } 147 148 151 public void setReadOnly(boolean isReadOnly) 152 { 153 _isReadOnly = isReadOnly; 154 } 155 156 159 public long getCacheTimeout() 160 { 161 return _cacheTimeout; 162 } 163 164 167 public void setCacheTimeout(long timeout) 168 { 169 _cacheTimeout = timeout; 170 } 171 172 175 public Column createColumn(String name, Type type) 176 { 177 for (int i = 0; i < _columns.size(); i++) { 178 Column oldColumn = _columns.get(i); 179 180 if (oldColumn.getName().equals(name)) 181 return oldColumn; 182 } 183 184 Column column = new Column(this, name, type); 185 186 _columns.add(column); 187 Collections.sort(_columns, new ColumnCompare()); 188 189 return column; 190 } 191 192 195 public ForeignColumn createForeignColumn(String name, Column key) 196 { 197 for (int i = 0; i < _columns.size(); i++) { 198 Column oldColumn = _columns.get(i); 199 200 if (! oldColumn.getName().equals(name)) { 201 } 202 else if (oldColumn instanceof ForeignColumn) { 203 return (ForeignColumn) oldColumn; 205 } 206 else { 207 209 ForeignColumn column = new ForeignColumn(this, name, key); 210 _columns.set(i, column); 211 return column; 212 } 213 } 214 215 ForeignColumn column = new ForeignColumn(this, name, key); 216 217 _columns.add(column); 218 Collections.sort(_columns, new ColumnCompare()); 219 220 return column; 221 } 222 223 226 public Column addColumn(Column column) 227 { 228 for (int i = 0; i < _columns.size(); i++) { 229 Column oldColumn = _columns.get(i); 230 231 if (! oldColumn.getName().equals(column.getName())) { 232 } 233 else if (oldColumn instanceof ForeignColumn) 234 return oldColumn; 235 else if (column instanceof ForeignColumn) { 236 _columns.set(i, column); 237 return column; 238 } 239 else 240 return oldColumn; 241 } 242 243 _columns.add(column); 244 Collections.sort(_columns, new ColumnCompare()); 245 246 return column; 247 } 248 249 252 public ArrayList <Column> getColumns() 253 { 254 return _columns; 255 } 256 257 260 public boolean removeColumn(Column column) 261 { 262 return _columns.remove(column); 263 } 264 265 268 void addIncomingLink(LinkColumns link) 269 { 270 assert(! _incomingLinks.contains(link)); 271 272 _incomingLinks.add(link); 273 } 274 275 278 void addOutgoingLink(LinkColumns link) 279 { 280 assert(! _outgoingLinks.contains(link)); 281 282 _outgoingLinks.add(link); 283 } 284 285 288 public void addIdColumn(Column column) 289 { 290 _idColumns.add(column); 291 } 292 293 296 public ArrayList <Column> getIdColumns() 297 { 298 return _idColumns; 299 } 300 301 304 public void setDependentIdLink(LinkColumns link) 305 { 306 _dependentIdLink = link; 307 } 308 309 312 public LinkColumns getDependentIdLink() 313 { 314 return _dependentIdLink; 315 } 316 317 320 public void createDatabaseTable(AmberPersistenceUnit amberPersistenceUnit) 321 throws ConfigException 322 { 323 try { 324 DataSource ds = amberPersistenceUnit.getDataSource(); 325 Connection conn = ds.getConnection(); 326 try { 327 Statement stmt = conn.createStatement(); 328 329 try { 330 332 String sql = "select 1 from " + getName() + " o where 1=0"; 333 334 ResultSet rs = stmt.executeQuery(sql); 335 rs.close(); 336 return; 337 } catch (SQLException e) { 338 } 339 340 String createSQL = generateCreateTableSQL(amberPersistenceUnit); 341 342 stmt.executeUpdate(createSQL); 343 344 stmt.close(); 345 } finally { 346 conn.close(); 347 } 348 } catch (Exception e) { 349 throw error(e); 350 } 351 } 352 353 356 private String generateCreateTableSQL(AmberPersistenceUnit amberPersistenceUnit) 357 { 358 CharBuffer cb = new CharBuffer(); 359 360 cb.append("create table " + getName() + " ("); 361 362 boolean hasColumn = false; 363 for (Column column : _columns) { 364 String columnSQL = column.generateCreateTableSQL(amberPersistenceUnit); 365 366 if (columnSQL == null) { 367 } 368 else if (! hasColumn) { 369 hasColumn = true; 370 cb.append("\n " + columnSQL); 371 } 372 else { 373 cb.append(",\n " + columnSQL); 374 } 375 } 376 377 cb.append("\n)"); 378 379 return cb.close(); 380 } 381 382 385 public void validateDatabaseTable(AmberPersistenceUnit amberPersistenceUnit) 386 throws ConfigException 387 { 388 try { 389 DataSource ds = amberPersistenceUnit.getDataSource(); 390 Connection conn = ds.getConnection(); 391 try { 392 Statement stmt = conn.createStatement(); 393 394 try { 395 397 String sql = "select 1 from " + getName() + " o where 1=0"; 398 399 ResultSet rs = stmt.executeQuery(sql); 400 rs.close(); 401 } catch (SQLException e) { 402 throw error(L.l("'{0}' is not a valid database table. Either the table needs to be created or the create-database-tables attribute must be set.\n\n{1}", 403 getName(), e.toString()), e); 404 } 405 } finally { 406 conn.close(); 407 } 408 409 for (Column column : _columns) { 410 column.validateDatabase(amberPersistenceUnit); 411 } 412 } catch (ConfigException e) { 413 if (_type != null) 414 _type.setConfigException(e); 415 416 throw e; 417 } catch (Exception e) { 418 if (_type != null) 419 _type.setConfigException(e); 420 421 throw error(e); 422 } 423 } 424 425 428 public AmberCompletion getInvalidateCompletion() 429 { 430 if (_invalidateCompletion == null) 431 _invalidateCompletion = new TableInvalidateCompletion(getName()); 432 433 return _invalidateCompletion; 434 } 435 436 439 public AmberCompletion getUpdateCompletion() 440 { 441 return getInvalidateCompletion(); 442 } 443 444 447 public AmberCompletion getDeleteCompletion() 448 { 449 return getInvalidateCompletion(); 450 } 451 452 455 public void addEntityListener(EntityListener listener) 456 { 457 if (! _entityListeners.contains(listener)) 458 _entityListeners.add(listener); 459 } 460 461 464 public boolean hasListeners() 465 { 466 return _entityListeners.size() > 0; 467 } 468 469 472 public boolean isCascadeDelete() 473 { 474 for (int i = 0; i < _incomingLinks.size(); i++) { 476 LinkColumns link = _incomingLinks.get(i); 477 478 if (link.isSourceCascadeDelete()) 479 return true; 480 } 481 482 for (int i = 0; i < _outgoingLinks.size(); i++) { 484 LinkColumns link = _outgoingLinks.get(i); 485 486 if (link.isTargetCascadeDelete()) 487 return true; 488 } 489 490 return false; 491 } 492 493 496 public void beforeEntityDelete(AmberConnection aConn, Entity entity) 497 { 498 try { 499 for (int i = 0; i < _entityListeners.size(); i++) { 500 EntityListener listener = _entityListeners.get(i); 501 502 listener.beforeEntityDelete(aConn, entity); 503 } 504 506 for (int i = 0; i < _incomingLinks.size(); i++) { 507 LinkColumns link = _incomingLinks.get(i); 508 509 link.beforeTargetDelete(aConn, entity); 510 } 511 512 aConn.addCompletion(getDeleteCompletion()); 513 } catch (RuntimeException e) { 514 throw e; 515 } catch (Exception e) { 516 throw new AmberRuntimeException(e); 517 } 518 } 519 520 protected ConfigException error(String msg, Throwable e) 521 { 522 if (_configLocation != null) 523 return new LineConfigException(_configLocation + msg, e); 524 else 525 return new ConfigException(msg, e); 526 } 527 528 protected ConfigException error(Throwable e) 529 { 530 if (_configLocation != null) 531 return new LineConfigException(_configLocation + e.getMessage(), e); 532 else 533 return new ConfigException(e); 534 } 535 536 539 public String toString() 540 { 541 return "Table[" + getName() + "]"; 542 } 543 } 544 | Popular Tags |