1 22 package org.jboss.ejb.plugins.cmp.jdbc.bridge; 23 24 import java.lang.ref.WeakReference ; 25 import java.lang.reflect.Method ; 26 import javax.sql.DataSource ; 27 import java.sql.PreparedStatement ; 28 import java.sql.ResultSet ; 29 import java.util.ArrayList ; 30 import java.util.Collection ; 31 import java.util.Collections ; 32 import java.util.HashSet ; 33 import java.util.Iterator ; 34 import java.util.List ; 35 import java.util.Map ; 36 import java.util.Set ; 37 import java.util.HashMap ; 38 import java.util.Arrays ; 39 import java.security.AccessController ; 40 import java.security.PrivilegedAction ; 41 import java.security.Principal ; 42 import java.rmi.RemoteException ; 43 import javax.ejb.EJBException ; 44 import javax.ejb.EJBLocalObject ; 45 import javax.ejb.EJBLocalHome ; 46 import javax.ejb.RemoveException ; 47 import javax.ejb.NoSuchObjectLocalException ; 48 import javax.transaction.Status ; 49 import javax.transaction.Synchronization ; 50 import javax.transaction.SystemException ; 51 import javax.transaction.Transaction ; 52 import javax.transaction.TransactionManager ; 53 import javax.transaction.RollbackException ; 54 55 import org.jboss.deployment.DeploymentException; 56 import org.jboss.ejb.EntityCache; 57 import org.jboss.ejb.EntityContainer; 58 import org.jboss.ejb.EntityEnterpriseContext; 59 import org.jboss.ejb.LocalProxyFactory; 60 import org.jboss.ejb.plugins.cmp.bridge.EntityBridge; 61 import org.jboss.ejb.plugins.cmp.bridge.FieldBridge; 62 import org.jboss.ejb.plugins.cmp.jdbc.JDBCContext; 63 import org.jboss.ejb.plugins.cmp.jdbc.JDBCStoreManager; 64 import org.jboss.ejb.plugins.cmp.jdbc.JDBCType; 65 import org.jboss.ejb.plugins.cmp.jdbc.SQLUtil; 66 import org.jboss.ejb.plugins.cmp.jdbc.CascadeDeleteStrategy; 67 import org.jboss.ejb.plugins.cmp.jdbc.RelationData; 68 import org.jboss.ejb.plugins.cmp.jdbc.JDBCEntityPersistenceStore; 69 import org.jboss.ejb.plugins.cmp.jdbc.JDBCParameterSetter; 70 import org.jboss.ejb.plugins.cmp.jdbc.JDBCResultSetReader; 71 import org.jboss.tm.TransactionLocal; 72 import org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCCMPFieldMetaData; 73 import org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCReadAheadMetaData; 74 import org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCRelationMetaData; 75 import org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCRelationshipRoleMetaData; 76 import org.jboss.ejb.plugins.cmp.ejbql.Catalog; 77 import org.jboss.ejb.plugins.lock.Entrancy; 78 import org.jboss.invocation.InvocationType; 79 import org.jboss.logging.Logger; 80 import org.jboss.security.SecurityAssociation; 81 82 97 public final class JDBCCMRFieldBridge extends JDBCAbstractCMRFieldBridge 98 { 99 102 private final JDBCEntityBridge entity; 103 106 private final JDBCStoreManager manager; 107 110 private final JDBCRelationshipRoleMetaData metadata; 111 114 private DataSource dataSource; 115 118 private String qualifiedTableName; 119 private String tableName; 120 123 private JDBCCMP2xFieldBridge[] tableKeyFields; 124 128 private JDBCType jdbcType; 129 132 private WeakReference relatedContainerRef; 133 136 private JDBCStoreManager relatedManager; 137 140 private JDBCEntityBridge relatedEntity; 141 144 private JDBCCMRFieldBridge relatedCMRField; 145 148 private final Logger log; 149 150 153 private JDBCCMP2xFieldBridge[] foreignKeyFields; 154 157 private boolean allFKFieldsMappedToPKFields; 158 161 private final Map relatedPKFieldsByMyPKFields = new HashMap (); 162 165 private final Map relatedPKFieldsByMyFKFields = new HashMap (); 166 169 private boolean hasFKFieldsMappedToCMPFields; 170 171 private final TransactionLocal relatedPKValuesWaitingForMyPK = new TransactionLocal() 178 { 179 protected Object initialValue() 180 { 181 return new HashMap (); 182 } 183 }; 184 185 188 private Method relatedFindByPrimaryKey; 189 190 193 private final int jdbcContextIndex; 194 195 198 private CascadeDeleteStrategy cascadeDeleteStrategy; 199 200 203 private RelationDataManager relationManager; 204 205 208 public JDBCCMRFieldBridge(JDBCEntityBridge entity, 209 JDBCStoreManager manager, 210 JDBCRelationshipRoleMetaData metadata) 211 throws DeploymentException 212 { 213 this.entity = entity; 214 this.manager = manager; 215 this.metadata = metadata; 216 this.jdbcContextIndex = ((JDBCEntityBridge) manager.getEntityBridge()).getNextJDBCContextIndex(); 217 218 String categoryName = this.getClass().getName() + 220 "." + manager.getMetaData().getName() + "."; 221 if(metadata.getCMRFieldName() != null) 222 { 223 categoryName += metadata.getCMRFieldName(); 224 } 225 else 226 { 227 categoryName += metadata.getRelatedRole().getEntity().getName() + 228 "-" + metadata.getRelatedRole().getCMRFieldName(); 229 } 230 this.log = Logger.getLogger(categoryName); 231 } 232 233 public RelationDataManager getRelationDataManager() 234 { 235 return relationManager; 236 } 237 238 public void resolveRelationship() throws DeploymentException 239 { 240 245 String relatedEntityName = metadata.getRelatedRole().getEntity().getName(); 247 248 Catalog catalog = (Catalog) manager.getApplicationData("CATALOG"); 250 relatedEntity = (JDBCEntityBridge) catalog.getEntityByEJBName(relatedEntityName); 251 if(relatedEntity == null) 252 { 253 throw new DeploymentException("Related entity not found: " + 254 "entity=" + 255 entity.getEntityName() + 256 ", " + 257 "cmrField=" + 258 getFieldName() + 259 ", " + 260 "relatedEntity=" + relatedEntityName); 261 } 262 263 JDBCCMRFieldBridge[] cmrFields = (JDBCCMRFieldBridge[]) relatedEntity.getCMRFields(); 265 for(int i = 0; i < cmrFields.length; ++i) 266 { 267 JDBCCMRFieldBridge cmrField = cmrFields[i]; 268 if(metadata.getRelatedRole() == cmrField.getMetaData()) 269 { 270 relatedCMRField = cmrField; 271 break; 272 } 273 } 274 275 if(relatedCMRField == null) 278 { 279 String message = "Related CMR field not found in " + 280 relatedEntity.getEntityName() + " for relationship from"; 281 282 message += entity.getEntityName() + "."; 283 if(getFieldName() != null) 284 { 285 message += getFieldName(); 286 } 287 else 288 { 289 message += "<no-field>"; 290 } 291 292 message += " to "; 293 message += relatedEntityName + "."; 294 if(metadata.getRelatedRole().getCMRFieldName() != null) 295 { 296 message += metadata.getRelatedRole().getCMRFieldName(); 297 } 298 else 299 { 300 message += "<no-field>"; 301 } 302 303 throw new DeploymentException(message); 304 } 305 306 relatedManager = (JDBCStoreManager) relatedEntity.getManager(); 308 309 EntityContainer relatedContainer = relatedManager.getContainer(); 311 this.relatedContainerRef = new WeakReference (relatedContainer); 312 313 Class homeClass = (relatedContainer.getLocalHomeClass() != null ? 315 relatedContainer.getLocalHomeClass() : relatedContainer.getHomeClass()); 316 try 317 { 318 relatedFindByPrimaryKey = 319 homeClass.getMethod("findByPrimaryKey", new Class []{relatedEntity.getPrimaryKeyClass()}); 320 } 321 catch(Exception e) 322 { 323 throw new DeploymentException("findByPrimaryKey(" + 324 relatedEntity.getPrimaryKeyClass().getName() 325 + " pk) was not found in " + homeClass.getName()); 326 } 327 328 if(metadata.getRelationMetaData().isTableMappingStyle()) 332 { 333 Collection tableKeys = metadata.getKeyFields(); 335 List keyFieldsList = new ArrayList (tableKeys.size()); 336 337 Map pkFieldsToFKFields = new HashMap (tableKeys.size()); 339 for(Iterator i = tableKeys.iterator(); i.hasNext();) 340 { 341 JDBCCMPFieldMetaData cmpFieldMetaData = (JDBCCMPFieldMetaData) i.next(); 342 FieldBridge pkField = entity.getFieldByName(cmpFieldMetaData.getFieldName()); 343 if(pkField == null) 344 { 345 throw new DeploymentException("Primary key not found for key-field " + cmpFieldMetaData.getFieldName()); 346 } 347 pkFieldsToFKFields.put(pkField, new JDBCCMP2xFieldBridge(manager, cmpFieldMetaData)); 348 } 349 JDBCFieldBridge[] pkFields = entity.getPrimaryKeyFields(); 351 for(int i = 0; i < pkFields.length; ++i) 352 { 353 Object fkField = pkFieldsToFKFields.get(pkFields[i]); 354 if(fkField == null) 355 { 356 throw new DeploymentException("Primary key " + pkFields[i].getFieldName() + " is not mapped."); 357 } 358 keyFieldsList.add(fkField); 359 } 360 tableKeyFields = (JDBCCMP2xFieldBridge[]) keyFieldsList.toArray( 361 new JDBCCMP2xFieldBridge[keyFieldsList.size()]); 362 363 dataSource = metadata.getRelationMetaData().getDataSource(); 364 } 365 else 366 { 367 initializeForeignKeyFields(); 368 dataSource = hasForeignKey() ? entity.getDataSource() : relatedEntity.getDataSource(); 369 } 370 371 qualifiedTableName = SQLUtil.fixTableName(metadata.getRelationMetaData().getDefaultTableName(), dataSource); 376 tableName = SQLUtil.getTableNameWithoutSchema(qualifiedTableName); 377 378 relationManager = relatedCMRField.initRelationManager(this); 379 } 380 381 386 public void start() throws DeploymentException 387 { 388 cascadeDeleteStrategy = CascadeDeleteStrategy.getCascadeDeleteStrategy(this); 389 } 390 391 public boolean removeFromRelations(EntityEnterpriseContext ctx, Object [] oldRelationsRef) 392 { 393 load(ctx); 394 395 FieldState fieldState = getFieldState(ctx); 396 List value = fieldState.getValue(); 397 398 boolean removed = false; 399 if(!value.isEmpty()) 400 { 401 if(hasFKFieldsMappedToCMPFields) 402 { 403 if(isForeignKeyValid(value.get(0))) 404 { 405 cascadeDeleteStrategy.removedIds(ctx, oldRelationsRef, value); 406 removed = true; 407 } 408 } 409 else 410 { 411 cascadeDeleteStrategy.removedIds(ctx, oldRelationsRef, value); 412 removed = true; 413 } 414 } 415 return removed; 416 } 417 418 public void cascadeDelete(EntityEnterpriseContext ctx, List oldValues) 419 throws RemoveException , RemoteException 420 { 421 cascadeDeleteStrategy.cascadeDelete(ctx, oldValues); 422 } 423 424 public boolean isBatchCascadeDelete() 425 { 426 return (cascadeDeleteStrategy instanceof CascadeDeleteStrategy.BatchCascadeDeleteStrategy); 427 } 428 429 432 public JDBCStoreManager getJDBCStoreManager() 433 { 434 return manager; 435 } 436 437 440 public JDBCAbstractEntityBridge getEntity() 441 { 442 return entity; 443 } 444 445 448 public JDBCRelationshipRoleMetaData getMetaData() 449 { 450 return metadata; 451 } 452 453 456 public JDBCRelationMetaData getRelationMetaData() 457 { 458 return metadata.getRelationMetaData(); 459 } 460 461 464 public String getFieldName() 465 { 466 return metadata.getCMRFieldName(); 467 } 468 469 472 public String getQualifiedTableName() 473 { 474 return qualifiedTableName; 475 } 476 477 public String getTableName() 478 { 479 return tableName; 480 } 481 482 485 public DataSource getDataSource() 486 { 487 return dataSource; 488 } 489 490 493 public JDBCReadAheadMetaData getReadAhead() 494 { 495 return metadata.getReadAhead(); 496 } 497 498 public JDBCType getJDBCType() 499 { 500 return jdbcType; 501 } 502 503 public boolean isPrimaryKeyMember() 504 { 505 return false; 506 } 507 508 511 public boolean hasForeignKey() 512 { 513 return foreignKeyFields != null; 514 } 515 516 519 public boolean allFkFieldsMappedToPkFields() 520 { 521 return allFKFieldsMappedToPKFields; 522 } 523 524 527 public boolean isCollectionValued() 528 { 529 return metadata.getRelatedRole().isMultiplicityMany(); 530 } 531 532 535 public boolean isSingleValued() 536 { 537 return metadata.getRelatedRole().isMultiplicityOne(); 538 } 539 540 543 public JDBCFieldBridge[] getTableKeyFields() 544 { 545 return tableKeyFields; 546 } 547 548 551 public JDBCFieldBridge[] getForeignKeyFields() 552 { 553 return foreignKeyFields; 554 } 555 556 559 public JDBCAbstractCMRFieldBridge getRelatedCMRField() 560 { 561 return relatedCMRField; 562 } 563 564 567 public JDBCStoreManager getRelatedManager() 568 { 569 return relatedManager; 570 } 571 572 575 public EntityBridge getRelatedEntity() 576 { 577 return relatedEntity; 578 } 579 580 583 public JDBCEntityBridge getRelatedJDBCEntity() 584 { 585 return relatedEntity; 586 } 587 588 591 private final EntityContainer getRelatedContainer() 592 { 593 return (EntityContainer) relatedContainerRef.get(); 594 } 595 596 599 public final Class getRelatedLocalInterface() 600 { 601 return getRelatedContainer().getLocalClass(); 602 } 603 604 607 public final LocalProxyFactory getRelatedInvoker() 608 { 609 return getRelatedContainer().getLocalProxyFactory(); 610 } 611 612 616 public boolean isLoaded(EntityEnterpriseContext ctx) 617 { 618 return getFieldState(ctx).isLoaded; 619 } 620 621 627 public void addRelatedPKsWaitedForMe(EntityEnterpriseContext ctx) 628 { 629 final Map relatedPKsMap = getRelatedPKsWaitingForMyPK(); 630 synchronized(relatedPKsMap) 631 { 632 List relatedPKsWaitingForMe = (List ) relatedPKsMap.get(ctx.getId()); 633 if(relatedPKsWaitingForMe != null) 634 { 635 for(Iterator waitingPKsIter = relatedPKsWaitingForMe.iterator(); waitingPKsIter.hasNext();) 636 { 637 Object waitingPK = waitingPKsIter.next(); 638 waitingPKsIter.remove(); 639 if(isForeignKeyValid(waitingPK)) 640 { 641 createRelationLinks(ctx, waitingPK); 642 } 643 } 644 } 645 } 646 } 647 648 651 public boolean isReadOnly() 652 { 653 return getRelationMetaData().isReadOnly(); 654 } 655 656 659 public boolean isReadTimedOut(EntityEnterpriseContext ctx) 660 { 661 if(!isReadOnly()) 663 { 664 return true; 665 } 666 667 if(getRelationMetaData().getReadTimeOut() == -1) 669 { 670 return false; 671 } 672 673 long readInterval = System.currentTimeMillis() - getFieldState(ctx).getLastRead(); 674 return readInterval > getRelationMetaData().getReadTimeOut(); 675 } 676 677 681 public Object getValue(EntityEnterpriseContext ctx) 682 { 683 return getInstanceValue(ctx); 685 } 686 687 693 public void setValue(EntityEnterpriseContext ctx, Object value) 694 { 695 if(isReadOnly()) 696 { 697 throw new EJBException ("Field is read-only: fieldName=" + getFieldName()); 698 } 699 700 if(!JDBCEntityBridge.isEjbCreateDone(ctx)) 701 { 702 throw new IllegalStateException ("A CMR field cannot be set " + 703 "in ejbCreate; this should be done in the ejbPostCreate " + 704 "method instead [EJB 2.0 Spec. 10.5.2]."); 705 } 706 707 if(isCollectionValued() && value == null) 708 { 709 throw new IllegalArgumentException ("null cannot be assigned to a " + 710 "collection-valued cmr-field [EJB 2.0 Spec. 10.3.8]."); 711 } 712 722 723 setInstanceValue(ctx, value); 724 } 725 726 730 public Object getInstanceValue(EntityEnterpriseContext myCtx) 731 { 732 load(myCtx); 733 734 FieldState fieldState = getFieldState(myCtx); 735 if(isCollectionValued()) 736 { 737 return fieldState.getRelationSet(); 738 } 739 740 try 742 { 743 List value = fieldState.getValue(); 744 if(!value.isEmpty()) 745 { 746 Object fk = value.get(0); 747 return getRelatedEntityByFK(fk); 748 } 749 else if(foreignKeyFields != null) 750 { 751 Object relatedId = getRelatedIdFromContext(myCtx); 753 if(relatedId != null) 754 { 755 return getRelatedEntityByFK(relatedId); 756 } 757 } 758 return null; 759 } 760 catch(EJBException e) 761 { 762 throw e; 763 } 764 catch(Exception e) 765 { 766 throw new EJBException (e); 767 } 768 } 769 770 780 public EJBLocalObject getRelatedEntityByFK(Object fk) 781 { 782 EJBLocalObject relatedLocalObject = null; 783 final EntityContainer relatedContainer = getRelatedContainer(); 784 785 if(hasFKFieldsMappedToCMPFields 786 && relatedManager.getReadAheadCache().getPreloadDataMap(fk, false) == null ) 788 { 789 EJBLocalHome relatedHome = relatedContainer.getLocalProxyFactory().getEJBLocalHome(); 790 try 791 { 792 relatedLocalObject = (EJBLocalObject ) relatedFindByPrimaryKey.invoke(relatedHome, new Object []{fk}); 793 } 794 catch(Exception ignore) 795 { 796 } 798 } 799 else 800 { 801 relatedLocalObject = relatedContainer.getLocalProxyFactory().getEntityEJBLocalObject(fk); 802 } 803 804 return relatedLocalObject; 805 } 806 807 814 public boolean isForeignKeyValid(Object fk) 815 { 816 boolean valid; 817 if(relatedManager.getReadAheadCache().getPreloadDataMap(fk, false) != null) 818 { 819 valid = true; 820 } 821 else 822 { 823 EJBLocalHome relatedHome = getRelatedContainer().getLocalProxyFactory().getEJBLocalHome(); 824 try 825 { 826 relatedFindByPrimaryKey.invoke(relatedHome, new Object []{fk}); 827 valid = true; 828 } 829 catch(Exception ignore) 830 { 831 valid = false; 833 } 834 } 835 return valid; 836 } 837 838 842 public void setInstanceValue(EntityEnterpriseContext myCtx, Object newValue) 843 { 844 List newPks; 846 if(newValue instanceof Collection ) 847 { 848 Collection col = (Collection ) newValue; 849 if(!col.isEmpty()) 850 { 851 newPks = new ArrayList (col.size()); 852 for(Iterator iter = col.iterator(); iter.hasNext();) 853 { 854 Object localObject = iter.next(); 855 if(localObject != null) 856 { 857 Object relatedId = getRelatedPrimaryKey(localObject); 858 859 if(relatedPKFieldsByMyPKFields.size() > 0) 861 { 862 checkSetForeignKey(myCtx, relatedId); 863 } 864 865 newPks.add(relatedId); 866 } 867 } 868 } 869 else 870 { 871 newPks = Collections.EMPTY_LIST; 872 } 873 } 874 else 875 { 876 if(newValue != null) 877 { 878 newPks = Collections.singletonList(getRelatedPrimaryKey(newValue)); 879 } 880 else 881 { 882 newPks = Collections.EMPTY_LIST; 883 } 884 } 885 886 load(myCtx); 888 FieldState fieldState = getFieldState(myCtx); 889 890 if(newValue == fieldState.getRelationSet()) 892 { 893 return; 894 } 895 896 try 897 { 898 List value = fieldState.getValue(); 900 if(!value.isEmpty()) 901 { 902 Object [] curPks = value.toArray(new Object [value.size()]); 903 for(int i = 0; i < curPks.length; ++i) 904 { 905 destroyRelationLinks(myCtx, curPks[i]); 906 } 907 } 908 909 for(int i = 0; i < newPks.size(); ++i) 911 { 912 createRelationLinks(myCtx, newPks.get(i)); 913 } 914 } 915 catch(RuntimeException e) 916 { 917 throw e; 918 } 919 catch(Exception e) 920 { 921 throw new EJBException (e); 922 } 923 } 924 925 934 private void checkSetForeignKey(EntityEnterpriseContext myCtx, Object newValue) 935 throws IllegalStateException 936 { 937 JDBCFieldBridge[] pkFields = entity.getPrimaryKeyFields(); 938 for(int i = 0; i < pkFields.length; ++i) 939 { 940 JDBCCMP2xFieldBridge pkField = (JDBCCMP2xFieldBridge) pkFields[i]; 941 JDBCCMP2xFieldBridge relatedPkField = (JDBCCMP2xFieldBridge) relatedPKFieldsByMyPKFields.get(pkField); 942 if(relatedPkField != null) 943 { 944 Object comingValue = relatedPkField.getPrimaryKeyValue(newValue); 945 Object currentValue = pkField.getInstanceValue(myCtx); 946 947 if(!comingValue.equals(currentValue)) 949 { 950 throw new IllegalStateException ("Can't create relationship: CMR field " 951 + 952 entity.getEntityName() + 953 "." + 954 getFieldName() 955 + 956 " has foreign key fields mapped to the primary key columns." 957 + 958 " Primary key may only be set once in ejbCreate [EJB 2.0 Spec. 10.3.5]." 959 + 960 " primary key value is " + 961 currentValue 962 + " overriding value is " + comingValue); 963 } 964 } 965 } 966 } 967 968 974 public void createRelationLinks(EntityEnterpriseContext myCtx, Object relatedId) 975 { 976 createRelationLinks(myCtx, relatedId, true); 977 } 978 979 public void createRelationLinks(EntityEnterpriseContext myCtx, Object relatedId, boolean updateForeignKey) 980 { 981 if(isReadOnly()) 982 { 983 throw new EJBException ("Field is read-only: " + getFieldName()); 984 } 985 986 Transaction tx = getTransaction(); 989 if(metadata.isMultiplicityOne()) 990 { 991 Object oldRelatedId = relatedCMRField.invokeGetRelatedId(tx, relatedId); 992 if(oldRelatedId != null) 993 { 994 invokeRemoveRelation(tx, oldRelatedId, relatedId); 995 relatedCMRField.invokeRemoveRelation(tx, relatedId, oldRelatedId); 996 } 997 } 998 999 addRelation(myCtx, relatedId, updateForeignKey); 1000 relatedCMRField.invokeAddRelation(tx, relatedId, myCtx.getId()); 1001 } 1002 1003 1009 public void destroyRelationLinks(EntityEnterpriseContext myCtx, Object relatedId) 1010 { 1011 destroyRelationLinks(myCtx, relatedId, true); 1012 } 1013 1014 1023 public void destroyRelationLinks(EntityEnterpriseContext myCtx, 1024 Object relatedId, 1025 boolean updateValueCollection) 1026 { 1027 destroyRelationLinks(myCtx, relatedId, updateValueCollection, true); 1028 } 1029 1030 public void destroyRelationLinks(EntityEnterpriseContext myCtx, 1031 Object relatedId, 1032 boolean updateValueCollection, 1033 boolean updateForeignKey) 1034 { 1035 if(isReadOnly()) 1036 { 1037 throw new EJBException ("Field is read-only: " + getFieldName()); 1038 } 1039 1040 removeRelation(myCtx, relatedId, updateValueCollection, updateForeignKey); 1041 relatedCMRField.invokeRemoveRelation(getTransaction(), relatedId, myCtx.getId()); 1042 } 1043 1044 1047 public void scheduleChildrenForCascadeDelete(EntityEnterpriseContext ctx) 1048 { 1049 load(ctx); 1050 FieldState fieldState = getFieldState(ctx); 1051 List value = fieldState.getValue(); 1052 if(!value.isEmpty()) 1053 { 1054 Transaction tx = getTransaction(); 1055 for(int i = 0; i < value.size(); ++i) 1056 { 1057 relatedCMRField.invokeScheduleForCascadeDelete(tx, value.get(i)); 1058 } 1059 } 1060 } 1061 1062 1065 public void scheduleChildrenForBatchCascadeDelete(EntityEnterpriseContext ctx) 1066 { 1067 load(ctx); 1068 FieldState fieldState = getFieldState(ctx); 1069 List value = fieldState.getValue(); 1070 if(!value.isEmpty()) 1071 { 1072 Transaction tx = getTransaction(); 1073 for(int i = 0; i < value.size(); ++i) 1074 { 1075 relatedCMRField.invokeScheduleForBatchCascadeDelete(tx, value.get(i)); 1076 } 1077 } 1078 } 1079 1080 1083 private Object invokeScheduleForCascadeDelete(Transaction tx, Object myId) 1084 { 1085 try 1086 { 1087 EntityCache instanceCache = (EntityCache) manager.getContainer().getInstanceCache(); 1088 SecurityActions actions = SecurityActions.UTIL.getSecurityActions(); 1089 1090 CMRInvocation invocation = new CMRInvocation(); 1091 invocation.setCmrMessage(CMRMessage.SCHEDULE_FOR_CASCADE_DELETE); 1092 invocation.setEntrancy(Entrancy.NON_ENTRANT); 1093 invocation.setId(instanceCache.createCacheKey(myId)); 1094 invocation.setArguments(new Object []{this}); 1095 invocation.setTransaction(tx); 1096 invocation.setPrincipal(actions.getPrincipal()); 1097 invocation.setCredential(actions.getCredential()); 1098 invocation.setType(InvocationType.LOCAL); 1099 return manager.getContainer().invoke(invocation); 1100 } 1101 catch(EJBException e) 1102 { 1103 throw e; 1104 } 1105 catch(Exception e) 1106 { 1107 throw new EJBException ("Error in scheduleForCascadeDelete()", e); 1108 } 1109 } 1110 1111 1114 private Object invokeScheduleForBatchCascadeDelete(Transaction tx, Object myId) 1115 { 1116 try 1117 { 1118 EntityCache instanceCache = (EntityCache) manager.getContainer().getInstanceCache(); 1119 SecurityActions actions = SecurityActions.UTIL.getSecurityActions(); 1120 1121 CMRInvocation invocation = new CMRInvocation(); 1122 invocation.setCmrMessage(CMRMessage.SCHEDULE_FOR_BATCH_CASCADE_DELETE); 1123 invocation.setEntrancy(Entrancy.NON_ENTRANT); 1124 invocation.setId(instanceCache.createCacheKey(myId)); 1125 invocation.setArguments(new Object []{this}); 1126 invocation.setTransaction(tx); 1127 invocation.setPrincipal(actions.getPrincipal()); 1128 invocation.setCredential(actions.getCredential()); 1129 invocation.setType(InvocationType.LOCAL); 1130 return manager.getContainer().invoke(invocation); 1131 } 1132 catch(EJBException e) 1133 { 1134 throw e; 1135 } 1136 catch(Exception e) 1137 { 1138 throw new EJBException ("Error in scheduleForBatchCascadeDelete()", e); 1139 } 1140 } 1141 1142 1146 private Object invokeGetRelatedId(Transaction tx, Object myId) 1147 { 1148 try 1149 { 1150 EntityCache instanceCache = (EntityCache) manager.getContainer().getInstanceCache(); 1151 SecurityActions actions = SecurityActions.UTIL.getSecurityActions(); 1152 1153 CMRInvocation invocation = new CMRInvocation(); 1154 invocation.setCmrMessage(CMRMessage.GET_RELATED_ID); 1155 invocation.setEntrancy(Entrancy.NON_ENTRANT); 1156 invocation.setId(instanceCache.createCacheKey(myId)); 1157 invocation.setArguments(new Object []{this}); 1158 invocation.setTransaction(tx); 1159 invocation.setPrincipal(actions.getPrincipal()); 1160 invocation.setCredential(actions.getCredential()); 1161 invocation.setType(InvocationType.LOCAL); 1162 return manager.getContainer().invoke(invocation); 1163 } 1164 catch(EJBException e) 1165 { 1166 throw e; 1167 } 1168 catch(Exception e) 1169 { 1170 throw new EJBException ("Error in getRelatedId", e); 1171 } 1172 } 1173 1174 1178 private void invokeAddRelation(Transaction tx, Object myId, Object relatedId) 1179 { 1180 try 1181 { 1182 EntityCache instanceCache = (EntityCache) manager.getContainer().getInstanceCache(); 1183 SecurityActions actions = SecurityActions.UTIL.getSecurityActions(); 1184 1185 CMRInvocation invocation = new CMRInvocation(); 1186 invocation.setCmrMessage(CMRMessage.ADD_RELATION); 1187 invocation.setEntrancy(Entrancy.NON_ENTRANT); 1188 invocation.setId(instanceCache.createCacheKey(myId)); 1189 invocation.setArguments(new Object []{this, relatedId}); 1190 invocation.setTransaction(tx); 1191 invocation.setPrincipal(actions.getPrincipal()); 1192 invocation.setCredential(actions.getCredential()); 1193 invocation.setType(InvocationType.LOCAL); 1194 manager.getContainer().invoke(invocation); 1195 } 1196 catch(EJBException e) 1197 { 1198 throw e; 1199 } 1200 catch(Exception e) 1201 { 1202 throw new EJBException ("Error in addRelation", e); 1203 } 1204 } 1205 1206 1210 private void invokeRemoveRelation(Transaction tx, Object myId, Object relatedId) 1211 { 1212 try 1213 { 1214 EntityCache instanceCache = (EntityCache) manager.getContainer().getInstanceCache(); 1215 SecurityActions actions = SecurityActions.UTIL.getSecurityActions(); 1216 1217 CMRInvocation invocation = new CMRInvocation(); 1218 invocation.setCmrMessage(CMRMessage.REMOVE_RELATION); 1219 invocation.setEntrancy(Entrancy.NON_ENTRANT); 1220 invocation.setId(instanceCache.createCacheKey(myId)); 1221 invocation.setArguments(new Object []{this, relatedId}); 1222 invocation.setTransaction(tx); 1223 invocation.setPrincipal(actions.getPrincipal()); 1224 invocation.setCredential(actions.getCredential()); 1225 invocation.setType(InvocationType.LOCAL); 1226 manager.getContainer().invoke(invocation); 1227 } 1228 catch(EJBException e) 1229 { 1230 throw e; 1231 } 1232 catch(Exception e) 1233 { 1234 throw new EJBException ("Error in removeRelation", e); 1235 } 1236 } 1237 1238 1241 public Object getRelatedId(EntityEnterpriseContext myCtx) 1242 { 1243 if(isCollectionValued()) 1244 { 1245 throw new EJBException ("getRelatedId may only be called on a cmr-field with a multiplicity of one."); 1246 } 1247 1248 load(myCtx); 1249 List value = getFieldState(myCtx).getValue(); 1250 return value.isEmpty() ? null : value.get(0); 1251 } 1252 1253 1259 public Object getRelatedIdFromContext(EntityEnterpriseContext ctx) 1260 { 1261 Object relatedId = null; 1262 Object fkFieldValue; 1263 for(int i = 0; i < foreignKeyFields.length; ++i) 1264 { 1265 JDBCCMP2xFieldBridge fkField = foreignKeyFields[i]; 1266 fkFieldValue = fkField.getInstanceValue(ctx); 1267 if(fkFieldValue == null) 1268 { 1269 return null; 1270 } 1271 JDBCCMP2xFieldBridge relatedPKField = (JDBCCMP2xFieldBridge) relatedPKFieldsByMyFKFields.get(fkField); 1272 relatedId = relatedPKField.setPrimaryKeyValue(relatedId, fkFieldValue); 1273 } 1274 return relatedId; 1275 } 1276 1277 1280 public void addRelation(EntityEnterpriseContext myCtx, Object fk) 1281 { 1282 addRelation(myCtx, fk, true); 1283 relationManager.addRelation(this, myCtx.getId(), relatedCMRField, fk); 1284 } 1285 1286 private void addRelation(EntityEnterpriseContext myCtx, Object fk, boolean updateForeignKey) 1287 { 1288 checkSetForeignKey(myCtx, fk); 1289 1290 if(isReadOnly()) 1291 { 1292 throw new EJBException ("Field is read-only: " + getFieldName()); 1293 } 1294 1295 if(!JDBCEntityBridge.isEjbCreateDone(myCtx)) 1296 { 1297 throw new IllegalStateException ("A CMR field cannot be set or added " + 1298 "to a relationship in ejbCreate; this should be done in the " + 1299 "ejbPostCreate method instead [EJB 2.0 Spec. 10.5.2]."); 1300 } 1301 1302 FieldState myState = getFieldState(myCtx); 1304 myState.addRelation(fk); 1305 1306 if(hasForeignKey() && updateForeignKey) 1308 { 1309 setForeignKey(myCtx, fk); 1310 } 1311 } 1312 1313 1316 public void removeRelation(EntityEnterpriseContext myCtx, Object fk) 1317 { 1318 removeRelation(myCtx, fk, true, true); 1319 relationManager.removeRelation(this, myCtx.getId(), relatedCMRField, fk); 1320 } 1321 1322 private void removeRelation(EntityEnterpriseContext myCtx, 1323 Object fk, 1324 boolean updateValueCollection, 1325 boolean updateForeignKey) 1326 { 1327 if(isReadOnly()) 1328 { 1329 throw new EJBException ("Field is read-only: " + getFieldName()); 1330 } 1331 1332 if(updateValueCollection) 1334 { 1335 FieldState myState = getFieldState(myCtx); 1336 myState.removeRelation(fk); 1337 } 1338 1339 if(hasForeignKey() && updateForeignKey) 1341 { 1342 setForeignKey(myCtx, null); 1343 } 1344 } 1345 1346 1352 private void load(EntityEnterpriseContext myCtx) 1353 { 1354 FieldState fieldState = getFieldState(myCtx); 1356 if(fieldState.isLoaded()) 1357 { 1358 return; 1359 } 1360 1361 if(log.isTraceEnabled()) 1363 { 1364 log.trace("Read ahead cahce load: cmrField=" + getFieldName() + " pk=" + myCtx.getId()); 1365 } 1366 1367 manager.getReadAheadCache().load(myCtx); 1368 if(fieldState.isLoaded()) 1369 { 1370 return; 1371 } 1372 1373 Collection values; 1375 if(hasForeignKey()) 1376 { 1377 1383 boolean loadWithManager = false; 1384 Object fk = null; 1385 for(int i = 0; i < foreignKeyFields.length; ++i) 1386 { 1387 JDBCCMP2xFieldBridge fkField = foreignKeyFields[i]; 1388 if(!fkField.isLoaded(myCtx)) 1390 { 1391 loadWithManager = true; 1392 break; 1393 } 1394 1395 Object fkFieldValue = fkField.getInstanceValue(myCtx); 1396 if(fkFieldValue == null) 1398 { 1399 fk = null; 1400 break; 1401 } 1402 JDBCCMP2xFieldBridge relatedPKField = (JDBCCMP2xFieldBridge) relatedPKFieldsByMyFKFields.get(fkField); 1403 fk = relatedPKField.setPrimaryKeyValue(fk, fkFieldValue); 1404 } 1405 1406 if(loadWithManager) 1407 { 1408 values = manager.loadRelation(this, myCtx.getId()); 1409 } 1410 else 1411 { 1412 values = (fk == null ? Collections.EMPTY_LIST : Collections.singletonList(fk)); 1413 } 1414 } 1415 else 1416 { 1417 values = manager.loadRelation(this, myCtx.getId()); 1418 } 1419 load(myCtx, values); 1420 } 1421 1422 public void load(EntityEnterpriseContext myCtx, Collection values) 1423 { 1424 if(isSingleValued() && values.size() > 1) 1426 { 1427 throw new EJBException ("Data contains multiple values, but this cmr field is single valued: " + values); 1428 } 1429 1430 FieldState fieldState = getFieldState(myCtx); 1432 fieldState.loadRelations(values); 1433 1434 if(hasForeignKey()) 1436 { 1437 if(!values.isEmpty()) 1439 { 1440 Object loadedValue = values.iterator().next(); 1441 for(int i = 0; i < foreignKeyFields.length; ++i) 1442 { 1443 JDBCCMP2xFieldBridge fkField = foreignKeyFields[i]; 1444 Object fieldValue = fkField.getPrimaryKeyValue(loadedValue); 1445 fkField.updateState(myCtx, fieldValue); 1446 } 1447 } 1448 1449 List realValue = fieldState.getValue(); 1451 Object fk = realValue.isEmpty() ? null : realValue.get(0); 1452 setForeignKey(myCtx, fk); 1453 } 1454 1455 JDBCEntityBridge.setCreated(myCtx); 1456 } 1457 1458 1461 public void setForeignKey(EntityEnterpriseContext myCtx, Object fk) 1462 { 1463 if(!hasForeignKey()) 1464 { 1465 throw new EJBException (getFieldName() + " CMR field does not have a foreign key to set."); 1466 } 1467 1468 for(int i = 0; i < foreignKeyFields.length; ++i) 1469 { 1470 JDBCCMP2xFieldBridge fkField = foreignKeyFields[i]; 1471 Object fieldValue = fkField.getPrimaryKeyValue(fk); 1472 fkField.setInstanceValue(myCtx, fieldValue); 1473 } 1474 } 1475 1476 1479 public void initInstance(EntityEnterpriseContext ctx) 1480 { 1481 getFieldState(ctx).loadRelations(Collections.EMPTY_SET); 1483 1484 if(foreignKeyFields == null) 1485 { 1486 return; 1487 } 1488 1489 for(int i = 0; i < foreignKeyFields.length; ++i) 1490 { 1491 JDBCCMP2xFieldBridge foreignKeyField = foreignKeyFields[i]; 1492 if(!foreignKeyField.isFKFieldMappedToCMPField()) 1493 { 1494 foreignKeyField.setInstanceValue(ctx, null); 1495 } 1496 } 1497 } 1498 1499 1502 public void resetPersistenceContext(EntityEnterpriseContext ctx) 1503 { 1504 if(!isReadTimedOut(ctx)) 1506 { 1507 return; 1508 } 1509 1510 JDBCContext jdbcCtx = (JDBCContext) ctx.getPersistenceContext(); 1512 1518 jdbcCtx.setFieldState(jdbcContextIndex, null); 1519 1520 if(foreignKeyFields == null) 1521 { 1522 return; 1523 } 1524 1525 for(int i = 0; i < foreignKeyFields.length; ++i) 1526 { 1527 JDBCCMP2xFieldBridge foreignKeyField = foreignKeyFields[i]; 1528 if(!foreignKeyField.isFKFieldMappedToCMPField()) 1529 { 1530 foreignKeyField.resetPersistenceContext(ctx); 1531 } 1532 } 1533 } 1534 1535 public int setInstanceParameters(PreparedStatement ps, 1536 int parameterIndex, 1537 EntityEnterpriseContext ctx) 1538 { 1539 if(foreignKeyFields == null) 1540 { 1541 return parameterIndex; 1542 } 1543 1544 List value = getFieldState(ctx).getValue(); 1545 Object fk = (value.isEmpty() ? null : value.get(0)); 1546 1547 for(int i = 0; i < foreignKeyFields.length; ++i) 1548 { 1549 parameterIndex = foreignKeyFields[i].setPrimaryKeyParameters(ps, parameterIndex, fk); 1550 } 1551 1552 return parameterIndex; 1553 } 1554 1555 public int loadInstanceResults(ResultSet rs, 1556 int parameterIndex, 1557 EntityEnterpriseContext ctx) 1558 { 1559 if(!hasForeignKey()) 1560 { 1561 return parameterIndex; 1562 } 1563 1564 Object [] ref = new Object [1]; 1566 parameterIndex = loadArgumentResults(rs, parameterIndex, ref); 1567 1568 FieldState fieldState = getFieldState(ctx); 1570 if(!fieldState.isLoaded()) 1571 { 1572 if(ref[0] != null) 1573 { 1574 load(ctx, Collections.singleton(ref[0])); 1575 } 1576 else 1577 { 1578 load(ctx, Collections.EMPTY_SET); 1579 } 1580 } 1581 return parameterIndex; 1582 } 1583 1584 public int loadArgumentResults(ResultSet rs, int parameterIndex, Object [] fkRef) 1585 { 1586 if(foreignKeyFields == null) 1587 { 1588 return parameterIndex; 1589 } 1590 1591 boolean fkIsNull = false; 1592 1593 Object [] argumentRef = new Object [1]; 1595 for(int i = 0; i < foreignKeyFields.length; ++i) 1596 { 1597 JDBCCMPFieldBridge field = foreignKeyFields[i]; 1598 parameterIndex = field.loadArgumentResults(rs, parameterIndex, argumentRef); 1599 1600 if(fkIsNull) 1601 { 1602 continue; 1603 } 1604 if(field.getPrimaryKeyField() != null) 1605 { 1606 if(argumentRef[0] == null) 1611 { 1612 fkRef[0] = null; 1613 fkIsNull = true; 1614 } 1615 else 1616 { 1617 if(fkRef[0] == null) 1619 { 1620 fkRef[0] = relatedEntity.createPrimaryKeyInstance(); 1621 } 1622 try 1623 { 1624 field.getPrimaryKeyField().set(fkRef[0], argumentRef[0]); 1626 } 1627 catch(Exception e) 1628 { 1629 throw new EJBException ("Internal error setting foreign-key field " + getFieldName(), e); 1631 } 1632 } 1633 } 1634 else 1635 { 1636 fkRef[0] = argumentRef[0]; 1638 } 1639 } 1640 return parameterIndex; 1641 } 1642 1643 1647 public boolean isDirty(EntityEnterpriseContext ctx) 1648 { 1649 return foreignKeyFields == null ? relationManager.isDirty() : false; 1650 } 1651 1652 public boolean invalidateCache(EntityEnterpriseContext ctx) 1653 { 1654 JDBCContext jdbcCtx = (JDBCContext) ctx.getPersistenceContext(); 1655 FieldState fieldState = (FieldState) jdbcCtx.getFieldState(jdbcContextIndex); 1656 return fieldState == null ? false : fieldState.isChanged(); 1657 } 1658 1659 1666 public void setClean(EntityEnterpriseContext ctx) 1667 { 1668 throw new UnsupportedOperationException (); 1669 } 1670 1671 public boolean isCMPField() 1672 { 1673 return false; 1674 } 1675 1676 public JDBCEntityPersistenceStore getManager() 1677 { 1678 return manager; 1679 } 1680 1681 public boolean hasFKFieldsMappedToCMPFields() 1682 { 1683 return hasFKFieldsMappedToCMPFields; 1684 } 1685 1686 public void addRelatedPKWaitingForMyPK(Object myPK, Object relatedPK) 1687 { 1688 Map relatedPKsWaitingForMyPK = getRelatedPKsWaitingForMyPK(); 1689 synchronized(relatedPKsWaitingForMyPK) 1690 { 1691 List relatedPKs = (List ) relatedPKsWaitingForMyPK.get(myPK); 1692 if(relatedPKs == null) 1693 { 1694 relatedPKs = new ArrayList (1); 1695 relatedPKsWaitingForMyPK.put(myPK, relatedPKs); 1696 } 1697 relatedPKs.add(relatedPK); 1698 } 1699 } 1700 1701 public void removeRelatedPKWaitingForMyPK(Object myPK, Object relatedPK) 1702 { 1703 final Map relatedPKMap = getRelatedPKsWaitingForMyPK(); 1704 synchronized(relatedPKMap) 1705 { 1706 List relatedPKs = (List ) relatedPKMap.get(myPK); 1707 if(relatedPKs != null) 1708 { 1709 relatedPKs.remove(relatedPK); 1710 } 1711 } 1712 } 1713 1714 1717 private FieldState getFieldState(EntityEnterpriseContext ctx) 1718 { 1719 JDBCContext jdbcCtx = (JDBCContext) ctx.getPersistenceContext(); 1720 FieldState fieldState = (FieldState) jdbcCtx.getFieldState(jdbcContextIndex); 1721 if(fieldState == null) 1722 { 1723 fieldState = new FieldState(ctx); 1724 jdbcCtx.setFieldState(jdbcContextIndex, fieldState); 1725 } 1726 return fieldState; 1727 } 1728 1729 1734 private void initializeForeignKeyFields() 1735 throws DeploymentException 1736 { 1737 Collection foreignKeys = metadata.getRelatedRole().getKeyFields(); 1738 1739 Map fkFieldsByRelatedPKFields = new HashMap (); 1741 for(Iterator i = foreignKeys.iterator(); i.hasNext();) 1742 { 1743 JDBCCMPFieldMetaData fkFieldMetaData = (JDBCCMPFieldMetaData) i.next(); 1744 JDBCCMP2xFieldBridge relatedPKField = 1745 (JDBCCMP2xFieldBridge) relatedEntity.getFieldByName(fkFieldMetaData.getFieldName()); 1746 1747 String fkColumnName = fkFieldMetaData.getColumnName(); 1749 JDBCCMP2xFieldBridge fkField = null; 1750 1751 JDBCFieldBridge[] tableFields = entity.getTableFields(); 1753 for(int tableInd = 0; tableInd < tableFields.length && fkField == null; ++tableInd) 1754 { 1755 JDBCCMP2xFieldBridge cmpField = (JDBCCMP2xFieldBridge) tableFields[tableInd]; 1756 if(fkColumnName.equals(cmpField.getColumnName())) 1757 { 1758 hasFKFieldsMappedToCMPFields = true; 1759 1760 fkField = new JDBCCMP2xFieldBridge((JDBCStoreManager) cmpField.getManager(), relatedPKField.getFieldName(), 1763 relatedPKField.getFieldType(), 1764 cmpField.getJDBCType(), relatedPKField.isReadOnly(), 1766 relatedPKField.getReadTimeOut(), 1767 relatedPKField.getPrimaryKeyClass(), 1768 relatedPKField.getPrimaryKeyField(), 1769 cmpField, this, 1771 fkColumnName); 1772 1773 if(cmpField.isPrimaryKeyMember()) 1774 { 1775 relatedPKFieldsByMyPKFields.put(cmpField, relatedPKField); 1776 } 1777 } 1778 } 1779 1780 if(fkField == null) 1782 { 1783 fkField = new JDBCCMP2xFieldBridge(manager, 1784 fkFieldMetaData, 1785 manager.getJDBCTypeFactory().getJDBCType(fkFieldMetaData)); 1786 } 1787 1788 fkFieldsByRelatedPKFields.put(relatedPKField, fkField); relatedPKFieldsByMyFKFields.put(fkField, relatedPKField); 1790 } 1791 1792 if(fkFieldsByRelatedPKFields.size() > 0) 1796 { 1797 JDBCFieldBridge[] relatedPKFields = relatedEntity.getPrimaryKeyFields(); 1798 List fkList = new ArrayList (relatedPKFields.length); 1799 for(int i = 0; i < relatedPKFields.length; ++i) 1800 { 1801 JDBCCMPFieldBridge fkField = (JDBCCMPFieldBridge) fkFieldsByRelatedPKFields.remove(relatedPKFields[i]); 1802 fkList.add(fkField); 1803 } 1804 foreignKeyFields = (JDBCCMP2xFieldBridge[]) fkList.toArray(new JDBCCMP2xFieldBridge[fkList.size()]); 1805 } 1806 else 1807 { 1808 foreignKeyFields = null; 1809 } 1810 1811 allFKFieldsMappedToPKFields = relatedPKFieldsByMyPKFields.size() > 0 1813 && relatedPKFieldsByMyPKFields.size() == foreignKeyFields.length; 1814 1815 if(foreignKeyFields != null) 1816 { 1817 jdbcType = new CMRJDBCType(Arrays.asList(foreignKeyFields)); 1818 } 1819 } 1820 1821 private Transaction getTransaction() 1822 { 1823 try 1824 { 1825 EntityContainer container = getJDBCStoreManager().getContainer(); 1826 TransactionManager tm = container.getTransactionManager(); 1827 return tm.getTransaction(); 1828 } 1829 catch(SystemException e) 1830 { 1831 throw new EJBException ("Error getting transaction from the transaction manager", e); 1832 } 1833 } 1834 1835 1838 private Map getRelatedPKsWaitingForMyPK() 1839 { 1840 return (Map ) relatedPKValuesWaitingForMyPK.get(); 1841 } 1842 1843 private RelationDataManager initRelationManager(JDBCCMRFieldBridge relatedField) 1844 { 1845 if(relationManager == null) 1846 { 1847 if(metadata.getRelationMetaData().isTableMappingStyle()) 1848 { 1849 relationManager = new M2MRelationManager(this, relatedField); 1850 } 1851 else 1852 { 1853 relationManager = EMPTY_RELATION_MANAGER; 1854 } 1855 } 1856 return relationManager; 1857 } 1858 1859 private Object getRelatedPrimaryKey(Object localObject) 1860 { 1861 Object relatedId; 1862 if(relatedEntity.getLocalInterface().isAssignableFrom(localObject.getClass())) 1863 { 1864 EJBLocalObject local = (EJBLocalObject ) localObject; 1865 try 1866 { 1867 relatedId = local.getPrimaryKey(); 1868 } 1869 catch(NoSuchObjectLocalException e) 1870 { 1871 throw new IllegalArgumentException (e.getMessage()); 1872 } 1873 1874 1880 } 1881 else 1882 { 1883 throw new IllegalArgumentException ("The values of this field must be of type " + 1884 relatedEntity.getLocalInterface().getName()); 1885 } 1886 return relatedId; 1887 } 1888 1889 public String toString() 1890 { 1891 return entity.getEntityName() + '.' + getFieldName(); 1892 } 1893 1894 private final class FieldState 1895 { 1896 private final EntityEnterpriseContext ctx; 1897 private List [] setHandle = new List [1]; 1898 private Set addedRelations; 1899 private Set removedRelations; 1900 private Set relationSet; 1901 private boolean isLoaded = false; 1902 private final long lastRead = -1; 1903 1904 private boolean changed; 1905 1906 public FieldState(EntityEnterpriseContext ctx) 1907 { 1908 this.ctx = ctx; 1909 setHandle[0] = new ArrayList (); 1910 } 1911 1912 1915 public List getValue() 1916 { 1917 if(!isLoaded) 1918 { 1919 throw new EJBException ("CMR field value not loaded yet"); 1920 } 1921 return Collections.unmodifiableList(setHandle[0]); 1922 } 1923 1924 1927 public boolean isLoaded() 1928 { 1929 return isLoaded; 1930 } 1931 1932 1935 public long getLastRead() 1936 { 1937 return lastRead; 1938 } 1939 1940 1943 public void addRelation(Object fk) 1944 { 1945 if(isLoaded) 1946 { 1947 setHandle[0].add(fk); 1948 } 1949 else 1950 { 1951 if(removedRelations == null) 1952 { 1953 removedRelations = new HashSet (); 1954 addedRelations = new HashSet (); 1955 } 1956 removedRelations.remove(fk); 1957 addedRelations.add(fk); 1958 } 1959 1960 changed = true; 1961 } 1962 1963 1966 public void removeRelation(Object fk) 1967 { 1968 if(isLoaded) 1969 { 1970 setHandle[0].remove(fk); 1971 } 1972 else 1973 { 1974 if(removedRelations == null) 1975 { 1976 removedRelations = new HashSet (); 1977 addedRelations = new HashSet (); 1978 } 1979 addedRelations.remove(fk); 1980 removedRelations.add(fk); 1981 } 1982 1983 changed = true; 1984 } 1985 1986 1989 public void loadRelations(Collection values) 1990 { 1991 if(isLoaded) 1993 { 1994 throw new EJBException ("CMR field value is already loaded"); 1995 } 1996 1997 setHandle[0].clear(); 1999 2000 setHandle[0].addAll(values); 2002 2003 if(removedRelations != null) 2004 { 2005 setHandle[0].removeAll(removedRelations); 2007 removedRelations = null; 2008 } 2009 2010 if(addedRelations != null) 2011 { 2012 setHandle[0].removeAll(addedRelations); 2015 setHandle[0].addAll(addedRelations); 2016 addedRelations = null; 2017 } 2018 2019 isLoaded = true; 2021 } 2022 2023 2026 public Set getRelationSet() 2027 { 2028 if(!isLoaded) 2029 { 2030 throw new EJBException ("CMR field value not loaded yet"); 2031 } 2032 2033 if(ctx.isReadOnly()) 2034 { 2035 return new RelationSet(JDBCCMRFieldBridge.this, 2037 ctx, 2038 new List []{new ArrayList (setHandle[0])}, 2039 true); 2040 } 2041 2042 if(relationSet != null) 2044 { 2045 return relationSet; 2046 } 2047 2048 try 2050 { 2051 EntityContainer container = getJDBCStoreManager().getContainer(); 2053 TransactionManager tm = container.getTransactionManager(); 2054 Transaction tx = tm.getTransaction(); 2055 2056 if(tx != null && (tx.getStatus() == Status.STATUS_ACTIVE || tx.getStatus() == Status.STATUS_PREPARING)) 2058 { 2059 relationSet = new RelationSet(JDBCCMRFieldBridge.this, ctx, setHandle, false); 2061 TxSynchronization sync = new TxSynchronization(FieldState.this); 2062 tx.registerSynchronization(sync); 2063 } 2064 else 2065 { 2066 relationSet = new RelationSet(JDBCCMRFieldBridge.this, ctx, new List [1], false); 2068 } 2069 2070 return relationSet; 2071 } 2072 catch(SystemException e) 2073 { 2074 throw new EJBException ("Error while creating RelationSet", e); 2075 } 2076 catch(RollbackException e) 2077 { 2078 throw new EJBException ("Error while creating RelationSet", e); 2079 } 2080 } 2081 2082 2085 public void invalidate() 2086 { 2087 List currentList = null; 2092 if(setHandle != null && setHandle.length > 0) 2093 { 2094 currentList = setHandle[0]; 2095 setHandle[0] = null; 2096 } 2097 setHandle = new List [1]; 2098 setHandle[0] = currentList; 2099 2100 relationSet = null; 2101 changed = false; 2102 } 2103 2104 public boolean isChanged() 2105 { 2106 return changed; 2107 } 2108 } 2109 2110 private final static class CMRJDBCType implements JDBCType 2111 { 2112 private final String [] columnNames; 2113 private final Class [] javaTypes; 2114 private final int[] jdbcTypes; 2115 private final String [] sqlTypes; 2116 private final boolean[] notNull; 2117 2118 private CMRJDBCType(List fields) 2119 { 2120 List columnNamesList = new ArrayList (); 2121 List javaTypesList = new ArrayList (); 2122 List jdbcTypesList = new ArrayList (); 2123 List sqlTypesList = new ArrayList (); 2124 List notNullList = new ArrayList (); 2125 2126 for(Iterator iter = fields.iterator(); iter.hasNext();) 2127 { 2128 JDBCCMPFieldBridge field = (JDBCCMPFieldBridge) iter.next(); 2129 JDBCType type = field.getJDBCType(); 2130 for(int i = 0; i < type.getColumnNames().length; i++) 2131 { 2132 columnNamesList.add(type.getColumnNames()[i]); 2133 javaTypesList.add(type.getJavaTypes()[i]); 2134 jdbcTypesList.add(new Integer (type.getJDBCTypes()[i])); 2135 sqlTypesList.add(type.getSQLTypes()[i]); 2136 notNullList.add(new Boolean (type.getNotNull()[i])); 2137 } 2138 } 2139 columnNames = (String []) columnNamesList.toArray(new String [columnNamesList.size()]); 2140 javaTypes = (Class []) javaTypesList.toArray(new Class [javaTypesList.size()]); 2141 sqlTypes = (String []) sqlTypesList.toArray(new String [sqlTypesList.size()]); 2142 2143 jdbcTypes = new int[jdbcTypesList.size()]; 2144 for(int i = 0; i < jdbcTypes.length; i++) 2145 { 2146 jdbcTypes[i] = ((Integer ) jdbcTypesList.get(i)).intValue(); 2147 } 2148 2149 notNull = new boolean[notNullList.size()]; 2150 for(int i = 0; i < notNull.length; i++) 2151 { 2152 notNull[i] = ((Boolean ) notNullList.get(i)).booleanValue(); 2153 } 2154 } 2155 2156 public String [] getColumnNames() 2157 { 2158 return columnNames; 2159 } 2160 2161 public Class [] getJavaTypes() 2162 { 2163 return javaTypes; 2164 } 2165 2166 public int[] getJDBCTypes() 2167 { 2168 return jdbcTypes; 2169 } 2170 2171 public String [] getSQLTypes() 2172 { 2173 return sqlTypes; 2174 } 2175 2176 public boolean[] getNotNull() 2177 { 2178 return notNull; 2179 } 2180 2181 public boolean[] getAutoIncrement() 2182 { 2183 return new boolean[]{false}; 2184 } 2185 2186 public Object getColumnValue(int index, Object value) 2187 { 2188 throw new UnsupportedOperationException (); 2189 } 2190 2191 public Object setColumnValue(int index, Object value, Object columnValue) 2192 { 2193 throw new UnsupportedOperationException (); 2194 } 2195 2196 public boolean hasMapper() 2197 { 2198 throw new UnsupportedOperationException ("hasMapper is not implemented."); 2199 } 2200 2201 public boolean isSearchable() 2202 { 2203 throw new UnsupportedOperationException ("isSearchable is not implemented."); 2204 } 2205 2206 public JDBCResultSetReader[] getResultSetReaders() 2207 { 2208 throw new UnsupportedOperationException (); 2210 } 2211 2212 public JDBCParameterSetter[] getParameterSetter() 2213 { 2214 throw new UnsupportedOperationException (); 2215 } 2216 } 2217 2218 private final static class TxSynchronization implements Synchronization 2219 { 2220 private final WeakReference fieldStateRef; 2221 2222 private TxSynchronization(FieldState fieldState) 2223 { 2224 if(fieldState == null) 2225 { 2226 throw new IllegalArgumentException ("fieldState is null"); 2227 } 2228 this.fieldStateRef = new WeakReference (fieldState); 2229 } 2230 2231 public void beforeCompletion() 2232 { 2233 FieldState fieldState = (FieldState) fieldStateRef.get(); 2238 if(fieldState != null) 2239 { 2240 fieldState.invalidate(); 2241 } 2242 } 2243 2244 public void afterCompletion(int status) 2245 { 2246 } 2247 } 2248 2249 public static interface RelationDataManager 2250 { 2251 void addRelation(JDBCCMRFieldBridge field, Object id, JDBCCMRFieldBridge relatedField, Object relatedId); 2252 2253 void removeRelation(JDBCCMRFieldBridge field, Object id, JDBCCMRFieldBridge relatedField, Object relatedId); 2254 2255 boolean isDirty(); 2256 2257 RelationData getRelationData(); 2258 } 2259 2260 private static final RelationDataManager EMPTY_RELATION_MANAGER = new RelationDataManager() 2261 { 2262 public void addRelation(JDBCCMRFieldBridge field, Object id, JDBCCMRFieldBridge relatedField, Object relatedId) 2263 { 2264 } 2265 2266 public void removeRelation(JDBCCMRFieldBridge field, 2267 Object id, 2268 JDBCCMRFieldBridge relatedField, 2269 Object relatedId) 2270 { 2271 } 2272 2273 public boolean isDirty() 2274 { 2275 return false; 2276 } 2277 2278 public RelationData getRelationData() 2279 { 2280 throw new UnsupportedOperationException (); 2281 } 2282 }; 2283 2284 public static class M2MRelationManager 2285 implements RelationDataManager 2286 { 2287 private final JDBCCMRFieldBridge leftField; 2288 private final JDBCCMRFieldBridge rightField; 2289 2290 private final TransactionLocal relationData = new TransactionLocal() 2291 { 2292 protected Object initialValue() 2293 { 2294 return new RelationData(leftField, rightField); 2295 } 2296 }; 2297 2298 public M2MRelationManager(JDBCCMRFieldBridge leftField, JDBCCMRFieldBridge rightField) 2299 { 2300 this.leftField = leftField; 2301 this.rightField = rightField; 2302 } 2303 2304 public void addRelation(JDBCCMRFieldBridge field, 2305 Object id, 2306 JDBCCMRFieldBridge relatedField, 2307 Object relatedId) 2308 { 2309 final RelationData local = getRelationData(); 2310 local.addRelation(field, id, relatedField, relatedId); 2311 } 2312 2313 public void removeRelation(JDBCCMRFieldBridge field, 2314 Object id, 2315 JDBCCMRFieldBridge relatedField, 2316 Object relatedId) 2317 { 2318 RelationData local = getRelationData(); 2319 local.removeRelation(field, id, relatedField, relatedId); 2320 } 2321 2322 public boolean isDirty() 2323 { 2324 RelationData local = getRelationData(); 2325 return local.isDirty(); 2326 } 2327 2328 public RelationData getRelationData() 2329 { 2330 final RelationData local = (RelationData) relationData.get(); 2331 return local; 2332 } 2333 } 2334 2335 interface SecurityActions 2336 { 2337 class UTIL 2338 { 2339 static SecurityActions getSecurityActions() 2340 { 2341 return System.getSecurityManager() == null ? NON_PRIVILEGED : PRIVILEGED; 2342 } 2343 } 2344 2345 SecurityActions NON_PRIVILEGED = new SecurityActions() 2346 { 2347 public Principal getPrincipal() 2348 { 2349 return SecurityAssociation.getPrincipal(); 2350 } 2351 2352 public Object getCredential() 2353 { 2354 return SecurityAssociation.getCredential(); 2355 } 2356 }; 2357 2358 SecurityActions PRIVILEGED = new SecurityActions() 2359 { 2360 private final PrivilegedAction getPrincipalAction = new PrivilegedAction () 2361 { 2362 public Object run() 2363 { 2364 return SecurityAssociation.getPrincipal(); 2365 } 2366 }; 2367 2368 private final PrivilegedAction getCredentialAction = new PrivilegedAction () 2369 { 2370 public Object run() 2371 { 2372 return SecurityAssociation.getCredential(); 2373 } 2374 }; 2375 2376 public Principal getPrincipal() 2377 { 2378 return (Principal ) AccessController.doPrivileged(getPrincipalAction); 2379 } 2380 2381 public Object getCredential() 2382 { 2383 return AccessController.doPrivileged(getCredentialAction); 2384 } 2385 }; 2386 2387 Principal getPrincipal(); 2388 2389 Object getCredential(); 2390 } 2391} 2392 | Popular Tags |