1 19 20 package org.apache.cayenne.map; 21 22 import java.util.ArrayList ; 23 import java.util.Collection ; 24 import java.util.Collections ; 25 import java.util.HashMap ; 26 import java.util.Iterator ; 27 import java.util.List ; 28 import java.util.Map ; 29 30 import org.apache.commons.collections.CollectionUtils; 31 import org.apache.commons.collections.Transformer; 32 import org.apache.cayenne.CayenneRuntimeException; 33 import org.apache.cayenne.event.EventManager; 34 import org.apache.cayenne.event.EventSubject; 35 import org.apache.cayenne.map.event.RelationshipEvent; 36 import org.apache.cayenne.util.Util; 37 import org.apache.cayenne.util.XMLEncoder; 38 39 46 public class DbRelationship extends Relationship { 47 48 public static final EventSubject PROPERTY_DID_CHANGE = EventSubject.getSubject( 50 DbRelationship.class, 51 "PropertyDidChange"); 52 53 protected List joins = new ArrayList (); 55 56 protected boolean toDependentPK; 60 61 public DbRelationship() { 62 super(); 63 } 64 65 public DbRelationship(String name) { 66 super(name); 67 } 68 69 74 public void encodeAsXML(XMLEncoder encoder) { 75 encoder.print("<db-relationship name=\""); 76 encoder.print(Util.encodeXmlAttribute(getName())); 77 encoder.print("\" source=\""); 78 encoder.print(getSourceEntity().getName()); 79 80 if (getTargetEntityName() != null && getTargetEntity() != null) { 81 encoder.print("\" target=\""); 82 encoder.print(getTargetEntityName()); 83 } 84 85 if (isToDependentPK() && isValidForDepPk()) { 86 encoder.print("\" toDependentPK=\"true"); 87 } 88 89 encoder.print("\" toMany=\""); 90 encoder.print(isToMany()); 91 encoder.println("\">"); 92 93 encoder.indent(1); 94 encoder.print(getJoins()); 95 encoder.indent(-1); 96 97 encoder.println("</db-relationship>"); 98 } 99 100 104 public Entity getTargetEntity() { 105 String targetName = getTargetEntityName(); 106 if (targetName == null) { 107 return null; 108 } 109 110 return getNonNullNamespace().getDbEntity(targetName); 111 } 112 113 118 public Collection getTargetAttributes() { 119 if (joins.size() == 0) { 120 return Collections.EMPTY_LIST; 121 } 122 123 return CollectionUtils.collect(joins, JoinTransformers.targetExtractor); 124 } 125 126 131 public Collection getSourceAttributes() { 132 if (joins.size() == 0) { 133 return Collections.EMPTY_LIST; 134 } 135 136 return CollectionUtils.collect(joins, JoinTransformers.sourceExtractor); 137 } 138 139 145 public DbRelationship createReverseRelationship() { 146 DbRelationship reverse = new DbRelationship(); 147 reverse.setSourceEntity(getTargetEntity()); 148 reverse.setTargetEntityName(getSourceEntity().getName()); 149 150 153 reverse.setToMany(!toMany); 154 155 Iterator it = joins.iterator(); 156 while (it.hasNext()) { 157 DbJoin join = (DbJoin) it.next(); 158 DbJoin reverseJoin = join.createReverseJoin(); 159 reverseJoin.setRelationship(reverse); 160 reverse.addJoin(reverseJoin); 161 } 162 163 return reverse; 164 } 165 166 171 public DbRelationship getReverseRelationship() { 172 Entity target = this.getTargetEntity(); 173 174 if (target == null) { 175 return null; 176 } 177 178 Entity src = this.getSourceEntity(); 179 180 if (target == src && joins.size() == 0) { 182 return null; 183 } 184 185 TestJoin testJoin = new TestJoin(this); 186 Iterator it = target.getRelationships().iterator(); 187 while (it.hasNext()) { 188 DbRelationship rel = (DbRelationship) it.next(); 189 if (rel.getTargetEntity() != src) 190 continue; 191 192 List otherJoins = rel.getJoins(); 193 if (otherJoins.size() != joins.size()) { 194 continue; 195 } 196 197 Iterator jit = otherJoins.iterator(); 198 boolean joinsMatch = true; 199 while (jit.hasNext()) { 200 DbJoin join = (DbJoin) jit.next(); 201 202 testJoin.setSourceName(join.getTargetName()); 204 testJoin.setTargetName(join.getSourceName()); 205 if (!joins.contains(testJoin)) { 206 joinsMatch = false; 207 break; 208 } 209 } 210 211 if (joinsMatch) { 212 return rel; 213 } 214 } 215 216 return null; 217 } 218 219 225 public boolean isToPK() { 226 Iterator it = getJoins().iterator(); 227 while (it.hasNext()) { 228 DbJoin join = (DbJoin) it.next(); 229 if (join.getTarget() == null) { 230 return false; 231 } 232 233 if (join.getTarget().isPrimaryKey()) { 234 return true; 235 } 236 } 237 238 return false; 239 } 240 241 245 public boolean isToMasterPK() { 246 if (isToMany() || isToDependentPK()) { 247 return false; 248 } 249 250 DbRelationship revRel = getReverseRelationship(); 251 return (revRel != null) ? revRel.isToDependentPK() : false; 252 } 253 254 259 public boolean isToDependentPK() { 260 return toDependentPK; 261 } 262 263 public void setToDependentPK(boolean toDependentPK) { 264 if (this.toDependentPK != toDependentPK) { 265 this.toDependentPK = toDependentPK; 266 firePropertyDidChange(); 267 } 268 } 269 270 273 public boolean isValidForDepPk() { 274 Iterator it = getJoins().iterator(); 275 if (!it.hasNext()) { 277 return false; 278 } 279 280 while (it.hasNext()) { 281 DbJoin join = (DbJoin) it.next(); 282 DbAttribute target = join.getTarget(); 283 DbAttribute source = join.getSource(); 284 285 if ((target != null && !target.isPrimaryKey()) 286 || (source != null && !source.isPrimaryKey())) { 287 return false; 288 } 289 } 290 291 return true; 292 } 293 294 298 public List getJoins() { 299 return joins; 300 } 301 302 307 public void addJoin(DbJoin join) { 308 if (join != null) { 309 joins.add(join); 310 } 311 } 312 313 public void removeJoin(DbJoin join) { 314 joins.remove(join); 315 } 316 317 public void removeAllJoins() { 318 joins.clear(); 319 } 320 321 public void setJoins(Collection newJoins) { 322 this.removeAllJoins(); 323 324 if (newJoins != null) { 325 joins.addAll(newJoins); 326 } 327 } 328 329 336 public Map targetPkSnapshotWithSrcSnapshot(Map srcSnapshot) { 337 338 if (isToMany()) { 339 throw new CayenneRuntimeException( 340 "Only 'to one' relationships support this method."); 341 } 342 343 Map idMap; 344 345 int numJoins = joins.size(); 346 int foundNulls = 0; 347 348 if (numJoins == 1) { 350 DbJoin join = (DbJoin) joins.get(0); 351 Object val = srcSnapshot.get(join.getSourceName()); 352 if (val == null) { 353 foundNulls++; 354 idMap = Collections.EMPTY_MAP; 355 } 356 else { 357 idMap = Collections.singletonMap(join.getTargetName(), val); 358 } 359 } 360 else { 362 idMap = new HashMap (numJoins * 2); 363 for (int i = 0; i < numJoins; i++) { 364 DbJoin join = (DbJoin) joins.get(i); 365 DbAttribute source = join.getSource(); 366 Object val = srcSnapshot.get(join.getSourceName()); 367 368 if (val == null) { 369 370 if (!source.isMandatory()) { 373 return null; 374 } 375 376 foundNulls++; 377 } 378 else { 379 idMap.put(join.getTargetName(), val); 380 } 381 } 382 } 383 384 if (foundNulls == 0) { 385 return idMap; 386 } 387 else if (foundNulls == numJoins) { 388 return null; 389 } 390 else { 391 throw new CayenneRuntimeException("Some parts of FK are missing in snapshot," 392 + " relationship: " 393 + this); 394 } 395 } 396 397 401 private Map srcSnapshotWithTargetSnapshot(Map targetSnapshot) { 402 int len = joins.size(); 403 404 if (len == 1) { 406 DbJoin join = (DbJoin) joins.get(0); 407 Object val = targetSnapshot.get(join.getTargetName()); 408 return Collections.singletonMap(join.getSourceName(), val); 409 410 } 411 412 Map idMap = new HashMap (len * 2); 414 for (int i = 0; i < len; i++) { 415 DbJoin join = (DbJoin) joins.get(i); 416 Object val = targetSnapshot.get(join.getTargetName()); 417 idMap.put(join.getSourceName(), val); 418 } 419 420 return idMap; 421 } 422 423 428 public Map srcFkSnapshotWithTargetSnapshot(Map targetSnapshot) { 429 430 if (isToMany()) { 431 throw new CayenneRuntimeException( 432 "Only 'to one' relationships support this method."); 433 } 434 435 return srcSnapshotWithTargetSnapshot(targetSnapshot); 436 } 437 438 443 public Map srcPkSnapshotWithTargetSnapshot(Map targetSnapshot) { 444 if (!isToMany()) 445 throw new CayenneRuntimeException( 446 "Only 'to many' relationships support this method."); 447 return srcSnapshotWithTargetSnapshot(targetSnapshot); 448 } 449 450 453 public void setToMany(boolean toMany) { 454 if (this.toMany != toMany) { 455 this.toMany = toMany; 456 this.firePropertyDidChange(); 457 } 458 } 459 460 protected void firePropertyDidChange() { 461 RelationshipEvent event = new RelationshipEvent(this, this, this 462 .getSourceEntity()); 463 EventManager.getDefaultManager().postEvent(event, PROPERTY_DID_CHANGE); 464 } 465 466 final static class JoinTransformers { 467 468 static final Transformer targetExtractor = new Transformer() { 469 470 public Object transform(Object input) { 471 return (input instanceof DbJoin) ? ((DbJoin) input).getTarget() : input; 472 } 473 }; 474 475 static final Transformer sourceExtractor = new Transformer() { 476 477 public Object transform(Object input) { 478 return (input instanceof DbJoin) ? ((DbJoin) input).getSource() : input; 479 } 480 }; 481 } 482 483 final static class TestJoin extends DbJoin { 485 486 TestJoin(DbRelationship relationship) { 487 super(relationship); 488 } 489 490 public boolean equals(Object o) { 491 if (o == null) { 492 return false; 493 } 494 495 if (o == this) { 496 return true; 497 } 498 499 if (!(o instanceof DbJoin)) { 500 return false; 501 } 502 503 DbJoin j = (DbJoin) o; 504 return j.relationship == this.relationship 505 && Util.nullSafeEquals(j.sourceName, this.sourceName) 506 && Util.nullSafeEquals(j.targetName, this.targetName); 507 } 508 } 509 } 510 | Popular Tags |