1 22 package org.jboss.ejb.plugins.cmp.jdbc.bridge; 23 24 import java.lang.reflect.Field ; 25 26 import javax.ejb.EJBException ; 27 28 import org.jboss.deployment.DeploymentException; 29 import org.jboss.ejb.EntityEnterpriseContext; 30 31 import org.jboss.ejb.plugins.cmp.jdbc.JDBCContext; 32 import org.jboss.ejb.plugins.cmp.jdbc.JDBCStoreManager; 33 import org.jboss.ejb.plugins.cmp.jdbc.JDBCType; 34 import org.jboss.ejb.plugins.cmp.jdbc.CMPFieldStateFactory; 35 import org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCCMPFieldMetaData; 36 37 53 public class JDBCCMP2xFieldBridge extends JDBCAbstractCMPFieldBridge 54 { 55 56 private final String columnName; 57 58 59 private final JDBCCMP2xFieldBridge cmpFieldIAmMappedTo; 60 61 62 private ChainLink cmrChainLink; 63 64 66 public JDBCCMP2xFieldBridge(JDBCStoreManager manager, 67 JDBCCMPFieldMetaData metadata) 68 throws DeploymentException 69 { 70 super(manager, metadata); 71 cmpFieldIAmMappedTo = null; 72 columnName = metadata.getColumnName(); 73 } 74 75 public JDBCCMP2xFieldBridge(JDBCStoreManager manager, 76 JDBCCMPFieldMetaData metadata, 77 CMPFieldStateFactory stateFactory, 78 boolean checkDirtyAfterGet) 79 throws DeploymentException 80 { 81 this(manager, metadata); 82 this.stateFactory = stateFactory; 83 this.checkDirtyAfterGet = checkDirtyAfterGet; 84 } 85 86 public JDBCCMP2xFieldBridge(JDBCCMP2xFieldBridge cmpField, 87 CMPFieldStateFactory stateFactory, 88 boolean checkDirtyAfterGet) 89 throws DeploymentException 90 { 91 this( 92 (JDBCStoreManager) cmpField.getManager(), 93 cmpField.getFieldName(), 94 cmpField.getFieldType(), 95 cmpField.getJDBCType(), 96 cmpField.isReadOnly(), cmpField.getReadTimeOut(), 98 cmpField.getPrimaryKeyClass(), 99 cmpField.getPrimaryKeyField(), 100 cmpField, 101 null, cmpField.getColumnName() 103 ); 104 this.stateFactory = stateFactory; 105 this.checkDirtyAfterGet = checkDirtyAfterGet; 106 } 107 108 111 public JDBCCMP2xFieldBridge(JDBCStoreManager manager, 112 JDBCCMPFieldMetaData metadata, 113 JDBCType jdbcType) 114 throws DeploymentException 115 { 116 super(manager, metadata, jdbcType); 117 cmpFieldIAmMappedTo = null; 118 columnName = metadata.getColumnName(); 119 } 120 121 125 public JDBCCMP2xFieldBridge(JDBCStoreManager manager, 126 String fieldName, 127 Class fieldType, 128 JDBCType jdbcType, 129 boolean readOnly, 130 long readTimeOut, 131 Class primaryKeyClass, 132 Field primaryKeyField, 133 JDBCCMP2xFieldBridge cmpFieldIAmMappedTo, 134 JDBCCMRFieldBridge myCMRField, 135 String columnName) 136 throws DeploymentException 137 { 138 super( 139 manager, 140 fieldName, 141 fieldType, 142 jdbcType, 143 readOnly, 144 readTimeOut, 145 primaryKeyClass, 146 primaryKeyField, 147 cmpFieldIAmMappedTo.getFieldIndex(), 148 cmpFieldIAmMappedTo.getTableIndex(), 149 cmpFieldIAmMappedTo.checkDirtyAfterGet, 150 cmpFieldIAmMappedTo.stateFactory 151 ); 152 this.cmpFieldIAmMappedTo = cmpFieldIAmMappedTo; 153 if(myCMRField != null) 154 { 155 cmrChainLink = new CMRChainLink(myCMRField); 156 cmpFieldIAmMappedTo.addCMRChainLink(cmrChainLink); 157 } 158 this.columnName = columnName; 159 } 160 161 163 public JDBCCMP2xFieldBridge getCmpFieldIAmMappedTo() 164 { 165 return cmpFieldIAmMappedTo; 166 } 167 168 public ChainLink getCmrChainLink() 169 { 170 return cmrChainLink; 171 } 172 173 public boolean isFKFieldMappedToCMPField() 174 { 175 return cmpFieldIAmMappedTo != null && this.cmrChainLink != null; 176 } 177 178 public String getColumnName() 179 { 180 return columnName; 181 } 182 183 185 public Object getInstanceValue(EntityEnterpriseContext ctx) 186 { 187 FieldState fieldState = getLoadedState(ctx); 188 return fieldState.getValue(); 189 } 190 191 public void setInstanceValue(EntityEnterpriseContext ctx, Object value) 192 { 193 FieldState fieldState = getFieldState(ctx); 194 195 if(cmpFieldIAmMappedTo != null && cmpFieldIAmMappedTo.isPrimaryKeyMember()) 197 { 198 if(value != null) 201 { 202 if(fieldState.isLoaded() && fieldState.isValueChanged(value)) 203 { 204 throw new IllegalStateException ( 205 "New value [" + value + "] of a foreign key field " 206 + getFieldName() 207 + " changed the value of a primary key field " 208 + cmpFieldIAmMappedTo.getFieldName() 209 + "[" + fieldState.value + "]" 210 ); 211 } 212 else 213 { 214 fieldState.setValue(value); 215 } 216 } 217 } 218 else 219 { 220 if(cmrChainLink != null 221 && JDBCEntityBridge.isEjbCreateDone(ctx) 222 && fieldState.isLoaded() 223 && fieldState.isValueChanged(value)) 224 { 225 cmrChainLink.execute(ctx, fieldState, value); 226 } 227 228 fieldState.setValue(value); 229 } 230 231 fieldState.setLoaded(); 233 } 234 235 public void lockInstanceValue(EntityEnterpriseContext ctx) 236 { 237 getFieldState(ctx).lockValue(); 238 } 239 240 public boolean isLoaded(EntityEnterpriseContext ctx) 241 { 242 return getFieldState(ctx).isLoaded(); 243 } 244 245 248 public boolean isDirty(EntityEnterpriseContext ctx) 249 { 250 return !primaryKeyMember 251 && !readOnly 252 && getFieldState(ctx).isDirty(); 253 } 254 255 259 public void setClean(EntityEnterpriseContext ctx) 260 { 261 FieldState fieldState = getFieldState(ctx); 262 fieldState.setClean(); 263 264 if(readOnly && readTimeOut != -1) 266 fieldState.lastRead = System.currentTimeMillis(); 267 } 268 269 public void resetPersistenceContext(EntityEnterpriseContext ctx) 270 { 271 if(isReadTimedOut(ctx)) 272 { 273 JDBCContext jdbcCtx = (JDBCContext)ctx.getPersistenceContext(); 274 FieldState fieldState = (FieldState)jdbcCtx.getFieldState(jdbcContextIndex); 275 if(fieldState != null) 276 fieldState.reset(); 277 } 278 } 279 280 public boolean isReadTimedOut(EntityEnterpriseContext ctx) 281 { 282 if(!readOnly) 284 return true; 285 286 if(readTimeOut == -1) 288 return false; 289 290 long readInterval = System.currentTimeMillis() - getFieldState(ctx).lastRead; 291 return readInterval >= readTimeOut; 292 } 293 294 public Object getLockedValue(EntityEnterpriseContext ctx) 295 { 296 return getLoadedState(ctx).getLockedValue(); 297 } 298 299 public void updateState(EntityEnterpriseContext ctx, Object value) 300 { 301 getFieldState(ctx).updateState(value); 302 } 303 304 protected void setDirtyAfterGet(EntityEnterpriseContext ctx) 305 { 306 getFieldState(ctx).setCheckDirty(); 307 } 308 309 311 private FieldState getLoadedState(EntityEnterpriseContext ctx) 312 { 313 FieldState fieldState = getFieldState(ctx); 314 if(!fieldState.isLoaded()) 315 { 316 manager.loadField(this, ctx); 317 if(!fieldState.isLoaded()) 318 throw new EJBException ("Could not load field value: " + getFieldName()); 319 } 320 return fieldState; 321 } 322 323 private void addCMRChainLink(ChainLink nextCMRChainLink) 324 { 325 if(cmrChainLink == null) 326 { 327 cmrChainLink = new DummyChainLink(); 328 } 329 cmrChainLink.setNextLink(nextCMRChainLink); 330 } 331 332 private FieldState getFieldState(EntityEnterpriseContext ctx) 333 { 334 JDBCContext jdbcCtx = (JDBCContext)ctx.getPersistenceContext(); 335 FieldState fieldState = (FieldState)jdbcCtx.getFieldState(jdbcContextIndex); 336 if(fieldState == null) 337 { 338 fieldState = new FieldState(jdbcCtx); 339 jdbcCtx.setFieldState(jdbcContextIndex, fieldState); 340 } 341 return fieldState; 342 } 343 344 346 private class FieldState 347 { 348 349 private JDBCEntityBridge.EntityState entityState; 350 351 private Object value; 352 353 private Object state; 354 355 private Object lockedValue; 356 357 private long lastRead = -1; 358 359 public FieldState(JDBCContext jdbcCtx) 360 { 361 this.entityState = jdbcCtx.getEntityState(); 362 } 363 364 368 public Object getValue() 369 { 370 return value; 373 } 374 375 379 public void setValue(Object newValue) 380 { 381 this.value = newValue; 382 setCheckDirty(); 383 } 384 385 private void setCheckDirty() 386 { 387 entityState.setCheckDirty(tableIndex); 388 } 389 390 393 public boolean isLoaded() 394 { 395 return entityState.isLoaded(tableIndex); 396 } 397 398 401 public void setLoaded() 402 { 403 entityState.setLoaded(tableIndex); 404 } 405 406 409 public boolean isDirty() 410 { 411 return isLoaded() && !stateFactory.isStateValid(state, value); 412 } 413 414 420 public boolean isValueChanged(Object newValue) 421 { 422 return value == null ? newValue != null : !value.equals(newValue); 423 } 424 425 428 public void setClean() 429 { 430 entityState.setClean(tableIndex); 431 updateState(value); 432 } 433 434 441 private void updateState(Object value) 442 { 443 state = stateFactory.getFieldState(value); 444 lockedValue = value; 445 } 446 447 450 public void reset() 451 { 452 value = null; 453 state = null; 454 lastRead = -1; 455 entityState.resetFlags(tableIndex); 456 } 457 458 public void lockValue() 459 { 460 if(entityState.lockValue(tableIndex)) 461 { 462 lockedValue = value; 464 } 465 } 466 467 public Object getLockedValue() 468 { 469 return lockedValue; 470 } 471 } 472 473 477 private abstract static class ChainLink 478 { 479 private ChainLink nextLink; 480 481 public ChainLink() 482 { 483 nextLink = this; 484 } 485 486 public void setNextLink(ChainLink nextLink) 487 { 488 nextLink.nextLink = this.nextLink; 489 this.nextLink = nextLink; 490 } 491 492 public ChainLink getNextLink() 493 { 494 return nextLink; 495 } 496 497 public void execute(EntityEnterpriseContext ctx, 498 FieldState fieldState, 499 Object newValue) 500 { 501 nextLink.doExecute(this, ctx, fieldState, newValue); 502 } 503 504 protected abstract void doExecute(ChainLink originator, 505 EntityEnterpriseContext ctx, 506 FieldState fieldState, 507 Object newValue); 508 } 509 510 513 private static class CMRChainLink 514 extends ChainLink 515 { 516 private final JDBCCMRFieldBridge cmrField; 517 518 public CMRChainLink(JDBCCMRFieldBridge cmrField) 519 { 520 this.cmrField = cmrField; 521 } 522 523 536 public void doExecute(ChainLink originator, 537 EntityEnterpriseContext ctx, 538 FieldState fieldState, 539 Object newValue) 540 { 541 Object oldRelatedId = cmrField.getRelatedIdFromContext(ctx); 543 544 if(originator != getNextLink()) 546 { 547 getNextLink().doExecute(originator, ctx, fieldState, newValue); 548 } 549 550 fieldState.setValue(newValue); 552 553 Object newRelatedId = cmrField.getRelatedIdFromContext(ctx); 555 556 if(oldRelatedId != null) 558 destroyRelations(oldRelatedId, ctx); 559 560 if(newRelatedId != null) 562 createRelations(newRelatedId, ctx); 563 } 564 565 private void createRelations(Object newRelatedId, EntityEnterpriseContext ctx) 566 { 567 try 568 { 569 if(cmrField.isForeignKeyValid(newRelatedId)) 570 { 571 cmrField.createRelationLinks(ctx, newRelatedId, false); 572 } 573 else 574 { 575 cmrField.setForeignKey(ctx, newRelatedId); 577 if(ctx.getId() != null) 579 { 580 JDBCCMRFieldBridge relatedCMRField = (JDBCCMRFieldBridge)cmrField.getRelatedCMRField(); 581 relatedCMRField.addRelatedPKWaitingForMyPK(newRelatedId, ctx.getId()); 582 } 583 } 584 } 585 catch(Exception e) 586 { 587 } 589 } 590 591 private void destroyRelations(Object oldRelatedId, EntityEnterpriseContext ctx) 592 { 593 JDBCCMRFieldBridge relatedCMRField = (JDBCCMRFieldBridge)cmrField.getRelatedCMRField(); 594 relatedCMRField.removeRelatedPKWaitingForMyPK(oldRelatedId, ctx.getId()); 595 try 596 { 597 if(cmrField.isForeignKeyValid(oldRelatedId)) 598 { 599 cmrField.destroyRelationLinks(ctx, oldRelatedId, true, false); 600 } 601 } 602 catch(Exception e) 603 { 604 } 606 } 607 } 608 609 private static class DummyChainLink 610 extends ChainLink 611 { 612 public void doExecute(ChainLink originator, 613 EntityEnterpriseContext ctx, 614 FieldState fieldState, 615 Object newValue) 616 { 617 if(originator != getNextLink()) 619 { 620 getNextLink().doExecute(originator, ctx, fieldState, newValue); 621 } 622 fieldState.setValue(newValue); 624 } 625 } 626 } 627 | Popular Tags |