Changeset 6085
- Timestamp:
- Aug 17, 2012, 2:04:45 PM (11 years ago)
- Location:
- trunk
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/core/net/sf/basedb/core/DerivedBioAssay.java
r6082 r6085 24 24 import java.util.ArrayList; 25 25 import java.util.Collection; 26 import java.util.Collections; 26 27 import java.util.Date; 27 28 import java.util.HashSet; 29 import java.util.IdentityHashMap; 30 import java.util.Iterator; 31 import java.util.LinkedList; 32 import java.util.List; 33 import java.util.Map; 28 34 import java.util.Set; 29 35 … … 437 443 } 438 444 445 public void testFixChildren() 446 { 447 FixDerivedBioAssayParentsRecursivelyAction.get(getDbControl()).add(getData()); 448 } 449 439 450 /** 440 451 Add a physical bioassay as a parent to this derived bioassay. … … 452 463 if (bioAssay == null) throw new InvalidUseOfNullException("bioAssay"); 453 464 bioAssay.checkPermission(Permission.USE); 454 getData().getPhysicalBioAssays().add(bioAssay.getData()); 465 boolean wasAdded = getData().getPhysicalBioAssays().add(bioAssay.getData()); 466 if (wasAdded) 467 { 468 FixDerivedBioAssayParentsRecursivelyAction.get(getDbControl()).add(getData()); 469 } 455 470 } 456 471 … … 470 485 if (!isRoot()) throw new PermissionDeniedException("Can't remove physical bioassay from non-root derived bioassay"); 471 486 if (bioAssay == null) throw new InvalidUseOfNullException("bioAssay"); 472 getData().getPhysicalBioAssays().remove(bioAssay.getData()); 487 boolean wasRemoved = getData().getPhysicalBioAssays().remove(bioAssay.getData()); 488 if (wasRemoved) 489 { 490 FixDerivedBioAssayParentsRecursivelyAction.get(getDbControl()).add(getData()); 491 } 473 492 } 474 493 … … 521 540 if (this.equals(bioAssay)) throw new InvalidDataException("Can't add self as parent: " + this); 522 541 bioAssay.checkPermission(Permission.USE); 523 getData().getParents().add(bioAssay.getData()); 524 getData().getPhysicalBioAssays().addAll(bioAssay.getData().getPhysicalBioAssays()); 542 boolean wasAdded = getData().getParents().add(bioAssay.getData()); 543 if (wasAdded) 544 { 545 FixDerivedBioAssayParentsRecursivelyAction.get(getDbControl()).add(getData()); 546 } 525 547 } 526 548 … … 539 561 if (isRoot()) throw new PermissionDeniedException("Root derived bioassays can't have parent derived bioassays"); 540 562 if (bioAssay == null) throw new InvalidUseOfNullException("bioAssay"); 541 getData().getParents().remove(bioAssay.getData()); 563 boolean wasRemoved = getData().getParents().remove(bioAssay.getData()); 564 if (wasRemoved) 565 { 566 FixDerivedBioAssayParentsRecursivelyAction.get(getDbControl()).add(getData()); 567 } 542 568 } 543 569 … … 773 799 } 774 800 801 /** 802 Whenever we modify the parent items to a derived bioassay, 803 we must make sure that the physical bioassays for all 804 child items are synchronized with the same changes. 805 This is a bit complicated due to the fact that a single transaction 806 may affect multiple derived bioassays at different levels in 807 the parent-child tree. The fix must be made top-down and 808 must handle accidentally created circular references. 809 810 Whenever a change is deteced a single instance of this 811 class is associated with the DbControl. All changed 812 derived bioassays are collected with the {@link #add(DerivedBioAssayData)} 813 method. The actual fix is done as a last step before committing 814 the transaction {@link #onBeforeCommit()}. 815 */ 816 static class FixDerivedBioAssayParentsRecursivelyAction 817 implements TransactionalAction 818 { 819 820 private static Map<DbControl, FixDerivedBioAssayParentsRecursivelyAction> cache = 821 Collections.synchronizedMap(new IdentityHashMap<DbControl, DerivedBioAssay.FixDerivedBioAssayParentsRecursivelyAction>()); 822 823 /** 824 Get an instance tht handles the fixes for the given DbControl. 825 If no instance exists yet, a new one is created. 826 */ 827 static FixDerivedBioAssayParentsRecursivelyAction get(DbControl dc) 828 { 829 FixDerivedBioAssayParentsRecursivelyAction dbt = cache.get(dc); 830 if (dbt == null) 831 { 832 dbt = new FixDerivedBioAssayParentsRecursivelyAction(dc); 833 cache.put(dc, dbt); 834 } 835 return dbt; 836 } 837 838 private final DbControl dc; 839 private final Set<DerivedBioAssayData> allModified; 840 841 private FixDerivedBioAssayParentsRecursivelyAction(DbControl dc) 842 { 843 this.dc = dc; 844 this.allModified = new HashSet<DerivedBioAssayData>(); 845 dc.addTransactionalAction(this); 846 } 847 848 /** 849 Register the given derived bioassay as one that has had it's 850 parent items changed. 851 */ 852 void add(DerivedBioAssayData dba) 853 { 854 allModified.add(dba); 855 } 856 857 /* 858 From the TransactionalAction interface 859 -------------------------------------- 860 */ 861 @Override 862 public void onBeforeCommit() 863 { 864 865 Set<DerivedBioAssayData> allToFix = new HashSet<DerivedBioAssayData>(); 866 List<DerivedBioAssayData> moreToFix = new LinkedList<DerivedBioAssayData>(); 867 868 // First step is to find all child items recursively 869 // All non-root bioassays need to be fixed and all children may also have to be fixed 870 for (DerivedBioAssayData dba : allModified) 871 { 872 if (!dba.isRoot()) allToFix.add(dba); 873 if (dba.getChildren() != null) 874 { 875 moreToFix.addAll(dba.getChildren()); 876 } 877 } 878 879 // Check each child item and then also grandchildren 880 while (moreToFix.size() > 0) 881 { 882 DerivedBioAssayData dba = moreToFix.remove(0); 883 if (allToFix.add(dba) && dba.getChildren() != null) 884 { 885 moreToFix.addAll(dba.getChildren()); 886 } 887 } 888 // We now have all items that must be fixed... 889 890 //System.out.println("allToFix: " + allToFix); 891 892 // We don't know the actual order that items can be fixed, so 893 // we have to keep trying until the set is empty 894 while (allToFix.size() > 0) 895 { 896 int numFixed = 0; 897 Iterator<DerivedBioAssayData> it = allToFix.iterator(); 898 while (it.hasNext()) 899 { 900 DerivedBioAssayData dba = it.next(); 901 // Collect all physical bioassays from all parents in this set 902 Set<PhysicalBioAssayData> allPhysicalBioAssays = new HashSet<PhysicalBioAssayData>(); 903 boolean canFix = true; 904 905 // For each item that should be fixed, load all parent items... 906 for (DerivedBioAssayData parent : dba.getParents()) 907 { 908 if (allToFix.contains(parent)) 909 { 910 // If at least one parent has not yet been fixed, we can't fix this item now 911 canFix = false; 912 break; 913 } 914 allPhysicalBioAssays.addAll(parent.getPhysicalBioAssays()); 915 } 916 917 if (canFix) 918 { 919 //System.out.println("Fixing: " + dba.getName() + "; " + allPhysicalBioAssays); 920 it.remove(); 921 dba.getPhysicalBioAssays().clear(); 922 dba.getPhysicalBioAssays().addAll(allPhysicalBioAssays); 923 numFixed++; 924 } 925 else 926 { 927 //System.out.println("Can't fix " + dba.getName() + " yet, since it has unfixed parents"); 928 } 929 } 930 // If we couldn't fix any item in the last iteration, but there are more 931 // items to fix, throw an exception since this is an indication of circular 932 // reference 933 if (numFixed == 0 && allToFix.size() > 0) 934 { 935 // Hmm... a circular reference prevents us from fixing 936 throw new InvalidDataException("Circular reference between derived bioassays: " + allToFix); 937 } 938 } 939 940 } 941 942 @Override 943 public void onAfterCommit() 944 { 945 cache.remove(dc); 946 } 947 948 @Override 949 public void onRollback() 950 { 951 cache.remove(dc); 952 } 953 // --------------------------------------- 954 955 } 775 956 } -
trunk/src/core/net/sf/basedb/core/data/DerivedBioAssayData.java
r6082 r6085 157 157 @hibernate.collection-many-to-many column="`derivedbioassay_id`" class="net.sf.basedb.core.data.DerivedBioAssayData" 158 158 */ 159 Set<DerivedBioAssayData> getChildren()159 public Set<DerivedBioAssayData> getChildren() 160 160 { 161 161 return children; -
trunk/www/views/derivedbioassays/edit_bioassay.jsp
r6082 r6085 403 403 } 404 404 405 function selectPhysicalBioAssayOnClick()406 {407 var frm = document.forms['bioAssay'];408 var url = '../physicalbioassays/index.jsp?ID=<%=ID%>&cmd=UpdateContext&mode=selectone';409 url += '&callback=setPhysicalBioAssayCallback&resetTemporary=1';410 url += ItemSubtype.createRelatedFilter('bioAssay', 'PHYSICALBIOASSAY');411 if (frm.physicalbioassay_id.selectedIndex >= 0)412 {413 var id = Math.abs(parseInt(frm.physicalbioassay_id[frm.physicalbioassay_id.selectedIndex].value));414 url += '&item_id='+id;415 }416 Main.openPopup(url, 'SelectPhysicalBioAssay', 1050, 700);417 }418 function setPhysicalBioAssayCallback(id, name)419 {420 var frm = document.forms['bioAssay'];421 var list = frm.physicalbioassay_id;422 if (list.length < 1 || list[0].value == '0') // >423 {424 Forms.addListOption(list, 0, new Option());425 }426 list[0].value = id;427 list[0].text = name;428 list.selectedIndex = 0;429 physicalBioAssayOnChange();430 }431 405 function physicalBioAssayOnChange() 432 406 { … … 435 409 } 436 410 437 function selectParentBioAssayOnClick()438 {439 var frm = document.forms['bioAssay'];440 var url = 'index.jsp?ID=<%=ID%>&cmd=UpdateContext&mode=selectone';441 url += '&callback=setParentBioAssayCallback&resetTemporary=1';442 url += ItemSubtype.createRelatedFilter('bioAssay', 'DERIVEDBIOASSAY');443 if (frm.parents.selectedIndex >= 0)444 {445 var id = Math.abs(parseInt(frm.parents[frm.parents.selectedIndex].value));446 url += '&item_id='+id;447 }448 Main.openPopup(url, 'SelectParentBioAssay', 1050, 700);449 }450 function setParentBioAssayCallback(id, name)451 {452 var frm = document.forms['bioAssay'];453 var list = frm.parents;454 if (list.length < 1 || list[0].value == '0') // >455 {456 Forms.addListOption(list, 0, new Option());457 }458 list[0].value = id;459 list[0].text = name;460 list.selectedIndex = 0;461 parentBioAssayOnChange();462 }463 411 function parentBioAssayOnChange() 464 412 { … … 536 484 } 537 485 486 function removePhysicalBioAssayOnClick() 487 { 488 Link.removeSelected(document.forms['bioAssay'].physicalBioAssays); 489 parentsChanged = true; 490 } 491 492 538 493 function addParentOnClick() 539 494 { … … 553 508 parentsChanged = true; 554 509 } 510 511 function removeParentOnClick() 512 { 513 Link.removeSelected(document.forms['bioAssay'].parents); 514 parentsChanged = true; 515 } 516 555 517 556 518 function init()
Note: See TracChangeset
for help on using the changeset viewer.