1 22 package org.jboss.ejb.plugins.cmp.jdbc; 23 24 import java.sql.Connection ; 25 import java.sql.PreparedStatement ; 26 import java.sql.ResultSet ; 27 import java.util.ArrayList ; 28 import java.util.Collection ; 29 import java.util.Iterator ; 30 import java.util.HashMap ; 31 import java.util.List ; 32 import java.util.Map ; 33 import java.util.Collections ; 34 import javax.ejb.EJBException ; 35 36 import org.jboss.ejb.plugins.cmp.jdbc.bridge.JDBCFieldBridge; 37 import org.jboss.ejb.plugins.cmp.jdbc.bridge.JDBCCMPFieldBridge; 38 import org.jboss.ejb.plugins.cmp.jdbc.bridge.JDBCCMRFieldBridge; 39 import org.jboss.ejb.plugins.cmp.jdbc.bridge.JDBCEntityBridge; 40 import org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCFunctionMappingMetaData; 41 import org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCReadAheadMetaData; 42 import org.jboss.logging.Logger; 43 import org.jboss.deployment.DeploymentException; 44 45 52 public final class JDBCLoadRelationCommand 53 { 54 private final JDBCStoreManager manager; 55 private final JDBCEntityBridge entity; 56 private final Logger log; 57 58 public JDBCLoadRelationCommand(JDBCStoreManager manager) 59 { 60 this.manager = manager; 61 this.entity = (JDBCEntityBridge) manager.getEntityBridge(); 62 63 log = Logger.getLogger( 65 this.getClass().getName() + 66 "." + 67 manager.getMetaData().getName()); 68 } 69 70 public Collection execute(JDBCCMRFieldBridge cmrField, Object pk) 71 { 72 JDBCCMRFieldBridge relatedCMRField = (JDBCCMRFieldBridge) cmrField.getRelatedCMRField(); 73 74 ReadAheadCache readAheadCache = manager.getReadAheadCache(); 76 ReadAheadCache relatedReadAheadCache = cmrField.getRelatedManager().getReadAheadCache(); 77 78 ReadAheadCache.EntityReadAheadInfo info = readAheadCache.getEntityReadAheadInfo(pk); 80 List loadKeys = info.getLoadKeys(); 81 82 Connection con = null; 83 PreparedStatement ps = null; 84 ResultSet rs = null; 85 try 86 { 87 boolean[] preloadMask = getPreloadMask(cmrField); 89 String sql = getSQL(cmrField, preloadMask, loadKeys.size()); 90 91 if(log.isDebugEnabled()) 93 log.debug("load relation SQL: " + sql); 94 95 con = cmrField.getDataSource().getConnection(); 97 ps = con.prepareStatement(sql.toString()); 98 99 if(entity.getFetchSize() > 0) 101 { 102 ps.setFetchSize(entity.getFetchSize()); 103 } 104 105 JDBCCMPFieldBridge[] myKeyFields = getMyKeyFields(cmrField); 107 JDBCCMPFieldBridge[] relatedKeyFields = getRelatedKeyFields(cmrField); 108 109 int paramIndex = 1; 111 for(int i = 0; i < loadKeys.size(); i++) 112 { 113 Object key = loadKeys.get(i); 114 for(int j = 0; j < myKeyFields.length; ++j) 115 paramIndex = myKeyFields[j].setPrimaryKeyParameters(ps, paramIndex, key); 116 } 117 118 rs = ps.executeQuery(); 120 121 Map resultsMap = new HashMap (loadKeys.size()); 123 for(int i = 0; i < loadKeys.size(); ++i) 124 { 125 resultsMap.put(loadKeys.get(i), new ArrayList ()); 126 } 127 128 Object [] ref = new Object [1]; 130 while(rs.next()) 131 { 132 int index = 1; 134 135 ref[0] = null; 137 138 Object loadedPk = pk; 140 if(loadKeys.size() > 1) 141 { 142 for(int i = 0; i < myKeyFields.length; ++i) 144 { 145 index = myKeyFields[i].loadPrimaryKeyResults(rs, index, ref); 146 if(ref[0] == null) 147 { 148 break; 149 } 150 } 151 loadedPk = ref[0]; 152 } 153 154 ref[0] = null; 156 for(int i = 0; i < relatedKeyFields.length; ++i) 157 { 158 index = relatedKeyFields[i].loadPrimaryKeyResults(rs, index, ref); 159 if(ref[0] == null) 160 { 161 break; 162 } 163 } 164 Object loadedFk = ref[0]; 165 166 if(loadedFk != null) 167 { 168 List results = (List )resultsMap.get(loadedPk); 170 results.add(loadedFk); 171 172 if(relatedCMRField.isSingleValued()) 175 { 176 relatedReadAheadCache.addPreloadData( 177 loadedFk, 178 relatedCMRField, 179 Collections.singletonList(loadedPk)); 180 } 181 182 if(preloadMask != null) 184 { 185 JDBCFieldBridge[] relatedFields = cmrField.getRelatedJDBCEntity().getTableFields(); 186 for(int i = 0; i < relatedFields.length; ++i) 187 { 188 if(preloadMask[i]) 189 { 190 JDBCFieldBridge field = relatedFields[i]; 191 ref[0] = null; 192 193 index = field.loadArgumentResults(rs, index, ref); 195 relatedReadAheadCache.addPreloadData(loadedFk, field, ref[0]); 196 } 197 } 198 } 199 } 200 } 201 202 JDBCReadAheadMetaData readAhead = relatedCMRField.getReadAhead(); 204 for(Iterator iter = resultsMap.keySet().iterator(); iter.hasNext();) 205 { 206 Object key = iter.next(); 207 208 List results = (List )resultsMap.get(key); 210 211 relatedReadAheadCache.addFinderResults(results, readAhead); 213 214 if(!key.equals(pk)) 217 { 218 readAheadCache.addPreloadData(key, cmrField, results); 219 } 220 } 221 222 return (List )resultsMap.get(pk); 224 } 225 catch(EJBException e) 226 { 227 throw e; 228 } 229 catch(Exception e) 230 { 231 throw new EJBException ("Load relation failed", e); 232 } 233 finally 234 { 235 JDBCUtil.safeClose(rs); 236 JDBCUtil.safeClose(ps); 237 JDBCUtil.safeClose(con); 238 } 239 } 240 241 private String getSQL(JDBCCMRFieldBridge cmrField, boolean[] preloadMask, int keyCount) throws DeploymentException 242 { 243 JDBCCMPFieldBridge[] myKeyFields = getMyKeyFields(cmrField); 244 JDBCCMPFieldBridge[] relatedKeyFields = getRelatedKeyFields(cmrField); 245 String relationTable = getQualifiedRelationTable(cmrField); 246 JDBCEntityBridge relatedEntity = cmrField.getRelatedJDBCEntity(); 247 String relatedTable = relatedEntity.getQualifiedTableName(); 248 249 boolean join = ((preloadMask != null) || cmrField.allFkFieldsMappedToPkFields()) 251 && (relatedKeyFields != relatedEntity.getPrimaryKeyFields()); 252 253 String relationTableAlias; 255 String relatedTableAlias; 256 if(join) 257 { 258 relationTableAlias = getRelationTable(cmrField); 259 relatedTableAlias = ( 260 relatedTable.equals(relationTable) ? getRelationTable(cmrField) + '_' + cmrField.getFieldName() : relatedEntity.getTableName() 261 ); 262 } 263 else 264 { 265 relationTableAlias = ""; 266 relatedTableAlias = ""; 267 } 268 269 JDBCFunctionMappingMetaData selectTemplate = getSelectTemplate(cmrField); 270 return selectTemplate == null ? 271 getPlainSQL( 272 keyCount, 273 myKeyFields, 274 relationTableAlias, 275 relatedKeyFields, 276 preloadMask, 277 cmrField, 278 relatedTableAlias, 279 relationTable, 280 join, 281 relatedTable) 282 : 283 getSQLByTemplate( 284 keyCount, 285 myKeyFields, 286 relationTableAlias, 287 relatedKeyFields, 288 preloadMask, 289 cmrField, 290 relatedTableAlias, 291 relationTable, 292 join, 293 relatedTable, 294 selectTemplate); 295 } 296 297 private JDBCCMPFieldBridge[] getMyKeyFields(JDBCCMRFieldBridge cmrField) 298 { 299 if(cmrField.getRelationMetaData().isTableMappingStyle()) 300 { 301 return (JDBCCMPFieldBridge[]) cmrField.getTableKeyFields(); 303 } 304 else if(cmrField.getRelatedCMRField().hasForeignKey()) 305 { 306 return (JDBCCMPFieldBridge[]) cmrField.getRelatedCMRField().getForeignKeyFields(); 308 } 309 else 310 { 311 return (JDBCCMPFieldBridge[])entity.getPrimaryKeyFields(); 313 } 314 } 315 316 private static JDBCCMPFieldBridge[] getRelatedKeyFields(JDBCCMRFieldBridge cmrField) 317 { 318 if(cmrField.getRelationMetaData().isTableMappingStyle()) 319 { 320 return (JDBCCMPFieldBridge[]) cmrField.getRelatedCMRField().getTableKeyFields(); 322 } 323 else if(cmrField.getRelatedCMRField().hasForeignKey()) 324 { 325 return (JDBCCMPFieldBridge[])cmrField.getRelatedJDBCEntity().getPrimaryKeyFields(); 327 } 328 else 329 { 330 return (JDBCCMPFieldBridge[]) cmrField.getForeignKeyFields(); 332 } 333 } 334 335 private static boolean[] getPreloadMask(JDBCCMRFieldBridge cmrField) 336 { 337 boolean[] preloadMask = null; 338 if(cmrField.getReadAhead().isOnFind()) 339 { 340 JDBCEntityBridge relatedEntity = cmrField.getRelatedJDBCEntity(); 341 String eagerLoadGroup = cmrField.getReadAhead().getEagerLoadGroup(); 342 preloadMask = relatedEntity.getLoadGroupMask(eagerLoadGroup); 343 } 344 return preloadMask; 345 } 346 347 private String getQualifiedRelationTable(JDBCCMRFieldBridge cmrField) 348 { 349 if(cmrField.getRelationMetaData().isTableMappingStyle()) 350 { 351 return cmrField.getQualifiedTableName(); 353 } 354 else if(cmrField.getRelatedCMRField().hasForeignKey()) 355 { 356 return cmrField.getRelatedJDBCEntity().getQualifiedTableName(); 358 } 359 else 360 { 361 return entity.getQualifiedTableName(); 363 } 364 } 365 366 private String getRelationTable(JDBCCMRFieldBridge cmrField) 367 { 368 if(cmrField.getRelationMetaData().isTableMappingStyle()) 369 { 370 return cmrField.getTableName(); 372 } 373 else if(cmrField.getRelatedCMRField().hasForeignKey()) 374 { 375 return cmrField.getRelatedJDBCEntity().getTableName(); 377 } 378 else 379 { 380 return entity.getTableName(); 382 } 383 } 384 385 private JDBCFunctionMappingMetaData getSelectTemplate(JDBCCMRFieldBridge cmrField) throws DeploymentException 386 { 387 388 JDBCFunctionMappingMetaData selectTemplate = null; 389 if(cmrField.getRelationMetaData().isTableMappingStyle()) 390 { 391 if(cmrField.getRelationMetaData().hasRowLocking()) 393 { 394 selectTemplate = 395 cmrField.getRelationMetaData().getTypeMapping().getRowLockingTemplate(); 396 if(selectTemplate == null) 397 { 398 throw new IllegalStateException ( 399 "row-locking is not allowed for this type of datastore"); 400 } 401 } 402 } 403 else if(cmrField.getRelatedCMRField().hasForeignKey()) 404 { 405 if(cmrField.getRelatedJDBCEntity().getMetaData().hasRowLocking()) 407 { 408 selectTemplate = 409 cmrField.getRelatedJDBCEntity().getMetaData().getTypeMapping().getRowLockingTemplate(); 410 if(selectTemplate == null) 411 { 412 throw new IllegalStateException ( 413 "row-locking is not allowed for this type of datastore"); 414 } 415 } 416 } 417 else 418 { 419 if(entity.getMetaData().hasRowLocking()) 421 { 422 selectTemplate = entity.getMetaData().getTypeMapping().getRowLockingTemplate(); 423 if(selectTemplate == null) 424 { 425 throw new IllegalStateException ( 426 "row-locking is not allowed for this type of datastore"); 427 } 428 } 429 } 430 return selectTemplate; 431 } 432 433 private static String getPlainSQL(int keyCount, 434 JDBCCMPFieldBridge[] myKeyFields, 435 String relationTableAlias, 436 JDBCCMPFieldBridge[] relatedKeyFields, 437 boolean[] preloadMask, 438 JDBCCMRFieldBridge cmrField, 439 String relatedTableAlias, 440 String relationTable, 441 boolean join, 442 String relatedTable) 443 { 444 StringBuffer sql = new StringBuffer (400); 448 sql.append(SQLUtil.SELECT); 449 450 if(keyCount > 1) 451 { 452 SQLUtil.getColumnNamesClause(myKeyFields, relationTableAlias, sql) 453 .append(SQLUtil.COMMA); 454 } 455 SQLUtil.getColumnNamesClause(relatedKeyFields, relationTableAlias, sql); 456 457 if(preloadMask != null) 458 { 459 SQLUtil.appendColumnNamesClause( 460 cmrField.getRelatedJDBCEntity().getTableFields(), 461 preloadMask, 462 relatedTableAlias, 463 sql); 464 } 465 466 sql.append(SQLUtil.FROM).append(relationTable); 470 if(join) 471 { 472 sql.append(' ') 473 .append(relationTableAlias) 474 .append(SQLUtil.COMMA) 475 .append(relatedTable) 476 .append(' ') 477 .append(relatedTableAlias); 478 } 479 480 sql.append(SQLUtil.WHERE); 484 if(join) 486 { 487 sql.append('('); 489 SQLUtil.getJoinClause( 490 relatedKeyFields, 491 relationTableAlias, 492 cmrField.getRelatedJDBCEntity().getPrimaryKeyFields(), 493 relatedTableAlias, 494 sql) 495 .append(')') 496 .append(SQLUtil.AND) 497 .append('('); 498 } 499 500 String pkWhere = SQLUtil.getWhereClause(myKeyFields, relationTableAlias, new StringBuffer (50)).toString(); 502 for(int i = 0; i < keyCount; i++) 503 { 504 if(i > 0) 505 sql.append(SQLUtil.OR); 506 sql.append('(').append(pkWhere).append(')'); 507 } 508 509 if(join) 510 sql.append(')'); 511 512 return sql.toString(); 513 } 514 515 private static String getSQLByTemplate(int keyCount, 516 JDBCCMPFieldBridge[] myKeyFields, 517 String relationTableAlias, 518 JDBCCMPFieldBridge[] relatedKeyFields, 519 boolean[] preloadMask, 520 JDBCCMRFieldBridge cmrField, 521 String relatedTableAlias, 522 String relationTable, 523 boolean join, 524 String relatedTable, 525 JDBCFunctionMappingMetaData selectTemplate) 526 { 527 StringBuffer columnNamesClause = new StringBuffer (100); 531 if(keyCount > 1) 532 { 533 SQLUtil.getColumnNamesClause(myKeyFields, relationTableAlias, columnNamesClause) 534 .append(SQLUtil.COMMA); 535 } 536 SQLUtil.getColumnNamesClause(relatedKeyFields, relationTableAlias, columnNamesClause); 537 if(preloadMask != null) 538 { 539 SQLUtil.appendColumnNamesClause( 540 cmrField.getRelatedJDBCEntity().getTableFields(), 541 preloadMask, 542 relatedTableAlias, 543 columnNamesClause); 544 } 545 546 StringBuffer fromClause = new StringBuffer (100); 550 fromClause.append(relationTable); 551 if(join) 552 { 553 fromClause.append(' ') 554 .append(relationTableAlias) 555 .append(SQLUtil.COMMA) 556 .append(relatedTable) 557 .append(' ') 558 .append(relatedTableAlias); 559 } 560 561 StringBuffer whereClause = new StringBuffer (150); 565 if(join) 567 { 568 whereClause.append('('); 570 SQLUtil.getJoinClause( 571 relatedKeyFields, 572 relationTableAlias, 573 cmrField.getRelatedJDBCEntity().getPrimaryKeyFields(), 574 relatedTableAlias, 575 whereClause) 576 .append(')') 577 .append(SQLUtil.AND) 578 .append('('); 579 } 580 581 String pkWhere = SQLUtil.getWhereClause(myKeyFields, relationTableAlias, new StringBuffer (50)).toString(); 583 for(int i = 0; i < keyCount; i++) 584 { 585 if(i > 0) 586 { 587 whereClause.append(SQLUtil.OR); 588 } 589 whereClause.append('(').append(pkWhere).append(')'); 590 } 591 592 if(join) 593 { 594 whereClause.append(')'); 595 } 596 597 String [] args = new String []{ 601 columnNamesClause.toString(), 602 fromClause.toString(), 603 whereClause.toString(), 604 null }; 606 return selectTemplate.getFunctionSql(args, new StringBuffer (500)).toString(); 607 } 608 } 609 | Popular Tags |