1 package org.apache.ojb.odmg; 2 3 17 18 import java.util.ArrayList ; 19 import java.util.Collection ; 20 import java.util.Collections ; 21 import java.util.HashMap ; 22 import java.util.Iterator ; 23 import java.util.List ; 24 import java.util.Map ; 25 26 import org.apache.commons.lang.ClassUtils; 27 import org.apache.ojb.broker.Identity; 28 import org.apache.ojb.broker.IdentityFactory; 29 import org.apache.ojb.broker.OJBRuntimeException; 30 import org.apache.ojb.broker.PersistenceBrokerInternal; 31 import org.apache.ojb.broker.core.proxy.CollectionProxy; 32 import org.apache.ojb.broker.core.proxy.CollectionProxyDefaultImpl; 33 import org.apache.ojb.broker.core.proxy.CollectionProxyListener; 34 import org.apache.ojb.broker.core.proxy.ProxyHelper; 35 import org.apache.ojb.broker.metadata.CollectionDescriptor; 36 import org.apache.ojb.broker.metadata.FieldType; 37 import org.apache.ojb.broker.metadata.ObjectReferenceDescriptor; 38 import org.apache.ojb.broker.util.BrokerHelper; 39 import org.apache.ojb.broker.util.logging.Logger; 40 import org.apache.ojb.broker.util.logging.LoggerFactory; 41 42 48 public abstract class Image 49 { 50 static Logger log = LoggerFactory.getLogger(Image.class); 51 private long timestamp = System.currentTimeMillis(); 52 53 private Image() 54 { 55 } 56 57 boolean illegalImageComparison(Image oldImage) 58 { 59 return timestamp < oldImage.timestamp; 60 } 61 62 public abstract void cleanup(boolean reuse); 63 64 public abstract boolean modified(Image other); 65 66 abstract void referenceProcessing(Image oldImage); 67 68 public void performReferenceDetection(Image oldImage) 69 { 70 if(illegalImageComparison(oldImage)) 71 { 72 throw new ImageException("The specified Image object is newer than current one, wrong Image order!"); 73 } 74 referenceProcessing(oldImage); 75 } 76 77 public static class MultipleRef extends Image implements CollectionProxyListener 81 { 82 static final int IS_NORMAL_OBJECT = 11; 83 static final int IS_MATERIALIZED_PROXY = 13; 84 static final int IS_UNMATERIALIZED_PROXY = 17; 85 86 private ImageListener listener; 87 private final CollectionDescriptor cod; 88 private final Object collectionOrArray; 89 private Map references; 90 private int status; 91 private boolean hasTransientIdentity; 92 private boolean isRefreshed; 93 94 public MultipleRef(ImageListener listener, CollectionDescriptor cod, Object collectionOrArray) 95 { 96 this.listener = listener; 97 this.cod = cod; 98 this.collectionOrArray = collectionOrArray; 99 this.isRefreshed = true; 100 this.hasTransientIdentity = false; 101 this.references = Collections.EMPTY_MAP; 102 init(); 103 } 104 105 private void init() 106 { 107 CollectionProxy colProxy = ProxyHelper.getCollectionProxy(collectionOrArray); 108 if(colProxy != null) 109 { 110 if(colProxy.isLoaded()) 111 { 112 status = IS_MATERIALIZED_PROXY; 113 118 handleReferencedObjects(((Collection ) colProxy).iterator()); 119 } 120 else 121 { 122 status = IS_UNMATERIALIZED_PROXY; 123 if(log.isDebugEnabled()) log.debug("Unmaterialized proxy collection, use proxy listener"); 124 colProxy.addListener(this); 125 } 126 } 127 else 128 { 129 status = IS_NORMAL_OBJECT; 130 if(collectionOrArray != null) 131 { 132 Iterator it = BrokerHelper.getCollectionIterator(collectionOrArray); 133 handleReferencedObjects(it); 134 } 135 } 136 } 137 138 void handleReferencedObjects(Iterator it) 139 { 140 if(it == null) return; 141 references = new HashMap (); 142 if(log.isDebugEnabled()) log.debug("Handle collection references"); 143 IdentityFactory idFac = listener.getBroker().serviceIdentity(); 144 Identity oid; 145 Object obj; 146 while(it.hasNext()) 147 { 148 obj = it.next(); 149 oid = idFac.buildIdentity(obj); 150 if(!hasTransientIdentity && oid.isTransient()) 151 { 152 hasTransientIdentity = true; 153 } 154 references.put(oid, obj); 155 } 156 } 157 158 public void cleanup(boolean reuse) 159 { 160 if(log.isDebugEnabled()) log.debug("Cleanup collection image, reuse=" + reuse); 161 if(reuse) 162 { 163 isRefreshed = false; 164 } 165 else 166 { 167 if(status == IS_UNMATERIALIZED_PROXY) 168 { 169 CollectionProxy colProxy = ProxyHelper.getCollectionProxy(collectionOrArray); 170 if(colProxy != null) 171 { 172 colProxy.removeListener(this); 173 } 174 } 175 } 176 } 177 178 void referenceProcessing(Image oldImage) 179 { 180 MultipleRef oldRefs = (MultipleRef) oldImage; 181 if(incommensurableProxies(oldRefs)) 182 { 183 if(isUnmaterializedProxy()) handleReferencedObjects(BrokerHelper.getCollectionIterator(collectionOrArray)); 184 if(oldRefs.isUnmaterializedProxy()) oldRefs.handleReferencedObjects(BrokerHelper.getCollectionIterator(oldRefs.collectionOrArray)); 185 } 186 if(!isRefreshed) refreshIdentities(); 187 if(!oldRefs.isRefreshed) oldRefs.refreshIdentities(); 188 189 if(oldRefs.references.size() > 0) 191 { 192 Iterator oldIter = oldRefs.references.entrySet().iterator(); 193 while(oldIter.hasNext()) 194 { 195 Map.Entry entry = (Map.Entry ) oldIter.next(); 196 Identity oldOid = (Identity) entry.getKey(); 197 201 if(!isUnmaterializedProxy() && !containsReference(oldOid)) 202 { 203 listener.deletedXToN(cod, entry.getValue(), oldOid); 204 } 205 } 206 } 207 208 if(references.size() > 0) 210 { 211 Iterator newIter = references.entrySet().iterator(); 212 while(newIter.hasNext()) 213 { 214 Map.Entry entry = (Map.Entry ) newIter.next(); 215 Identity newOid = (Identity) entry.getKey(); 216 220 if(!oldRefs.containsReference(newOid)) 221 { 222 listener.addedXToN(cod, entry.getValue(), newOid); 223 } 224 } 225 } 226 } 227 228 235 private boolean incommensurableProxies(MultipleRef oldImage) 236 { 237 boolean result = false; 238 if(oldImage.isUnmaterializedProxy() || isUnmaterializedProxy()) 240 { 241 result = !collectionOrArray.equals(oldImage.collectionOrArray); 242 } 243 return result; 244 } 245 246 private void refreshIdentities() 247 { 248 if(hasTransientIdentity && references.size() > 0) 250 { 251 hasTransientIdentity = false; 252 List list = new ArrayList (references.keySet()); 254 IdentityFactory idFac = listener.getBroker().serviceIdentity(); 255 Identity oid, newOid; 256 Object obj; 257 for(int i = 0; i < list.size(); i++) 258 { 259 oid = (Identity) list.get(i); 260 if(oid.isTransient()) 261 { 262 obj = references.remove(oid); 263 newOid = idFac.buildIdentity(obj); 264 references.put(newOid, obj); 265 if(!hasTransientIdentity && oid.isTransient()) 266 { 267 hasTransientIdentity = true; 268 } 269 } 270 } 271 isRefreshed = true; 272 } 273 } 274 275 279 public boolean modified(Image other) 280 { 281 return false; 282 } 283 284 boolean containsReference(Identity oid) 285 { 286 if(!isRefreshed) refreshIdentities(); 287 return references.containsKey(oid); 288 } 289 290 Map getIdentityReferenceObjectMap() 291 { 292 if(!isRefreshed) refreshIdentities(); 293 return references; 294 } 295 296 boolean isMaterializedProxy() 297 { 298 return status == IS_MATERIALIZED_PROXY; 299 } 300 301 boolean isUnmaterializedProxy() 302 { 303 return status == IS_UNMATERIALIZED_PROXY; 304 } 305 306 307 public void beforeLoading(CollectionProxyDefaultImpl colProxy) 310 { 311 } 313 314 public void afterLoading(CollectionProxyDefaultImpl colProxy) 315 { 316 if(status == IS_UNMATERIALIZED_PROXY) 317 { 318 status = IS_MATERIALIZED_PROXY; 319 handleReferencedObjects(colProxy.iterator()); 320 colProxy.removeListener(this); 321 } 322 } 323 324 public String toString() 325 { 326 return ClassUtils.getShortClassName(this.getClass()) + "[references-size=" 327 + (references != null ? "" + references.size() : "undefined") + "]"; 328 } 329 } 330 331 public static class SingleRef extends Image 335 { 336 private Object referenceObjOrProxy; 337 private Identity oid = null; 338 private final ImageListener listener; 339 private final ObjectReferenceDescriptor ord; 340 341 public SingleRef(ImageListener listener, ObjectReferenceDescriptor ord, Object reference) 342 { 343 this.listener = listener; 344 this.ord = ord; 345 this.referenceObjOrProxy = reference; 346 } 347 348 public void cleanup(boolean reuse) 349 { 350 if(!reuse) 351 { 352 referenceObjOrProxy = null; 353 } 354 } 355 356 void referenceProcessing(Image oldImage) 357 { 358 SingleRef oldRef = (SingleRef) oldImage; 359 boolean isSame = getReferenceObjectOrProxy() == oldRef.getReferenceObjectOrProxy(); 360 if(!isSame) 361 { 362 Identity newOid = getIdentity(); 363 Identity oldOid = oldRef.getIdentity(); 364 if(newOid == null) 365 { 366 if(oldOid != null) 367 { 368 listener.deletedOneToOne(ord, oldRef.getReferenceObjectOrProxy(), oldOid, true); 369 } 370 } 371 else 372 { 373 if(oldOid == null) 374 { 375 listener.addedOneToOne(ord, getReferenceObjectOrProxy(), newOid); 376 } 377 else 378 { 379 if(!newOid.equals(oldOid)) 380 { 381 listener.deletedOneToOne(ord, oldRef.getReferenceObjectOrProxy(), oldOid, false); 382 listener.addedOneToOne(ord, getReferenceObjectOrProxy(), newOid); 383 } 384 } 385 } 386 } 387 } 388 389 public Object getReferenceObjectOrProxy() 390 { 391 return referenceObjOrProxy; 392 } 393 394 private Identity getIdentity() 395 { 396 if(oid == null || oid.isTransient()) 397 { 398 if(referenceObjOrProxy != null) 399 { 400 oid = listener.getBroker().serviceIdentity().buildIdentity(referenceObjOrProxy); 401 } 402 } 403 return oid; 404 } 405 406 410 public boolean modified(Image toCompare) 411 { 412 boolean modified = false; 413 if(!(this == toCompare)) 414 { 415 if(toCompare instanceof Image.SingleRef) 416 { 417 Image.SingleRef other = (Image.SingleRef) toCompare; 418 Identity current = getIdentity(); 419 Identity otherOid = other.getIdentity(); 420 modified = current != null ? !current.equals(otherOid) : !(otherOid == null); 421 } 422 } 423 return modified; 424 } 425 426 public String toString() 427 { 428 return ClassUtils.getShortClassName(this.getClass()) + "[reference=" + getIdentity() + "]"; 429 } 430 } 431 432 public static class Field extends Image 436 { 437 private final FieldType type; 438 private final Object value; 439 440 public Field(FieldType type, Object value) 441 { 442 this.type = type; 443 this.value = value; 444 } 445 446 public void cleanup(boolean reuse) 447 { 448 } 449 450 void referenceProcessing(Image oldImage) 451 { 452 } 454 455 456 public boolean modified(Image other) 457 { 458 boolean result = false; 459 if(this == other) 460 { 461 result = true; 462 } 463 else 464 { 465 if(other instanceof Field) 466 { 467 result = !type.equals(value, ((Field) other).value); 468 } 469 } 470 return result; 471 } 472 473 public String toString() 474 { 475 return ClassUtils.getShortClassName(this.getClass()) + "[type=" + type + ", value=" + value + "]"; 476 } 477 } 478 479 public static interface ImageListener 483 { 484 public void addedOneToOne(ObjectReferenceDescriptor ord, Object refObjOrProxy, Identity oid); 485 486 public void deletedOneToOne(ObjectReferenceDescriptor ord, Object refObjOrProxy, Identity oid, boolean needsUnlink); 487 488 public void addedXToN(CollectionDescriptor ord, Object refObjOrProxy, Identity oid); 489 490 public void deletedXToN(CollectionDescriptor ord, Object refObjOrProxy, Identity oid); 491 492 public PersistenceBrokerInternal getBroker(); 493 } 494 495 499 503 public static class ImageException extends OJBRuntimeException 504 { 505 public ImageException() 506 { 507 } 508 509 public ImageException(String msg) 510 { 511 super(msg); 512 } 513 514 public ImageException(Throwable cause) 515 { 516 super(cause); 517 } 518 519 public ImageException(String msg, Throwable cause) 520 { 521 super(msg, cause); 522 } 523 } 524 } 525 | Popular Tags |