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.Iterator ; 26 import java.util.LinkedList ; 27 import java.util.List ; 28 import java.util.Map ; 29 30 import org.apache.commons.collections.Transformer; 31 import org.apache.cayenne.CayenneRuntimeException; 32 import org.apache.cayenne.ObjectId; 33 import org.apache.cayenne.exp.Expression; 34 import org.apache.cayenne.exp.ExpressionException; 35 import org.apache.cayenne.exp.ExpressionFactory; 36 import org.apache.cayenne.map.event.AttributeEvent; 37 import org.apache.cayenne.map.event.DbAttributeListener; 38 import org.apache.cayenne.map.event.DbEntityListener; 39 import org.apache.cayenne.map.event.DbRelationshipListener; 40 import org.apache.cayenne.map.event.EntityEvent; 41 import org.apache.cayenne.map.event.MapEvent; 42 import org.apache.cayenne.map.event.RelationshipEvent; 43 import org.apache.cayenne.util.CayenneMapEntry; 44 import org.apache.cayenne.util.Util; 45 import org.apache.cayenne.util.XMLEncoder; 46 47 53 public class DbEntity extends Entity implements DbEntityListener, DbAttributeListener, 54 DbRelationshipListener { 55 56 protected String catalog; 57 protected String schema; 58 protected List primaryKey; 59 60 63 protected Collection generatedAttributes; 64 protected DbKeyGenerator primaryKeyGenerator; 65 66 69 public DbEntity() { 70 super(); 71 72 this.primaryKey = new ArrayList (2); 73 this.generatedAttributes = new ArrayList (2); 74 } 75 76 79 public DbEntity(String name) { 80 this(); 81 this.setName(name); 82 } 83 84 89 public void encodeAsXML(XMLEncoder encoder) { 90 encoder.print("<db-entity name=\""); 91 encoder.print(Util.encodeXmlAttribute(getName())); 92 encoder.print('\"'); 93 94 if (getSchema() != null && getSchema().trim().length() > 0) { 95 encoder.print(" schema=\""); 96 encoder.print(Util.encodeXmlAttribute(getSchema().trim())); 97 encoder.print('\"'); 98 } 99 100 if (getCatalog() != null && getCatalog().trim().length() > 0) { 101 encoder.print(" catalog=\""); 102 encoder.print(Util.encodeXmlAttribute(getCatalog().trim())); 103 encoder.print('\"'); 104 } 105 106 encoder.println('>'); 107 108 encoder.indent(1); 109 encoder.print(getAttributeMap()); 110 111 if (getPrimaryKeyGenerator() != null) { 112 getPrimaryKeyGenerator().encodeAsXML(encoder); 113 } 114 115 encoder.indent(-1); 116 encoder.println("</db-entity>"); 117 } 118 119 122 public String getFullyQualifiedName() { 123 return (schema != null) ? schema + '.' + getName() : getName(); 124 } 125 126 131 public String getSchema() { 132 return schema; 133 } 134 135 138 public void setSchema(String schema) { 139 this.schema = schema; 140 } 141 142 145 public String getCatalog() { 146 return catalog; 147 } 148 149 152 public void setCatalog(String catalog) { 153 this.catalog = catalog; 154 } 155 156 160 public List getPrimaryKey() { 163 return Collections.unmodifiableList(primaryKey); 164 } 165 166 172 public Collection getGeneratedAttributes() { 173 return Collections.unmodifiableCollection(generatedAttributes); 174 } 175 176 179 public void addAttribute(Attribute attr) { 180 super.addAttribute(attr); 181 this.dbAttributeAdded(new AttributeEvent(this, attr, this, MapEvent.ADD)); 182 } 183 184 190 public void removeAttribute(String attrName) { 191 Attribute attr = getAttribute(attrName); 192 if (attr == null) { 193 return; 194 } 195 196 DataMap map = getDataMap(); 197 if (map != null) { 198 Iterator ents = map.getDbEntities().iterator(); 199 while (ents.hasNext()) { 200 DbEntity ent = (DbEntity) ents.next(); 201 Iterator it = ent.getRelationships().iterator(); 202 while (it.hasNext()) { 203 DbRelationship rel = (DbRelationship) it.next(); 204 Iterator joins = rel.getJoins().iterator(); 205 while (joins.hasNext()) { 206 DbJoin join = (DbJoin) joins.next(); 207 if (join.getSource() == attr || join.getTarget() == attr) { 208 joins.remove(); 209 } 210 } 211 } 212 } 213 } 214 215 super.removeAttribute(attrName); 216 this.dbAttributeRemoved(new AttributeEvent(this, attr, this, MapEvent.REMOVE)); 217 } 218 219 public void clearAttributes() { 220 super.clearAttributes(); 221 this.dbAttributeRemoved(new AttributeEvent(this, null, this, MapEvent.REMOVE)); 223 } 224 225 public Iterator resolvePathComponents(Expression pathExp) throws ExpressionException { 226 if (pathExp.getType() != Expression.DB_PATH) { 227 throw new ExpressionException("Invalid expression type: '" 228 + pathExp.expName() 229 + "', DB_PATH is expected."); 230 } 231 232 return new PathIterator((String ) pathExp.getOperand(0)); 233 } 234 235 public void setPrimaryKeyGenerator(DbKeyGenerator primaryKeyGenerator) { 236 this.primaryKeyGenerator = primaryKeyGenerator; 237 if (primaryKeyGenerator != null) { 238 primaryKeyGenerator.setDbEntity(this); 239 } 240 } 241 242 public DbKeyGenerator getPrimaryKeyGenerator() { 243 return primaryKeyGenerator; 244 } 245 246 253 public void dbEntityChanged(EntityEvent e) { 254 if ((e == null) || (e.getEntity() != this)) { 255 return; 257 } 258 259 if (e.getId() == EntityEvent.CHANGE && e.isNameChange()) { 261 String newName = e.getNewName(); 262 DataMap map = getDataMap(); 263 if (map != null) { 264 Iterator ents = map.getDbEntities().iterator(); 266 while (ents.hasNext()) { 267 DbEntity dbe = (DbEntity) ents.next(); 268 Iterator rit = dbe.getRelationships().iterator(); 269 while (rit.hasNext()) { 270 DbRelationship rel = (DbRelationship) rit.next(); 271 if (rel.getTargetEntity() == this) { 272 rel.setTargetEntityName(newName); 273 } 274 } 275 } 276 ents = map.getMappedEntities(this).iterator(); 278 while (ents.hasNext()) { 279 ObjEntity oe = (ObjEntity) ents.next(); 280 if (oe.getDbEntity() == this) { 281 oe.setDbEntityName(newName); 282 } 283 } 284 } 285 } 286 } 287 288 289 public void dbEntityAdded(EntityEvent e) { 290 } 292 293 294 public void dbEntityRemoved(EntityEvent e) { 295 } 297 298 public void dbAttributeAdded(AttributeEvent e) { 299 this.handleAttributeUpdate(e); 300 } 301 302 public void dbAttributeChanged(AttributeEvent e) { 303 this.handleAttributeUpdate(e); 304 } 305 306 public void dbAttributeRemoved(AttributeEvent e) { 307 this.handleAttributeUpdate(e); 308 } 309 310 private void handleAttributeUpdate(AttributeEvent e) { 311 if ((e == null) || (e.getEntity() != this)) { 312 return; 314 } 315 316 Attribute attr = e.getAttribute(); 318 if ((attr == null) && (this.attributes.isEmpty())) { 319 this.primaryKey.clear(); 320 this.generatedAttributes.clear(); 321 return; 322 } 323 324 if (!(attr instanceof DbAttribute)) { 326 return; 327 } 328 329 DbAttribute dbAttr = (DbAttribute) attr; 330 331 if (e.getId() == AttributeEvent.CHANGE && e.isNameChange()) { 333 String oldName = e.getOldName(); 334 String newName = e.getNewName(); 335 336 DataMap map = getDataMap(); 337 if (map != null) { 338 Iterator ents = map.getDbEntities().iterator(); 339 while (ents.hasNext()) { 340 DbEntity ent = (DbEntity) ents.next(); 341 342 Iterator it = map.getMappedEntities(ent).iterator(); 344 while (it.hasNext()) { 345 ObjEntity oe = (ObjEntity) it.next(); 346 Iterator ait = oe.getAttributes().iterator(); 347 while (ait.hasNext()) { 348 ObjAttribute oa = (ObjAttribute) ait.next(); 349 if (oa.getDbAttribute() == dbAttr) { 350 oa.setDbAttributeName(newName); 351 } 352 } 353 } 354 355 it = ent.getRelationships().iterator(); 358 while (it.hasNext()) { 359 DbRelationship rel = (DbRelationship) it.next(); 360 Iterator joins = rel.getJoins().iterator(); 361 while (joins.hasNext()) { 362 DbJoin join = (DbJoin) joins.next(); 363 if (join.getSource() == dbAttr) { 364 join.setSourceName(newName); 365 } 366 if (join.getTarget() == dbAttr) { 367 join.setTargetName(newName); 368 } 369 } 370 } 371 } 372 } 373 374 attributes.remove(oldName); 376 377 super.addAttribute(dbAttr); 379 } 380 381 if (primaryKey.contains(dbAttr) || dbAttr.isPrimaryKey()) { 383 switch (e.getId()) { 384 case MapEvent.ADD: 385 this.primaryKey.add(attr); 386 break; 387 388 case MapEvent.REMOVE: 389 this.primaryKey.remove(attr); 390 break; 391 392 default: 393 this.primaryKey.clear(); 395 Iterator it = this.getAttributes().iterator(); 396 while (it.hasNext()) { 397 DbAttribute dba = (DbAttribute) it.next(); 398 if (dba.isPrimaryKey()) { 399 this.primaryKey.add(dba); 400 } 401 } 402 } 403 } 404 405 if (generatedAttributes.contains(dbAttr) || dbAttr.isGenerated()) { 407 switch (e.getId()) { 408 case MapEvent.ADD: 409 this.generatedAttributes.add(attr); 410 break; 411 412 case MapEvent.REMOVE: 413 this.generatedAttributes.remove(attr); 414 break; 415 416 default: 417 this.generatedAttributes.clear(); 419 Iterator it = this.getAttributes().iterator(); 420 while (it.hasNext()) { 421 DbAttribute dba = (DbAttribute) it.next(); 422 if (dba.isGenerated()) { 423 this.generatedAttributes.add(dba); 424 } 425 } 426 } 427 } 428 } 429 430 433 public void dbRelationshipChanged(RelationshipEvent e) { 434 if ((e == null) || (e.getEntity() != this)) { 435 return; 437 } 438 439 Relationship rel = e.getRelationship(); 440 if (!(rel instanceof DbRelationship)) { 442 return; 443 } 444 445 DbRelationship dbRel = (DbRelationship) rel; 446 447 if (e.getId() == RelationshipEvent.CHANGE && e.isNameChange()) { 449 String oldName = e.getOldName(); 450 String newName = e.getNewName(); 451 452 DataMap map = getDataMap(); 453 if (map != null) { 454 Iterator ents = map.getObjEntities().iterator(); 457 while (ents.hasNext()) { 458 ObjEntity oe = (ObjEntity) ents.next(); 459 Iterator rit = oe.getRelationships().iterator(); 460 while (rit.hasNext()) { 461 ObjRelationship or = (ObjRelationship) rit.next(); 462 if (Util.nullSafeEquals(or.getDbRelationshipPath(), oldName)) { 464 or.setDbRelationshipPath(newName); 465 } 466 } 467 } 468 } 469 470 relationships.remove(oldName); 472 473 super.addRelationship(dbRel); 475 } 476 } 477 478 479 public void dbRelationshipAdded(RelationshipEvent e) { 480 } 482 483 484 public void dbRelationshipRemoved(RelationshipEvent e) { 485 } 487 488 494 public boolean isFullReplacementIdAttached(ObjectId id) { 495 if (!id.isReplacementIdAttached()) { 496 return false; 497 } 498 499 Map replacement = id.getReplacementIdMap(); 500 Collection pk = getPrimaryKey(); 501 if (pk.size() != replacement.size()) { 502 return false; 503 } 504 505 Iterator it = pk.iterator(); 506 while (it.hasNext()) { 507 DbAttribute attribute = (DbAttribute) it.next(); 508 if (!replacement.containsKey(attribute.getName())) { 509 return false; 510 } 511 } 512 513 return true; 514 } 515 516 522 public Expression translateToRelatedEntity( 523 Expression expression, 524 String relationshipPath) { 525 526 if (expression == null) { 527 return null; 528 } 529 530 if (relationshipPath == null) { 531 return expression; 532 } 533 534 return expression.transform(new RelationshipPathConverter(relationshipPath)); 535 } 536 537 final class RelationshipPathConverter implements Transformer { 538 539 String relationshipPath; 540 541 RelationshipPathConverter(String relationshipPath) { 542 this.relationshipPath = relationshipPath; 543 } 544 545 public Object transform(Object input) { 546 if (!(input instanceof Expression)) { 547 return input; 548 } 549 550 Expression expression = (Expression) input; 551 552 if (expression.getType() != Expression.DB_PATH) { 553 return input; 554 } 555 556 String path = (String ) expression.getOperand(0); 557 String converted = translatePath(path); 558 Expression transformed = ExpressionFactory 559 .expressionOfType(Expression.DB_PATH); 560 transformed.setOperand(0, converted); 561 return transformed; 562 } 563 564 String translatePath(String path) { 565 566 577 if (path.equals(relationshipPath)) { 579 580 LinkedList finalPath = new LinkedList (); 581 Iterator it = resolvePathComponents(path); 582 583 DbRelationship lastDBR = null; 586 587 while (it.hasNext()) { 588 lastDBR = (DbRelationship) it.next(); 590 } 591 592 if (lastDBR != null) { 593 prependReversedPath(finalPath, lastDBR); 594 appendPath(finalPath, lastDBR); 595 } 596 597 return convertToPath(finalPath); 598 } 599 600 String relationshipPathWithDot = relationshipPath + Entity.PATH_SEPARATOR; 602 if (path.startsWith(relationshipPathWithDot)) { 603 return path.substring(relationshipPathWithDot.length()); 604 } 605 606 Iterator pathIt = resolvePathComponents(path); 608 Iterator relationshipIt = resolvePathComponents(relationshipPath); 609 610 LinkedList finalPath = new LinkedList (); 612 613 while (relationshipIt.hasNext() && pathIt.hasNext()) { 614 DbRelationship nextDBR = (DbRelationship) relationshipIt.next(); 616 617 CayenneMapEntry next = (CayenneMapEntry) pathIt.next(); 619 620 if (nextDBR != next) { 621 prependReversedPath(finalPath, nextDBR); 625 appendPath(finalPath, next); 626 break; 627 } 628 629 break; 630 } 631 632 while (relationshipIt.hasNext()) { 634 DbRelationship nextDBR = (DbRelationship) relationshipIt.next(); 635 prependReversedPath(finalPath, nextDBR); 636 } 637 638 while (pathIt.hasNext()) { 639 CayenneMapEntry next = (CayenneMapEntry) pathIt.next(); 641 appendPath(finalPath, next); 642 } 643 644 return convertToPath(finalPath); 645 } 646 647 private String convertToPath(List path) { 648 StringBuffer converted = new StringBuffer (); 649 int len = path.size(); 650 for (int i = 0; i < len; i++) { 651 if (i > 0) { 652 converted.append(Entity.PATH_SEPARATOR); 653 } 654 655 converted.append(path.get(i)); 656 } 657 658 return converted.toString(); 659 } 660 661 private void prependReversedPath(LinkedList finalPath, DbRelationship relationship) { 662 DbRelationship revNextDBR = relationship.getReverseRelationship(); 663 664 if (revNextDBR == null) { 665 throw new CayenneRuntimeException( 666 "Unable to find reverse DbRelationship for " 667 + relationship.getSourceEntity().getName() 668 + Entity.PATH_SEPARATOR 669 + relationship.getName() 670 + "."); 671 } 672 673 finalPath.addFirst(revNextDBR.getName()); 674 } 675 676 private void appendPath(LinkedList finalPath, CayenneMapEntry pathComponent) { 677 finalPath.addLast(pathComponent.getName()); 678 } 679 } 680 } 681 | Popular Tags |