1 22 package org.jboss.ejb.plugins.cmp.jdbc.bridge; 23 24 import java.sql.PreparedStatement ; 25 import java.sql.ResultSet ; 26 27 import java.util.ArrayList ; 28 import java.util.Collection ; 29 import java.util.Collections ; 30 import java.util.HashMap ; 31 import java.util.Iterator ; 32 import java.util.List ; 33 import java.util.Map ; 34 import java.util.Arrays ; 35 import java.util.NoSuchElementException ; 36 import java.rmi.RemoteException ; 37 38 import javax.ejb.EJBException ; 39 import javax.ejb.RemoveException ; 40 import javax.sql.DataSource ; 41 import javax.naming.InitialContext ; 42 import javax.naming.NamingException ; 43 44 import org.jboss.deployment.DeploymentException; 45 import org.jboss.ejb.EntityEnterpriseContext; 46 47 import org.jboss.ejb.plugins.cmp.jdbc.JDBCContext; 48 import org.jboss.ejb.plugins.cmp.jdbc.JDBCStoreManager; 49 import org.jboss.ejb.plugins.cmp.jdbc.SQLUtil; 50 import org.jboss.ejb.plugins.cmp.jdbc.LockingStrategy; 51 import org.jboss.ejb.plugins.cmp.jdbc.JDBCTypeFactory; 52 import org.jboss.ejb.plugins.cmp.jdbc.JDBCEntityPersistenceStore; 53 54 import org.jboss.ejb.plugins.cmp.bridge.EntityBridgeInvocationHandler; 55 import org.jboss.ejb.plugins.cmp.bridge.FieldBridge; 56 57 import org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCAuditMetaData; 58 import org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCEntityMetaData; 59 import org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCCMPFieldMetaData; 60 import org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCQueryMetaData; 61 import org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCRelationshipRoleMetaData; 62 import org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCOptimisticLockingMetaData; 63 import org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCReadAheadMetaData; 64 import org.jboss.proxy.compiler.Proxies; 65 import org.jboss.proxy.compiler.InvocationHandler; 66 import org.jboss.logging.Logger; 67 68 69 84 public class JDBCEntityBridge implements JDBCAbstractEntityBridge 85 { 86 public final static byte LOADED = 1; 87 public final static byte LOAD_REQUIRED = 2; 88 public final static byte DIRTY = 4; 89 public final static byte CHECK_DIRTY = 8; 90 public final static byte LOCKED = 16; 91 public final static byte ADD_TO_SET_ON_UPDATE = 32; 92 public final static byte ADD_TO_WHERE_ON_UPDATE = 64; 93 94 private static final String DEFAULT_LOADGROUP_NAME = "*"; 95 96 private JDBCEntityMetaData metadata; 97 private JDBCStoreManager manager; 98 private DataSource dataSource; 99 private String qualifiedTableName; 100 private String tableName; 101 102 103 private final String primaryKeyFieldName; 104 private final Class primaryKeyClass; 105 private JDBCCMPFieldBridge[] primaryKeyFields; 106 107 private JDBCCMPFieldBridge[] cmpFields; 108 109 private JDBCCMRFieldBridge[] cmrFields; 110 111 private JDBCCMPFieldBridge[] tableFields; 112 113 114 private JDBCCMPFieldBridge versionField; 115 116 private JDBCCMPFieldBridge createdPrincipalField; 118 private JDBCCMPFieldBridge createdTimeField; 119 private JDBCCMPFieldBridge updatedPrincipalField; 120 private JDBCCMPFieldBridge updatedTimeField; 121 122 private Map selectorsByMethod; 123 124 125 private Map loadGroupMasks; 126 private List lazyLoadGroupMasks; 127 private boolean[] eagerLoadGroupMask; 128 private boolean[] defaultLockGroupMask; 129 130 private int jdbcContextSize; 131 132 private final Logger log; 133 134 public JDBCEntityBridge(JDBCEntityMetaData metadata, JDBCStoreManager manager) 135 throws DeploymentException 136 { 137 this.metadata = metadata; 138 this.manager = manager; 139 primaryKeyFieldName = metadata.getPrimaryKeyFieldName(); 140 primaryKeyClass = metadata.getPrimaryKeyClass(); 141 log = Logger.getLogger(this.getClass().getName() + "." + metadata.getName()); 142 } 143 144 public void init() throws DeploymentException 145 { 146 try 147 { 148 InitialContext ic = new InitialContext (); 149 dataSource = (DataSource )ic.lookup(metadata.getDataSourceName()); 150 } 151 catch(NamingException e) 152 { 153 throw new DeploymentException("Error: can't find data source: " + 154 metadata.getDataSourceName(), e); 155 } 156 157 qualifiedTableName = SQLUtil.fixTableName(metadata.getDefaultTableName(), dataSource); 158 int dotIndex = qualifiedTableName.indexOf('.'); 159 tableName = dotIndex == -1 ? qualifiedTableName : qualifiedTableName.substring(dotIndex + 1); 160 161 loadCMPFields(metadata); 163 164 loadCMRFields(metadata); 166 167 JDBCOptimisticLockingMetaData lockMetaData = metadata.getOptimisticLocking(); 169 if(lockMetaData != null && lockMetaData.getLockingField() != null) 170 { 171 Integer strategy = lockMetaData.getLockingStrategy(); 172 JDBCCMPFieldMetaData versionMD = lockMetaData.getLockingField(); 173 174 versionField = getCMPFieldByName(versionMD.getFieldName()); 175 boolean hidden = versionField == null; 176 if(strategy == JDBCOptimisticLockingMetaData.VERSION_COLUMN_STRATEGY) 177 { 178 if(hidden) 179 versionField = new JDBCLongVersionFieldBridge(manager, versionMD); 180 else 181 versionField = new JDBCLongVersionFieldBridge((JDBCCMP2xFieldBridge)versionField); 182 } 183 else if(strategy == JDBCOptimisticLockingMetaData.TIMESTAMP_COLUMN_STRATEGY) 184 { 185 if(hidden) 186 versionField = new JDBCTimestampVersionFieldBridge(manager, versionMD); 187 else 188 versionField = new JDBCTimestampVersionFieldBridge((JDBCCMP2xFieldBridge)versionField); 189 } 190 else if(strategy == JDBCOptimisticLockingMetaData.KEYGENERATOR_COLUMN_STRATEGY) 191 { 192 if(hidden) 193 versionField = new JDBCKeyGenVersionFieldBridge( 194 manager, versionMD, lockMetaData.getKeyGeneratorFactory()); 195 else 196 versionField = new JDBCKeyGenVersionFieldBridge( 197 (JDBCCMP2xFieldBridge)versionField, lockMetaData.getKeyGeneratorFactory()); 198 } 199 200 if(hidden) 201 addCMPField(versionField); 202 else 203 tableFields[versionField.getTableIndex()] = versionField; 204 } 205 206 JDBCAuditMetaData auditMetaData = metadata.getAudit(); 208 if(auditMetaData != null) 209 { 210 JDBCCMPFieldMetaData auditField = auditMetaData.getCreatedPrincipalField(); 211 if(auditField != null) 212 { 213 createdPrincipalField = getCMPFieldByName(auditField.getFieldName()); 214 if(createdPrincipalField == null) 215 { 216 createdPrincipalField = new JDBCCMP2xFieldBridge(manager, auditField); 217 addCMPField(createdPrincipalField); 218 } 219 } 220 else 221 { 222 createdPrincipalField = null; 223 } 224 225 auditField = auditMetaData.getCreatedTimeField(); 226 if(auditField != null) 227 { 228 createdTimeField = getCMPFieldByName(auditField.getFieldName()); 229 if(createdTimeField == null) 230 { 231 createdTimeField = new JDBCCMP2xFieldBridge(manager, auditField, JDBCTypeFactory.EQUALS, false); 232 addCMPField(createdTimeField); 233 } 234 else 235 { 236 createdTimeField = new JDBCCMP2xFieldBridge( 238 (JDBCCMP2xFieldBridge)createdTimeField, JDBCTypeFactory.EQUALS, false); 239 tableFields[createdTimeField.getTableIndex()] = createdTimeField; 240 } 241 } 242 else 243 { 244 createdTimeField = null; 245 } 246 247 auditField = auditMetaData.getUpdatedPrincipalField(); 248 if(auditField != null) 249 { 250 updatedPrincipalField = getCMPFieldByName(auditField.getFieldName()); 251 if(updatedPrincipalField == null) 252 { 253 updatedPrincipalField = new JDBCCMP2xUpdatedPrincipalFieldBridge(manager, auditField); 254 addCMPField(updatedPrincipalField); 255 } 256 else 257 { 258 updatedPrincipalField = new JDBCCMP2xUpdatedPrincipalFieldBridge( 259 (JDBCCMP2xFieldBridge)updatedPrincipalField); 260 tableFields[updatedPrincipalField.getTableIndex()] = updatedPrincipalField; 261 } 262 } 263 else 264 { 265 updatedPrincipalField = null; 266 } 267 268 auditField = auditMetaData.getUpdatedTimeField(); 269 if(auditField != null) 270 { 271 updatedTimeField = getCMPFieldByName(auditField.getFieldName()); 272 if(updatedTimeField == null) 273 { 274 updatedTimeField = new JDBCCMP2xUpdatedTimeFieldBridge(manager, auditField); 275 addCMPField(updatedTimeField); 276 } 277 else 278 { 279 updatedTimeField = new JDBCCMP2xUpdatedTimeFieldBridge((JDBCCMP2xFieldBridge)updatedTimeField); 280 tableFields[updatedTimeField.getTableIndex()] = updatedTimeField; 281 } 282 } 283 else 284 { 285 updatedTimeField = null; 286 } 287 } 288 289 loadSelectors(metadata); 291 } 292 293 public void resolveRelationships() throws DeploymentException 294 { 295 for(int i = 0; i < cmrFields.length; ++i) 296 cmrFields[i].resolveRelationship(); 297 298 loadLoadGroups(metadata); 301 loadEagerLoadGroup(metadata); 302 loadLazyLoadGroups(metadata); 303 } 304 305 309 public void start() throws DeploymentException 310 { 311 for(int i = 0; i < cmrFields.length; ++i) 312 { 313 cmrFields[i].start(); 314 } 315 } 316 317 public boolean removeFromRelations(EntityEnterpriseContext ctx, Object [] oldRelations) 318 { 319 boolean removed = false; 320 for(int i = 0; i < cmrFields.length; ++i) 321 { 322 if(cmrFields[i].removeFromRelations(ctx, oldRelations)) 323 removed = true; 324 } 325 return removed; 326 } 327 328 public void cascadeDelete(EntityEnterpriseContext ctx, Map oldRelations) 329 throws RemoveException , RemoteException 330 { 331 for(int i = 0; i < cmrFields.length; ++i) 332 { 333 JDBCCMRFieldBridge cmrField = cmrFields[i]; 334 Object value = oldRelations.get(cmrField); 335 if(value != null) 336 cmrField.cascadeDelete(ctx, (List )value); 337 } 338 } 339 340 public String getEntityName() 341 { 342 return metadata.getName(); 343 } 344 345 public String getAbstractSchemaName() 346 { 347 return metadata.getAbstractSchemaName(); 348 } 349 350 public Class getRemoteInterface() 351 { 352 return metadata.getRemoteClass(); 353 } 354 355 public Class getLocalInterface() 356 { 357 return metadata.getLocalClass(); 358 } 359 360 public JDBCEntityMetaData getMetaData() 361 { 362 return metadata; 363 } 364 365 public JDBCEntityPersistenceStore getManager() 366 { 367 return manager; 368 } 369 370 373 public DataSource getDataSource() 374 { 375 return dataSource; 376 } 377 378 public String getTableName() 379 { 380 return tableName; 381 } 382 383 public String getQualifiedTableName() 384 { 385 return qualifiedTableName; 386 } 387 388 public Class getPrimaryKeyClass() 389 { 390 return primaryKeyClass; 391 } 392 393 public int getListCacheMax() 394 { 395 return metadata.getListCacheMax(); 396 } 397 398 public int getFetchSize() 399 { 400 return metadata.getFetchSize(); 401 } 402 403 public Object createPrimaryKeyInstance() 404 { 405 if(primaryKeyFieldName == null) 406 { 407 try 408 { 409 return primaryKeyClass.newInstance(); 410 } 411 catch(Exception e) 412 { 413 throw new EJBException ("Error creating primary key instance: ", e); 414 } 415 } 416 return null; 417 } 418 419 public JDBCFieldBridge[] getPrimaryKeyFields() 420 { 421 return primaryKeyFields; 422 } 423 424 428 public List getFields() 429 { 430 int fieldsTotal = primaryKeyFields.length + cmpFields.length + cmrFields.length; 431 JDBCFieldBridge[] fields = new JDBCFieldBridge[fieldsTotal]; 432 int position = 0; 433 System.arraycopy(primaryKeyFields, 0, fields, position, primaryKeyFields.length); 435 position += primaryKeyFields.length; 436 System.arraycopy(cmpFields, 0, fields, position, cmpFields.length); 438 position += cmpFields.length; 439 System.arraycopy(cmrFields, 0, fields, position, cmrFields.length); 441 return Arrays.asList(fields); 442 } 443 444 public FieldBridge getFieldByName(String name) 445 { 446 FieldBridge field = null; 447 for(int i = 0; i < primaryKeyFields.length; ++i) 448 { 449 JDBCCMPFieldBridge primaryKeyField = primaryKeyFields[i]; 450 if(primaryKeyField.getFieldName().equals(name)) 451 { 452 field = primaryKeyField; 453 break; 454 } 455 } 456 if(field == null) 457 { 458 field = getCMPFieldByName(name); 459 } 460 if(field == null) 461 { 462 field = getCMRFieldByName(name); 463 } 464 return field; 465 } 466 467 public boolean[] getEagerLoadMask() 468 { 469 return eagerLoadGroupMask; 470 } 471 472 public Iterator getLazyLoadGroupMasks() 473 { 474 return lazyLoadGroupMasks.iterator(); 475 } 476 477 public boolean[] getLoadGroupMask(String name) 478 { 479 boolean[] mask = (boolean[])loadGroupMasks.get(name); 480 if(mask == null) 481 { 482 throw new IllegalStateException ( 483 "Load group '" + name + "' is not defined. Defined load groups: " + loadGroupMasks.keySet() 484 ); 485 } 486 return mask; 487 } 488 489 public FieldIterator getLoadIterator(JDBCCMPFieldBridge requiredField, 490 JDBCReadAheadMetaData readahead, 491 EntityEnterpriseContext ctx) 492 { 493 boolean[] loadGroup; 494 if(requiredField == null) 495 { 496 if(readahead != null && !readahead.isNone()) 497 { 498 if(log.isTraceEnabled()) 499 { 500 log.trace("Eager-load for entity: readahead=" + readahead); 501 } 502 loadGroup = getLoadGroupMask(readahead.getEagerLoadGroup()); 503 } 504 else 505 { 506 if(log.isTraceEnabled()) 507 { 508 log.trace("Default eager-load for entity: readahead=" + readahead); 509 } 510 loadGroup = eagerLoadGroupMask; 511 } 512 } 513 else 514 { 515 loadGroup = new boolean[tableFields.length]; 516 int requiredInd = requiredField.getTableIndex(); 517 loadGroup[requiredInd] = true; 518 for(Iterator groups = lazyLoadGroupMasks.iterator(); groups.hasNext();) 519 { 520 boolean[] lazyGroup = (boolean[])groups.next(); 521 if(lazyGroup[requiredInd]) 522 { 523 for(int i = 0; i < loadGroup.length; ++i) 524 loadGroup[i] = loadGroup[i] || lazyGroup[i]; 525 } 526 } 527 } 528 529 FieldIterator loadIter; 530 if(loadGroup != null) 531 { 532 int fieldsToLoad = 0; 534 EntityState entityState = getEntityState(ctx); 535 for(int i = 0; i < tableFields.length; ++i) 536 { 537 JDBCCMPFieldBridge field = tableFields[i]; 538 if(loadGroup[i] && !field.isPrimaryKeyMember() && !field.isLoaded(ctx)) 539 { 540 entityState.setLoadRequired(i); 541 ++fieldsToLoad; 542 } 543 } 544 loadIter = (fieldsToLoad > 0 ? entityState.getLoadIterator(ctx) : EMPTY_FIELD_ITERATOR); 545 } 546 else 547 { 548 loadIter = EMPTY_FIELD_ITERATOR; 549 } 550 return loadIter; 551 } 552 553 557 public JDBCCMPFieldBridge getCMPFieldByName(String name) 558 { 559 for(int i = 0; i < primaryKeyFields.length; ++i) 560 { 561 JDBCCMPFieldBridge cmpField = primaryKeyFields[i]; 562 if(cmpField.getFieldName().equals(name)) 563 return cmpField; 564 } 565 for(int i = 0; i < cmpFields.length; ++i) 566 { 567 JDBCCMPFieldBridge cmpField = cmpFields[i]; 568 if(cmpField.getFieldName().equals(name)) 569 return cmpField; 570 } 571 return null; 572 } 573 574 public JDBCAbstractCMRFieldBridge[] getCMRFields() 575 { 576 return cmrFields; 577 } 578 579 public JDBCCMRFieldBridge getCMRFieldByName(String name) 580 { 581 for(int i = 0; i < cmrFields.length; ++i) 582 { 583 JDBCCMRFieldBridge cmrField = cmrFields[i]; 584 if(cmrField.getFieldName().equals(name)) 585 return cmrField; 586 } 587 return null; 588 } 589 590 public JDBCCMPFieldBridge getVersionField() 591 { 592 return versionField; 593 } 594 595 public JDBCCMPFieldBridge getCreatedPrincipalField() 596 { 597 return createdPrincipalField; 598 } 599 600 public JDBCCMPFieldBridge getCreatedTimeField() 601 { 602 return createdTimeField; 603 } 604 605 public JDBCCMPFieldBridge getUpdatedPrincipalField() 606 { 607 return updatedPrincipalField; 608 } 609 610 public JDBCCMPFieldBridge getUpdatedTimeField() 611 { 612 return updatedTimeField; 613 } 614 615 public Collection getSelectors() 616 { 617 return selectorsByMethod.values(); 618 } 619 620 public void initInstance(EntityEnterpriseContext ctx) 621 { 622 for(int i = 0; i < tableFields.length; ++i) 623 tableFields[i].initInstance(ctx); 624 for(int i = 0; i < cmrFields.length; ++i) 629 { 630 JDBCCMRFieldBridge cmrField = cmrFields[i]; 631 cmrField.initInstance(ctx); 632 } 633 } 634 635 public static boolean isEjbCreateDone(EntityEnterpriseContext ctx) 636 { 637 return getEntityState(ctx).ejbCreateDone; 638 } 639 640 public static void setCreated(EntityEnterpriseContext ctx) 641 { 642 getEntityState(ctx).setCreated(); 643 } 644 645 public static void setEjbCreateDone(EntityEnterpriseContext ctx) 646 { 647 getEntityState(ctx).ejbCreateDone = true; 648 } 649 650 657 public boolean isModified(EntityEnterpriseContext ctx) 658 { 659 boolean invalidateCache = false; 660 final EntityState entityState = getEntityState(ctx); 661 if(entityState.isCreated()) 662 { 663 invalidateCache = areCmpFieldsDirty(ctx, entityState); 664 if(!invalidateCache) 665 { 666 for(int i = 0; i < cmrFields.length; ++i) 667 { 668 if(cmrFields[i].invalidateCache(ctx)) 669 { 670 invalidateCache = true; 671 break; 672 } 673 } 674 } 675 } 676 return invalidateCache; 677 } 678 679 public boolean isStoreRequired(EntityEnterpriseContext ctx) 680 { 681 boolean modified = false; 682 final EntityState entityState = getEntityState(ctx); 683 if(entityState.isCreated()) 684 { 685 modified = areCmpFieldsDirty(ctx, entityState); 686 if(!modified) 687 { 688 for(int i = 0; i < cmrFields.length; ++i) 689 { 690 if(cmrFields[i].isDirty(ctx)) 691 { 692 modified = true; 693 break; 694 } 695 } 696 } 697 } 698 return modified; 699 } 700 701 private boolean areCmpFieldsDirty(final EntityEnterpriseContext ctx, 702 final EntityState entityState) 703 { 704 for(int i = 0; i < tableFields.length; ++i) 705 { 706 final JDBCCMPFieldBridge field = tableFields[i]; 707 if(entityState.isCheckDirty(i) && field.isDirty(ctx)) 708 { 709 return true; 710 } 711 } 712 return false; 713 } 714 715 public FieldIterator getDirtyIterator(EntityEnterpriseContext ctx) 716 { 717 int dirtyFields = 0; 718 final EntityState entityState = getEntityState(ctx); 719 for(int i = 0; i < tableFields.length; ++i) 720 { 721 JDBCCMPFieldBridge field = tableFields[i]; 722 if(entityState.isCheckDirty(i) && field.isDirty(ctx)) 723 { 724 entityState.setUpdateRequired(i); 725 ++dirtyFields; 726 } 727 } 728 729 return dirtyFields > 0 ? getEntityState(ctx).getDirtyIterator(ctx) : EMPTY_FIELD_ITERATOR; 730 } 731 732 public boolean hasLockedFields(EntityEnterpriseContext ctx) 733 { 734 return getEntityState(ctx).hasLockedFields(); 735 } 736 737 public FieldIterator getLockedIterator(EntityEnterpriseContext ctx) 738 { 739 return getEntityState(ctx).getLockedIterator(ctx); 740 } 741 742 public void initPersistenceContext(EntityEnterpriseContext ctx) 743 { 744 Object instance = ctx.getInstance(); 747 if(instance instanceof Proxies.ProxyTarget) 748 { 749 InvocationHandler handler = ((Proxies.ProxyTarget)instance).getInvocationHandler(); 750 if(handler instanceof EntityBridgeInvocationHandler) 751 ((EntityBridgeInvocationHandler)handler).setContext(ctx); 752 } 753 ctx.setPersistenceContext(new JDBCContext(jdbcContextSize, new EntityState())); 754 } 755 756 759 public void resetPersistenceContext(EntityEnterpriseContext ctx) 760 { 761 for(int i = 0; i < primaryKeyFields.length; ++i) 762 primaryKeyFields[i].resetPersistenceContext(ctx); 763 for(int i = 0; i < cmpFields.length; ++i) 764 cmpFields[i].resetPersistenceContext(ctx); 765 for(int i = 0; i < cmrFields.length; ++i) 766 cmrFields[i].resetPersistenceContext(ctx); 767 } 768 769 770 public static void destroyPersistenceContext(EntityEnterpriseContext ctx) 771 { 772 Object instance = ctx.getInstance(); 775 if(instance instanceof Proxies.ProxyTarget) 776 { 777 InvocationHandler handler = ((Proxies.ProxyTarget)instance).getInvocationHandler(); 778 if(handler instanceof EntityBridgeInvocationHandler) 779 ((EntityBridgeInvocationHandler)handler).setContext(null); 780 } 781 ctx.setPersistenceContext(null); 782 } 783 784 788 public int setPrimaryKeyParameters(PreparedStatement ps, int parameterIndex, Object primaryKey) 789 { 790 for(int i = 0; i < primaryKeyFields.length; ++i) 791 parameterIndex = primaryKeyFields[i].setPrimaryKeyParameters(ps, parameterIndex, primaryKey); 792 return parameterIndex; 793 } 794 795 public int loadPrimaryKeyResults(ResultSet rs, int parameterIndex, Object [] pkRef) 796 { 797 pkRef[0] = createPrimaryKeyInstance(); 798 for(int i = 0; i < primaryKeyFields.length; ++i) 799 parameterIndex = primaryKeyFields[i].loadPrimaryKeyResults(rs, parameterIndex, pkRef); 800 return parameterIndex; 801 } 802 803 public Object extractPrimaryKeyFromInstance(EntityEnterpriseContext ctx) 804 { 805 try 806 { 807 Object pk = null; 808 for(int i = 0; i < primaryKeyFields.length; ++i) 809 { 810 JDBCCMPFieldBridge pkField = primaryKeyFields[i]; 811 Object fieldValue = pkField.getInstanceValue(ctx); 812 813 pk = pkField.setPrimaryKeyValue(pk, fieldValue); 816 } 817 return pk; 818 } 819 catch(EJBException e) 820 { 821 throw e; 823 } 824 catch(Exception e) 825 { 826 throw new EJBException ("Internal error extracting primary key from " + 828 "instance", e); 829 } 830 } 831 832 public void injectPrimaryKeyIntoInstance(EntityEnterpriseContext ctx, Object pk) 833 { 834 for(int i = 0; i < primaryKeyFields.length; ++i) 835 { 836 JDBCCMPFieldBridge pkField = primaryKeyFields[i]; 837 Object fieldValue = pkField.getPrimaryKeyValue(pk); 838 pkField.setInstanceValue(ctx, fieldValue); 839 } 840 } 841 842 int getNextJDBCContextIndex() 843 { 844 return jdbcContextSize++; 845 } 846 847 int addTableField(JDBCCMPFieldBridge field) 848 { 849 JDBCCMPFieldBridge[] tmpFields = tableFields; 850 if(tableFields == null) 851 { 852 tableFields = new JDBCCMPFieldBridge[1]; 853 } 854 else 855 { 856 tableFields = new JDBCCMPFieldBridge[tableFields.length + 1]; 857 System.arraycopy(tmpFields, 0, tableFields, 0, tmpFields.length); 858 } 859 int index = tableFields.length - 1; 860 tableFields[index] = field; 861 862 return index; 863 } 864 865 public JDBCFieldBridge[] getTableFields() 866 { 867 return tableFields; 868 } 869 870 874 public void setRemoved(EntityEnterpriseContext ctx) 875 { 876 getEntityState(ctx).setRemoved(); 877 } 878 879 883 public boolean isRemoved(EntityEnterpriseContext ctx) 884 { 885 return getEntityState(ctx).isRemoved(); 886 } 887 888 891 public void setIsBeingRemoved(EntityEnterpriseContext ctx) 892 { 893 getEntityState(ctx).setIsBeingRemoved(); 894 } 895 896 900 public boolean isBeingRemoved(EntityEnterpriseContext ctx) 901 { 902 return getEntityState(ctx).isBeingRemoved(); 903 } 904 905 909 public void scheduleForCascadeDelete(EntityEnterpriseContext ctx) 910 { 911 getEntityState(ctx).scheduleForCascadeDelete(); 912 if(log.isTraceEnabled()) 913 log.trace("Scheduled for cascade-delete: " + ctx.getId()); 914 } 915 916 920 public boolean isScheduledForCascadeDelete(EntityEnterpriseContext ctx) 921 { 922 return getEntityState(ctx).isScheduledForCascadeDelete(); 923 } 924 925 929 public void scheduleForBatchCascadeDelete(EntityEnterpriseContext ctx) 930 { 931 getEntityState(ctx).scheduleForBatchCascadeDelete(); 932 if(log.isTraceEnabled()) 933 log.trace("Scheduled for batch-cascade-delete: " + ctx.getId()); 934 } 935 936 940 public boolean isScheduledForBatchCascadeDelete(EntityEnterpriseContext ctx) 941 { 942 return getEntityState(ctx).isScheduledForBatchCascadeDelete(); 943 } 944 945 private static EntityState getEntityState(EntityEnterpriseContext ctx) 946 { 947 JDBCContext jdbcCtx = (JDBCContext)ctx.getPersistenceContext(); 948 EntityState entityState = jdbcCtx.getEntityState(); 949 if(entityState == null) 950 throw new IllegalStateException ("Entity state is null."); 951 return entityState; 952 } 953 954 private void loadCMPFields(JDBCEntityMetaData metadata) 955 throws DeploymentException 956 { 957 List cmpFieldsMD = metadata.getCMPFields(); 960 List cmpFieldsList = new ArrayList (cmpFieldsMD.size()); 961 List pkFieldsList = new ArrayList (cmpFieldsMD.size()); 963 964 for(int i = 0; i < cmpFieldsMD.size(); ++i) 966 { 967 JDBCCMPFieldMetaData fieldMD = (JDBCCMPFieldMetaData)cmpFieldsMD.get(i); 968 if(fieldMD.isPrimaryKeyMember()) 969 { 970 JDBCCMPFieldBridge cmpField = createCMPField(metadata, fieldMD); 971 pkFieldsList.add(cmpField); 972 } 973 } 974 975 for(int i = 0; i < cmpFieldsMD.size(); ++i) 977 { 978 JDBCCMPFieldMetaData fieldMD = (JDBCCMPFieldMetaData)cmpFieldsMD.get(i); 979 if(!fieldMD.isPrimaryKeyMember()) 980 { 981 JDBCCMPFieldBridge cmpField = createCMPField(metadata, fieldMD); 982 cmpFieldsList.add(cmpField); 983 } 984 } 985 986 primaryKeyFields = new JDBCCMPFieldBridge[pkFieldsList.size()]; 988 for(int i = 0; i < pkFieldsList.size(); ++i) 989 primaryKeyFields[i] = (JDBCCMPFieldBridge)pkFieldsList.get(i); 990 991 cmpFields = new JDBCCMPFieldBridge[cmpFieldsMD.size() - primaryKeyFields.length]; 993 int cmpFieldIndex = 0; 994 for(int i = 0; i < cmpFieldsList.size(); ++i) 995 cmpFields[cmpFieldIndex++] = (JDBCCMPFieldBridge)cmpFieldsList.get(i); 996 } 997 998 private void loadCMRFields(JDBCEntityMetaData metadata) 999 throws DeploymentException 1000 { 1001 cmrFields = new JDBCCMRFieldBridge[metadata.getRelationshipRoles().size()]; 1002 int cmrFieldIndex = 0; 1004 for(Iterator iter = metadata.getRelationshipRoles().iterator(); iter.hasNext();) 1005 { 1006 JDBCRelationshipRoleMetaData relationshipRole = (JDBCRelationshipRoleMetaData)iter.next(); 1007 JDBCCMRFieldBridge cmrField = new JDBCCMRFieldBridge(this, manager, relationshipRole); 1008 cmrFields[cmrFieldIndex++] = cmrField; 1009 } 1010 } 1011 1012 private void loadLoadGroups(JDBCEntityMetaData metadata) 1013 throws DeploymentException 1014 { 1015 loadGroupMasks = new HashMap (); 1016 1017 JDBCOptimisticLockingMetaData olMD = metadata.getOptimisticLocking(); 1019 if(olMD != null) 1020 { 1021 if(versionField != null) 1022 { 1023 defaultLockGroupMask = new boolean[tableFields.length]; 1024 defaultLockGroupMask[versionField.getTableIndex()] = true; 1025 versionField.setLockingStrategy(LockingStrategy.VERSION); 1026 } 1027 else if(olMD.getGroupName() != null) 1028 { 1029 defaultLockGroupMask = loadGroupMask(olMD.getGroupName(), null); 1030 for(int i = 0; i < tableFields.length; ++i) 1031 { 1032 if(defaultLockGroupMask[i]) 1033 { 1034 JDBCCMPFieldBridge tableField = tableFields[i]; 1035 tableField.setLockingStrategy(LockingStrategy.GROUP); 1036 tableField.addDefaultFlag(ADD_TO_WHERE_ON_UPDATE); 1037 } 1038 } 1039 } 1040 else { 1042 LockingStrategy strategy = 1043 (olMD.getLockingStrategy() == JDBCOptimisticLockingMetaData.READ_STRATEGY ? 1044 LockingStrategy.READ : LockingStrategy.MODIFIED 1045 ); 1046 for(int i = 0; i < tableFields.length; ++i) 1047 { 1048 JDBCCMPFieldBridge field = tableFields[i]; 1049 if(!field.isPrimaryKeyMember()) 1050 field.setLockingStrategy(strategy); 1051 } 1052 } 1053 } 1054 1055 boolean[] defaultLoadGroup = new boolean[tableFields.length]; 1057 Arrays.fill(defaultLoadGroup, true); 1058 for(int i = 0; i < primaryKeyFields.length; ++i) 1059 { 1060 int tableIndex = primaryKeyFields[i].getTableIndex(); 1061 defaultLoadGroup[tableIndex] = false; 1062 } 1063 loadGroupMasks.put(DEFAULT_LOADGROUP_NAME, defaultLoadGroup); 1064 1065 Iterator groupNames = metadata.getLoadGroups().keySet().iterator(); 1067 while(groupNames.hasNext()) 1068 { 1069 String groupName = (String )groupNames.next(); 1071 boolean[] loadGroup = loadGroupMask(groupName, defaultLockGroupMask); 1072 loadGroupMasks.put(groupName, loadGroup); 1073 } 1074 loadGroupMasks = Collections.unmodifiableMap(loadGroupMasks); 1075 } 1076 1077 private boolean[] loadGroupMask(String groupName, boolean[] defaultGroup) 1078 throws DeploymentException 1079 { 1080 List fieldNames = metadata.getLoadGroup(groupName); 1081 boolean[] group = new boolean[tableFields.length]; 1082 if(defaultGroup != null) 1083 System.arraycopy(defaultGroup, 0, group, 0, group.length); 1084 for(Iterator iter = fieldNames.iterator(); iter.hasNext();) 1085 { 1086 String fieldName = (String )iter.next(); 1087 JDBCFieldBridge field = (JDBCFieldBridge)getFieldByName(fieldName); 1088 if(field == null) 1089 throw new DeploymentException( 1090 "Field " + fieldName + " not found for entity " + getEntityName()); 1091 1092 if(field instanceof JDBCCMRFieldBridge) 1093 { 1094 JDBCCMRFieldBridge cmrField = (JDBCCMRFieldBridge)field; 1095 if(cmrField.hasForeignKey()) 1096 { 1097 JDBCCMPFieldBridge[] fkFields = (JDBCCMPFieldBridge[]) cmrField.getForeignKeyFields(); 1098 for(int i = 0; i < fkFields.length; ++i) 1099 { 1100 group[fkFields[i].getTableIndex()] = true; 1101 } 1102 } 1103 else 1104 { 1105 throw new DeploymentException("Only CMR fields that have " + 1106 "a foreign-key may be a member of a load group: " + 1107 "fieldName=" + fieldName); 1108 } 1109 } 1110 else 1111 { 1112 group[((JDBCCMPFieldBridge)field).getTableIndex()] = true; 1113 } 1114 } 1115 return group; 1116 } 1117 1118 private void loadEagerLoadGroup(JDBCEntityMetaData metadata) 1119 { 1120 String eagerLoadGroupName = metadata.getEagerLoadGroup(); 1121 if(eagerLoadGroupName == null) 1122 { 1123 eagerLoadGroupMask = defaultLockGroupMask; 1125 } 1126 else 1127 eagerLoadGroupMask = (boolean[])loadGroupMasks.get(eagerLoadGroupName); 1128 } 1129 1130 private void loadLazyLoadGroups(JDBCEntityMetaData metadata) 1131 { 1132 List lazyGroupNames = metadata.getLazyLoadGroups(); 1133 lazyLoadGroupMasks = new ArrayList (lazyGroupNames.size()); 1134 for(Iterator lazyLoadGroupNames = lazyGroupNames.iterator(); lazyLoadGroupNames.hasNext();) 1135 { 1136 String lazyLoadGroupName = (String )lazyLoadGroupNames.next(); 1137 lazyLoadGroupMasks.add(loadGroupMasks.get(lazyLoadGroupName)); 1138 } 1139 lazyLoadGroupMasks = Collections.unmodifiableList(lazyLoadGroupMasks); 1140 } 1141 1142 private JDBCCMPFieldBridge createCMPField(JDBCEntityMetaData metadata, 1143 JDBCCMPFieldMetaData cmpFieldMetaData) 1144 throws DeploymentException 1145 { 1146 JDBCCMPFieldBridge cmpField; 1147 if(metadata.isCMP1x()) 1148 cmpField = new JDBCCMP1xFieldBridge(manager, cmpFieldMetaData); 1149 else 1150 cmpField = new JDBCCMP2xFieldBridge(manager, cmpFieldMetaData); 1151 return cmpField; 1152 } 1153 1154 private void loadSelectors(JDBCEntityMetaData metadata) 1155 { 1156 selectorsByMethod = new HashMap (metadata.getQueries().size()); 1160 Iterator definedFinders = manager.getMetaData().getQueries().iterator(); 1161 while(definedFinders.hasNext()) 1162 { 1163 JDBCQueryMetaData q = (JDBCQueryMetaData)definedFinders.next(); 1164 if(q.getMethod().getName().startsWith("ejbSelect")) 1165 selectorsByMethod.put(q.getMethod(), new JDBCSelectorBridge(manager, q)); 1166 } 1167 selectorsByMethod = Collections.unmodifiableMap(selectorsByMethod); 1168 } 1169 1170 private void addCMPField(JDBCCMPFieldBridge field) 1171 { 1172 JDBCCMPFieldBridge[] tmpCMPFields = cmpFields; 1173 cmpFields = new JDBCCMPFieldBridge[cmpFields.length + 1]; 1174 System.arraycopy(tmpCMPFields, 0, cmpFields, 0, tmpCMPFields.length); 1175 cmpFields[tmpCMPFields.length] = field; 1176 } 1177 1178 public class EntityState 1179 { 1180 private static final byte REMOVED = 1; 1181 private static final byte SCHEDULED_FOR_CASCADE_DELETE = 2; 1182 private static final byte SCHEDULED_FOR_BATCH_CASCADE_DELETE = 4; 1183 private static final byte IS_BEING_REMOVED = 8; 1184 1185 1186 private boolean ejbCreateDone = false; 1187 1188 private boolean ejbPostCreateDone = false; 1189 1190 private byte entityFlags; 1191 1192 1193 private final byte[] fieldFlags = new byte[tableFields.length]; 1194 1195 public EntityState() 1196 { 1197 for(int i = 0; i < tableFields.length; ++i) 1198 { 1199 fieldFlags[i] = tableFields[i].getDefaultFlags(); 1200 } 1201 } 1202 1203 public void setRemoved() 1204 { 1205 entityFlags |= REMOVED; 1206 entityFlags &= ~(SCHEDULED_FOR_CASCADE_DELETE | SCHEDULED_FOR_BATCH_CASCADE_DELETE | IS_BEING_REMOVED); 1207 } 1208 1209 public boolean isRemoved() 1210 { 1211 return (entityFlags & REMOVED) > 0; 1212 } 1213 1214 public void setIsBeingRemoved() 1215 { 1216 entityFlags |= IS_BEING_REMOVED; 1217 } 1218 1219 public boolean isBeingRemoved() 1220 { 1221 return (entityFlags & IS_BEING_REMOVED) > 0; 1222 } 1223 1224 public void scheduleForCascadeDelete() 1225 { 1226 entityFlags |= SCHEDULED_FOR_CASCADE_DELETE; 1227 } 1228 1229 public boolean isScheduledForCascadeDelete() 1230 { 1231 return (entityFlags & SCHEDULED_FOR_CASCADE_DELETE) > 0; 1232 } 1233 1234 public void scheduleForBatchCascadeDelete() 1235 { 1236 entityFlags |= SCHEDULED_FOR_BATCH_CASCADE_DELETE | SCHEDULED_FOR_CASCADE_DELETE; 1237 } 1238 1239 public boolean isScheduledForBatchCascadeDelete() 1240 { 1241 return (entityFlags & SCHEDULED_FOR_BATCH_CASCADE_DELETE) > 0; 1242 } 1243 1244 public void setCreated() 1245 { 1246 ejbCreateDone = true; 1247 ejbPostCreateDone = true; 1248 } 1249 1250 public boolean isCreated() 1251 { 1252 return ejbCreateDone && ejbPostCreateDone; 1253 } 1254 1255 1259 public boolean isLoaded(int fieldIndex) 1260 { 1261 return (fieldFlags[fieldIndex] & LOADED) > 0; 1262 } 1263 1264 1268 public void setLoaded(int fieldIndex) 1269 { 1270 fieldFlags[fieldIndex] |= LOADED; 1271 } 1272 1273 1277 public void setLoadRequired(int fieldIndex) 1278 { 1279 fieldFlags[fieldIndex] |= LOAD_REQUIRED; 1280 } 1281 1282 1286 public void setUpdateRequired(int fieldIndex) 1287 { 1288 fieldFlags[fieldIndex] |= DIRTY; 1289 } 1290 1291 1295 public void setCheckDirty(int fieldIndex) 1296 { 1297 fieldFlags[fieldIndex] |= CHECK_DIRTY; 1298 } 1299 1300 1304 public boolean isCheckDirty(int fieldIndex) 1305 { 1306 return (fieldFlags[fieldIndex] & CHECK_DIRTY) > 0; 1307 } 1308 1309 1313 public void setClean(int fieldIndex) 1314 { 1315 fieldFlags[fieldIndex] &= ~(CHECK_DIRTY | DIRTY | LOCKED); 1316 } 1317 1318 1322 public void resetFlags(int fieldIndex) 1323 { 1324 fieldFlags[fieldIndex] = tableFields[fieldIndex].getDefaultFlags(); 1325 } 1326 1327 public FieldIterator getDirtyIterator(EntityEnterpriseContext ctx) 1328 { 1329 return new MaskFieldIterator((byte)(DIRTY | ADD_TO_SET_ON_UPDATE)); 1330 } 1331 1332 public boolean hasLockedFields() 1333 { 1334 boolean result = false; 1335 for(int i = 0; i < fieldFlags.length; ++i) 1336 { 1337 if((fieldFlags[i] & (LOCKED | ADD_TO_WHERE_ON_UPDATE)) > 0) 1338 { 1339 result = true; 1340 break; 1341 } 1342 } 1343 return result; 1344 } 1345 1346 public FieldIterator getLockedIterator(EntityEnterpriseContext ctx) 1347 { 1348 return new MaskFieldIterator((byte)(LOCKED | ADD_TO_WHERE_ON_UPDATE)); 1349 } 1350 1351 public boolean lockValue(int fieldIndex) 1352 { 1353 boolean lock = false; 1354 byte fieldFlag = fieldFlags[fieldIndex]; 1355 if((fieldFlag & LOADED) > 0 && (fieldFlag & LOCKED) == 0) 1356 { 1357 fieldFlags[fieldIndex] |= LOCKED; 1358 lock = true; 1359 } 1360 return lock; 1361 } 1362 1363 public FieldIterator getLoadIterator(EntityEnterpriseContext ctx) 1364 { 1365 return new MaskFieldIterator(LOAD_REQUIRED); 1366 } 1367 1368 1370 private class MaskFieldIterator implements FieldIterator 1371 { 1372 private final byte flagMask; 1373 private int nextIndex = 0; 1374 private int curIndex = -1; 1375 1376 public MaskFieldIterator(byte flagMask) 1377 { 1378 this.flagMask = flagMask; 1379 } 1380 1381 public boolean hasNext() 1382 { 1383 while(nextIndex < fieldFlags.length) 1384 { 1385 if((fieldFlags[nextIndex] & flagMask) > 0) 1386 { 1387 return true; 1388 } 1389 1390 ++nextIndex; 1391 } 1392 1393 return false; 1394 } 1395 1396 public JDBCCMPFieldBridge next() 1397 { 1398 if(!hasNext()) 1399 throw new NoSuchElementException (); 1400 curIndex = nextIndex; 1401 return tableFields[nextIndex++]; 1402 } 1403 1404 public void remove() 1405 { 1406 fieldFlags[curIndex] &= ~flagMask; 1407 } 1408 1409 public void removeAll() 1410 { 1411 int inversedMask = ~flagMask; 1412 for(int i = 0; i < fieldFlags.length; ++i) 1413 fieldFlags[i] &= inversedMask; 1414 } 1415 1416 public void reset() 1417 { 1418 nextIndex = 0; 1419 curIndex = -1; 1420 } 1421 } 1422 } 1423 1424 public static final FieldIterator EMPTY_FIELD_ITERATOR = new FieldIterator() 1425 { 1426 public boolean hasNext() 1427 { 1428 return false; 1429 } 1430 1431 public JDBCCMPFieldBridge next() 1432 { 1433 throw new NoSuchElementException (); 1434 } 1435 1436 public void remove() 1437 { 1438 throw new UnsupportedOperationException (); 1439 } 1440 1441 public void removeAll() 1442 { 1443 throw new UnsupportedOperationException (); 1444 } 1445 1446 public void reset() 1447 { 1448 } 1449 }; 1450 1451 public static interface FieldIterator 1452 { 1453 1456 boolean hasNext(); 1457 1458 1461 JDBCCMPFieldBridge next(); 1462 1463 1466 void remove(); 1467 1468 1471 void removeAll(); 1472 1473 1476 void reset(); 1477 } 1478} 1479 | Popular Tags |