1 10 package org.mmbase.module.corebuilders; 11 12 import java.util.*; 13 14 import org.mmbase.bridge.Field; 15 import org.mmbase.util.*; 16 import org.mmbase.module.core.*; 17 import org.mmbase.core.CoreField; 18 import org.mmbase.core.event.NodeEvent; 19 import org.mmbase.core.util.Fields; 20 import org.mmbase.storage.search.implementation.BasicRelationStep; 21 import org.mmbase.storage.search.RelationStep; 22 23 import org.mmbase.util.logging.Logger; 24 import org.mmbase.util.logging.Logging; 25 26 43 public class TypeRel extends MMObjectBuilder implements MMBaseObserver { 44 45 private static final Logger log = Logging.getLoggerInstance(TypeRel.class); 46 47 50 public static final int STRICT = 0; 51 52 56 public static final int INCLUDE_DESCENDANTS = 1; 57 58 62 public static final int INCLUDE_PARENTS = 2; 63 64 68 public static final int INCLUDE_PARENTS_AND_DESCENDANTS = 3; 69 70 74 protected TypeRelSet typeRelNodes; 76 protected TypeRelSet parentTypeRelNodes; 78 80 public InverseTypeRelSet inverseTypeRelNodes; 82 public boolean init() { 83 if (oType != -1) return true; 84 super.init(); 85 readCache(false); 91 return true; 92 } 93 94 99 public void readCache() { 100 readCache(true); 101 } 102 103 106 private void readCache(boolean buildersInitialized) { 107 log.debug("Reading in typerels"); 108 typeRelNodes = new TypeRelSet(); 109 parentTypeRelNodes = new TypeRelSet(); 110 inverseTypeRelNodes = new InverseTypeRelSet(); 111 112 TypeDef typeDef = mmb.getTypeDef(); 113 typeDef.init(); 114 List alltypes = getNodes(); 116 for (Iterator iter = alltypes.iterator(); iter.hasNext();) { 117 MMObjectNode typerel = (MMObjectNode) iter.next(); 119 addCacheEntry(typerel, buildersInitialized); 120 } 121 log.debug("Done reading typerel cache " + (buildersInitialized ? "(considered inheritance)" : "") + ": " + typeRelNodes); 122 } 123 124 130 protected TypeRelSet addCacheEntry(MMObjectNode typeRel, boolean buildersInitialized) { 131 132 TypeRelSet added = new TypeRelSet(); 134 added.add(typeRel); 137 138 RelDef reldef = mmb.getRelDef(); 139 140 MMObjectNode reldefNode = reldef.getNode(typeRel.getIntValue("rnumber")); 141 if (reldefNode == null) { throw new RuntimeException ("Could not find reldef-node for rnumber= " 142 + typeRel.getIntValue("rnumber")); } 143 144 boolean bidirectional = (!InsRel.usesdir) || (reldefNode.getIntValue("dir") > 1); 145 146 inheritance: if (buildersInitialized) { 150 TypeDef typeDef = mmb.getTypeDef(); 151 152 String sourceBuilderName = typeDef.getValue(typeRel.getIntValue("snumber")); 153 MMObjectBuilder sourceBuilder = sourceBuilderName != null ? mmb.getBuilder(sourceBuilderName) : null; 154 155 String destinationBuilderName = typeDef.getValue(typeRel.getIntValue("dnumber")); 156 MMObjectBuilder destinationBuilder = destinationBuilderName != null ? mmb.getBuilder(destinationBuilderName) : null; 157 158 if (sourceBuilder == null) { 159 if (destinationBuilder == null) { 160 log.warn("Both source and destination of " + typeRel 161 + " are not active builders. Cannot follow descendants."); 162 } else { 163 log.warn("The source of relation type " + typeRel 164 + " is not an active builder. Cannot follow descendants."); 165 } 166 break inheritance; 167 } 168 169 if (destinationBuilder == null) { 170 log.warn("The destination of relation type " + typeRel 171 + " is not an active builder. Cannot follow descendants."); 172 break inheritance; 173 } 174 175 int rnumber = typeRel.getIntValue("rnumber"); 176 177 List sources = sourceBuilder.getDescendants(); 178 sources.add(sourceBuilder); 179 180 List destinations = destinationBuilder.getDescendants(); 181 destinations.add(destinationBuilder); 182 183 Iterator i = sources.iterator(); 184 while (i.hasNext()) { 185 MMObjectBuilder s = (MMObjectBuilder) i.next(); 186 Iterator j = destinations.iterator(); 187 while (j.hasNext()) { 188 MMObjectBuilder d = (MMObjectBuilder) j.next(); 189 MMObjectNode vnode = new VirtualTypeRelNode(s.getNumber(), d.getNumber(), rnumber); 190 added.add(vnode); 191 } 192 } 193 194 MMObjectBuilder sourceParent = sourceBuilder; 198 while (sourceParent != null) { 199 MMObjectBuilder destinationParent = destinationBuilder; 200 while (destinationParent != null) { 201 MMObjectNode vnode = new VirtualTypeRelNode(sourceParent.getNumber(), destinationParent.getNumber(), rnumber); 202 parentTypeRelNodes.add(vnode); 203 destinationParent = destinationParent.getParentBuilder(); 204 } 205 sourceParent = sourceParent.getParentBuilder(); 206 } 207 added.add(typeRel); } 210 Iterator i = added.iterator(); 211 while (i.hasNext()) { 212 MMObjectNode node = (MMObjectNode) i.next(); 213 if (! node.isVirtual()) { 214 typeRelNodes.remove(node); 217 if (bidirectional) inverseTypeRelNodes.remove(node); 218 } 219 typeRelNodes.add(node); 220 if (bidirectional) inverseTypeRelNodes.add(node); 221 } 222 if (log.isDebugEnabled()) { 223 log.debug("Added to typerelcache: " + added); 224 } 225 return added; 226 } 227 228 238 public int insert(String owner, MMObjectNode node) { 239 int snumber = node.getIntValue("snumber"); 240 int dnumber = node.getIntValue("dnumber"); 241 int rnumber = node.getIntValue("rnumber"); 242 if (contains(snumber, dnumber, rnumber, STRICT)) { 243 log.error("The typerel with snumber=" + snumber + ", dnumber=" + dnumber + ", rnumber=" + rnumber + " already exists"); 244 throw new RuntimeException ("The typerel with snumber=" + snumber + ", dnumber=" + dnumber + ", rnumber=" 245 + rnumber + " already exists"); 246 } 247 int res = super.insert(owner, node); 248 return res; 249 } 250 251 255 public void removeNode(MMObjectNode node) { 256 super.removeNode(node); 257 } 258 259 267 public Enumeration getAllowedRelations(MMObjectNode node) { 268 return getAllowedRelations(node.getBuilder().getNumber()); 269 } 270 271 public Enumeration getAllowedRelations(int otype) { 272 Set res = getAllowedRelations(otype, 0, 0, RelationStep.DIRECTIONS_BOTH); 273 return Collections.enumeration(res); 274 } 275 276 283 public Enumeration getAllowedRelations(MMObjectNode node1, MMObjectNode node2) { 284 return getAllowedRelations(node1.getOType(), node2.getOType()); 285 } 286 287 292 public Enumeration getAllowedRelations(int builder1, int builder2) { 293 Set res = getAllowedRelations(builder1, builder2, 0, RelationStep.DIRECTIONS_BOTH); 294 return Collections.enumeration(res); 295 } 296 297 303 public Set getAllowedRelations(int builder1, int builder2, int role) { 304 return getAllowedRelations(builder1, builder2, role, RelationStep.DIRECTIONS_BOTH); 305 } 306 307 313 public Set getAllowedRelations(int builder1, int builder2, int role, int directionality) { 314 Set res = new HashSet(); 315 if (directionality != RelationStep.DIRECTIONS_SOURCE) { 316 res.addAll(typeRelNodes.getBySourceDestinationRole(builder1, builder2, role)); 317 } 318 if (directionality != RelationStep.DIRECTIONS_DESTINATION && (directionality != RelationStep.DIRECTIONS_EITHER || res.isEmpty())) { 319 res.addAll(inverseTypeRelNodes.getByDestinationSourceRole(builder2, builder1, role)); 320 } 321 return res; 322 } 323 324 331 protected Vector getAllowedRelationsNames(int snum, int dnum) { 332 Vector results = new Vector(); 333 for (Enumeration e = getAllowedRelations(snum, dnum); e.hasMoreElements();) { 334 MMObjectNode node = (MMObjectNode) e.nextElement(); 335 int rnumber = node.getIntValue("rnumber"); 336 MMObjectNode snode = mmb.getRelDef().getNode(rnumber); 337 results.addElement(snode.getStringValue("sname")); 338 } 339 return results; 340 } 341 342 351 public int getAllowedRelationType(int snum, int dnum) { 352 Set set = new HashSet(typeRelNodes.getBySourceDestination(snum, dnum)); 353 set.addAll(inverseTypeRelNodes.getByDestinationSource(dnum, snum)); 354 355 if (set.size() != 1) { 356 return -1; 357 } else { 358 MMObjectNode n = (MMObjectNode) set.iterator().next(); 359 return n.getIntValue("rnumber"); 360 } 361 } 362 363 369 public String getGUIIndicator(MMObjectNode node) { 370 try { 371 String source = mmb.getTypeDef().getValue(node.getIntValue("snumber")); 372 String destination = mmb.getTypeDef().getValue(node.getIntValue("dnumber")); 373 MMObjectNode role = mmb.getRelDef().getNode(node.getIntValue("rnumber")); 374 return source + "->" + destination + " (" + (role != null ? role.getGUIIndicator() : "???") + ")"; 375 } catch (Exception e) { 376 log.warn(e); 377 } 378 return null; 379 } 380 381 389 public String getGUIIndicator(String field, MMObjectNode node) { 390 try { 391 if (field.equals("snumber")) { 392 return mmb.getTypeDef().getValue(node.getIntValue("snumber")); 393 } else if (field.equals("dnumber")) { 394 return mmb.getTypeDef().getValue(node.getIntValue("dnumber")); 395 } else if (field.equals("rnumber")) { 396 MMObjectNode reldef = mmb.getRelDef().getNode(node.getIntValue("rnumber")); 397 return (reldef != null ? reldef.getGUIIndicator() : "???"); 398 } 399 } catch (Exception e) {} 400 return null; 401 } 402 403 409 public Vector getList(PageInfo sp, StringTagger tagger, StringTokenizer tok) { 410 if (tok.hasMoreTokens()) { 411 String cmd = tok.nextToken(); if (cmd.equals("ALLOWEDRELATIONSNAMES")) { 413 try { 414 String tmp = tagger.Value("TYPE"); 415 int number1 = mmb.getTypeDef().getIntValue(tmp); 416 tmp = tagger.Value("NODE"); 417 int number2 = Integer.parseInt(tmp); 418 MMObjectNode node = getNode(number2); 419 return getAllowedRelationsNames(number1, node.getOType()); 420 } catch (Exception e) { 421 log.error(e); 422 } 423 } 424 } 425 return null; 426 } 427 428 442 public boolean reldefCorrect(int n1, int n2, int r) { 443 return contains(n1, n2, r); 444 } 445 446 462 public boolean contains(int n1, int n2, int r) { 463 return contains(n1, n2, r, INCLUDE_DESCENDANTS); 464 } 465 466 490 public boolean contains(int n1, int n2, int r, int restriction) { 491 switch (restriction) { 492 case INCLUDE_DESCENDANTS: 493 return typeRelNodes.contains(new VirtualTypeRelNode(n1, n2, r)); 494 case INCLUDE_PARENTS: 495 return parentTypeRelNodes.contains(new VirtualTypeRelNode(n1, n2, r)); 496 case INCLUDE_PARENTS_AND_DESCENDANTS: 497 return typeRelNodes.contains(new VirtualTypeRelNode(n1, n2, r)) 498 || parentTypeRelNodes.contains(new VirtualTypeRelNode(n1, n2, r)); 499 case STRICT: 500 SortedSet existingNodes = typeRelNodes.getBySourceDestinationRole(n1, n2, r); 501 return (existingNodes.size() > 0 && !((MMObjectNode) existingNodes.first()).isVirtual()); 502 default: 503 log.error("Unknown restriction " + restriction); 504 return false; 505 } 506 } 507 508 512 516 public void notify(NodeEvent event) { 517 if (log.isDebugEnabled()) { 518 log.debug("Changed " + event.getMachine() + " " + event.getNodeNumber() + " " 519 + event.getBuilderName() + " " + NodeEvent.newTypeToOldType(event.getType())); 520 } 521 if (tableName.equals(event.getBuilderName())) { 522 if (event.getType() == NodeEvent.TYPE_NEW) { 523 Set newTypeRels = addCacheEntry(getNode(event.getNodeNumber()), true); 524 log.service("Added to typerelcache: " + newTypeRels); 525 } else { 526 readCache(); 528 } 529 } 530 super.notify(event); 531 } 532 533 539 public boolean optimizeRelationStep(BasicRelationStep relationStep, int sourceType, int destinationType, int roleInt, int searchDir) { 540 542 if (searchDir != RelationStep.DIRECTIONS_ALL && InsRel.usesdir) { 544 relationStep.setCheckedDirectionality(true); 545 } 546 547 550 boolean sourceToDestination = 551 searchDir != RelationStep.DIRECTIONS_SOURCE 552 && contains(sourceType, destinationType, roleInt, INCLUDE_PARENTS_AND_DESCENDANTS); 553 boolean destinationToSource = 554 searchDir != RelationStep.DIRECTIONS_DESTINATION 555 && contains(destinationType, sourceType, roleInt, INCLUDE_PARENTS_AND_DESCENDANTS); 556 557 if (destinationToSource && sourceToDestination && (searchDir == RelationStep.DIRECTIONS_EITHER)) { 558 destinationToSource = false; 560 } 561 562 if (destinationToSource) { 563 if (sourceToDestination) { 565 relationStep.setDirectionality(RelationStep.DIRECTIONS_BOTH); 568 } else { 569 relationStep.setDirectionality(RelationStep.DIRECTIONS_SOURCE); 572 } 573 } else { 574 if (sourceToDestination) { 575 relationStep.setDirectionality(RelationStep.DIRECTIONS_DESTINATION); 578 } else { 579 if (searchDir == RelationStep.DIRECTIONS_SOURCE) { 581 relationStep.setDirectionality(RelationStep.DIRECTIONS_SOURCE); 583 } else { 584 relationStep.setDirectionality(RelationStep.DIRECTIONS_DESTINATION); 586 } 587 return false; 588 } 589 } 590 return true; 591 } 592 593 598 public boolean equals(MMObjectNode o1, MMObjectNode o2) { 599 if (o2.getBuilder() instanceof TypeRel) { 600 int r1 = o1.getIntValue("rnumber"); 601 int r2 = o2.getIntValue("rnumber"); 602 return o1.getIntValue("snumber") == o2.getIntValue("snumber") 603 && o1.getIntValue("dnumber") == o2.getIntValue("dnumber") && (r1 == -1 || r2 == -1 || r1 == r2); 604 } 605 return false; 606 } 607 608 612 public int hashCode(MMObjectNode o) { 613 int result = 0; 614 result = HashCodeUtil.hashCode(result, o.getIntValue("snumber")); 615 result = HashCodeUtil.hashCode(result, o.getIntValue("dnumber")); 616 result = HashCodeUtil.hashCode(result, o.getIntValue("rnumber")); 617 return result; 618 } 619 620 public String toString(MMObjectNode n) { 621 try { 622 int snumber = n.getIntValue("snumber"); 623 int dnumber = n.getIntValue("dnumber"); 624 int rnumber = n.getIntValue("rnumber"); 625 626 String sourceName = mmb.getTypeDef().getValue(snumber); 627 String destName = mmb.getTypeDef().getValue(dnumber); 628 629 if (sourceName == null) sourceName = "unknown builder '" + snumber + "'"; 630 if (destName == null) destName = "unknown builder '" + dnumber + "'"; 631 632 String source = snumber > -1 ? sourceName : "[unfilled]"; 634 String destination = dnumber > -1 ? destName : "[unfilled]"; 635 MMObjectNode role = rnumber > -1 ? mmb.getRelDef().getNode(rnumber) : null; 636 return source + "->" + destination + " (" + (role != null ? role.getStringValue("sname") : "???") + ") " + (isVirtual() ? "(virtual)" : ""); 637 } catch (Exception e) { 638 log.warn(e); 639 } 640 return "typerel-node"; 641 } 642 643 650 static class VirtualTypeRel extends TypeRel { 651 static VirtualTypeRel virtualTypeRel = null; 652 653 VirtualTypeRel(TypeRel t) { 654 mmb = t.getMMBase(); 655 CoreField field = Fields.createField("snumber", Field.TYPE_NODE, Field.TYPE_UNKNOWN, Field.STATE_VIRTUAL, null); 656 field.finish(); 657 addField(field); 658 field = Fields.createField("dnumber", Field.TYPE_NODE, Field.TYPE_UNKNOWN, Field.STATE_VIRTUAL, null); 659 field.finish(); 660 addField(field); 661 field = Fields.createField("rnumber", Field.TYPE_NODE, Field.TYPE_UNKNOWN, Field.STATE_VIRTUAL, null); 662 field.finish(); 663 addField(field); 664 tableName = "virtual_typerel"; 665 virtual = true; 666 } 667 668 static VirtualTypeRel getVirtualTypeRel(TypeRel t) { 669 if (virtualTypeRel == null) virtualTypeRel = new VirtualTypeRel(t); 670 return virtualTypeRel; 671 } 672 } 673 674 681 protected class TypeRelSet extends TreeSet { 682 protected TypeRelSet() { 683 super(new Comparator() { 684 public int compare(Object o1, Object o2) { 686 MMObjectNode n1 = (MMObjectNode) o1; 687 MMObjectNode n2 = (MMObjectNode) o2; 688 689 int i1 = n1.getIntValue("snumber"); 690 int i2 = n2.getIntValue("snumber"); 691 if (i1 != i2) return i1 - i2; 692 693 i1 = n1.getIntValue("dnumber"); 694 i2 = n2.getIntValue("dnumber"); 695 if (i1 != i2) return i1 - i2; 696 697 i1 = n1.getIntValue("rnumber"); 698 i2 = n2.getIntValue("rnumber"); 699 if (i1 > 0 && i2 > 0 && i1 != i2) return i1 - i2; 700 701 return 0; 702 } 703 }); 704 } 705 706 public boolean add(Object object) { 708 MMObjectNode node = (MMObjectNode) object; 709 return super.add(node); 710 } 711 712 SortedSet getBySource(MMObjectBuilder source) { 714 return getBySourceDestinationRole(source.getNumber(), 0, 0); 715 } 716 717 SortedSet getBySource(int source) { 718 return getBySourceDestinationRole(source, 0, 0); 719 } 720 721 SortedSet getBySourceDestination(MMObjectBuilder source, MMObjectBuilder destination) { 722 return getBySourceDestinationRole(source.getNumber(), destination.getNumber(), 0); 723 } 724 725 SortedSet getBySourceDestination(int source, int destination) { 726 return getBySourceDestinationRole(source, destination, 0); 727 } 728 729 SortedSet getBySourceDestinationRole(int source, int destination, int role) { 730 int roleMin = role <= 0 ? 0 : role; 732 int destinationMin = destination <= 0 ? 0 : destination; 733 int sourceMin = source <= 0 ? 0 : source; 734 735 int roleMax = role <= 0 ? 0 : role + 1; int destinationMax = role <= 0 ? destination + 1 : destination; int sourceMax = (destination <= 0 && role <= 0) ? (source <= 0 ? 0 : source + 1) : source; 740 VirtualTypeRelNode fromTypeRelNode = new VirtualTypeRelNode(sourceMin, destinationMin, roleMin); 741 VirtualTypeRelNode toTypeRelNode = new VirtualTypeRelNode(sourceMax, destinationMax, roleMax); 742 743 SortedSet allowed = subSet(fromTypeRelNode, toTypeRelNode); 744 return Collections.unmodifiableSortedSet(allowed); 745 } 746 747 } 748 749 755 protected class InverseTypeRelSet extends TreeSet { 756 757 protected InverseTypeRelSet() { 758 super(new Comparator() { 759 public int compare(Object o1, Object o2) { 761 MMObjectNode n1 = (MMObjectNode) o1; 762 MMObjectNode n2 = (MMObjectNode) o2; 763 764 int i1 = n1.getIntValue("dnumber"); 765 int i2 = n2.getIntValue("dnumber"); 766 if (i1 != i2) return i1 - i2; 767 768 i1 = n1.getIntValue("snumber"); 769 i2 = n2.getIntValue("snumber"); 770 if (i1 != i2) return i1 - i2; 771 772 i1 = n1.getIntValue("rnumber"); 773 i2 = n2.getIntValue("rnumber"); 774 if (i1 != -1 && i2 != -1 && i1 != i2) return i1 - i2; 775 return 0; 776 } 777 }); 778 } 779 780 public boolean add(Object object) { 782 return super.add(object); 783 } 784 785 SortedSet getByDestination(MMObjectBuilder destination) { 786 return getByDestinationSourceRole(0, destination.getNumber(), 0); 787 } 788 789 SortedSet getByDestination(int destination) { 790 return getByDestinationSourceRole(0, destination, 0); 791 } 792 793 SortedSet getByDestinationSource(MMObjectBuilder source, MMObjectBuilder destination) { 794 return getByDestinationSourceRole(source.getNumber(), destination.getNumber(), 0); 795 } 796 797 SortedSet getByDestinationSource(int source, int destination) { 798 return getByDestinationSourceRole(source, destination, 0); 799 } 800 801 SortedSet getByDestinationSourceRole(int source, int destination, int role) { 802 int roleMin = role <= 0 ? 0 : role; 804 int sourceMin = source <= 0 ? 0 : source; 805 int destinationMin = destination <= 0 ? 0 : destination; 806 807 int roleMax = role <= 0 ? 0 : role + 1; int sourceMax = role <= 0 ? (source <= 0 ? 0 : source + 1) : source; int destinationMax = (source <= 0 && role <= 0) ? destination + 1 : destination; 812 return Collections.unmodifiableSortedSet(subSet(new VirtualTypeRelNode(sourceMin, destinationMin, roleMin), 813 new VirtualTypeRelNode(sourceMax, destinationMax, roleMax))); 814 } 815 816 } 817 818 824 protected class VirtualTypeRelNode extends VirtualNode { 825 826 VirtualTypeRelNode(int snumber, int dnumber) { super(VirtualTypeRel.getVirtualTypeRel(TypeRel.this)); 829 setValue("snumber", snumber); 830 setValue("dnumber", dnumber); 831 setValue("rnumber", -1); 832 } 833 834 VirtualTypeRelNode(int snumber) { super(VirtualTypeRel.getVirtualTypeRel(TypeRel.this)); 837 setValue("snumber", snumber); 838 setValue("dnumber", -1); 839 setValue("rnumber", -1); 840 } 841 VirtualTypeRelNode(int snumber, int dnumber, int rnumber) { 842 super(VirtualTypeRel.getVirtualTypeRel(TypeRel.this)); 843 setValue("snumber", snumber); 844 setValue("dnumber", dnumber); 845 setValue("rnumber", rnumber); 846 values = Collections.unmodifiableMap(values); } 848 } 849 850 851 } 852 853 | Popular Tags |