Changeset 4705


Ignore:
Timestamp:
Dec 16, 2008, 2:29:12 PM (13 years ago)
Author:
Nicklas Nordborg
Message:

Fixes #1191: Biomaterial lists manager API and interface

Location:
trunk
Files:
1 added
8 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/core/net/sf/basedb/core/BioMaterialList.java

    r4681 r4705  
    2222*/
    2323package net.sf.basedb.core;
     24
     25import java.util.Collection;
     26import java.util.HashMap;
     27import java.util.HashSet;
     28import java.util.Iterator;
     29import java.util.Map;
     30import java.util.Set;
     31
     32import org.apache.commons.collections.CollectionUtils;
     33import org.apache.commons.collections.Predicate;
    2434
    2535import net.sf.basedb.core.query.Restrictions;
     
    102112  }
    103113
     114  /**
     115    Create a set with the intersection of the items
     116    in the given lists.
     117    @return A set with items. The set is always a new
     118      set, modifications to it will not affect anything else
     119  */
     120  private static Set<BioMaterialData> intersection(Collection<BioMaterialList> lists)
     121  {
     122    Set<BioMaterialData> intersection = new HashSet<BioMaterialData>();
     123    if (lists != null)
     124    {
     125      boolean first = true;
     126      Iterator<BioMaterialList> it = lists.iterator();
     127      while (it.hasNext())
     128      {
     129        Set<BioMaterialData> other = it.next().getData().getBioMaterials();
     130        if (first)
     131        {
     132          intersection.addAll(other);
     133          first = false;
     134        }
     135        else
     136        {
     137          intersection.retainAll(other);
     138        }
     139      }
     140    }
     141    return intersection;
     142  }
     143 
     144  /**
     145    Create a set with the union of the items
     146    in the given lists.
     147    @return A set with items. The set is always a new
     148      set, modifications to it will not affect anything else
     149  */
     150  private static Set<BioMaterialData> union(Collection<BioMaterialList> lists)
     151  {
     152    Set<BioMaterialData> union = new HashSet<BioMaterialData>();
     153    if (lists != null)
     154    {
     155      for (BioMaterialList list : lists)
     156      {
     157          union.addAll(list.getData().getBioMaterials());
     158      }
     159    }
     160    return union;
     161  }
     162 
     163  /**
     164    Count the number of times each item is present in the
     165    given lists and return those items that are found in
     166    &gt=minCount and &lt;=maxCount lists.
     167    <p>
     168    NOTE!
     169    <ul>
     170      <li>'minCount=1' and 'maxCount=number of lists' is the same
     171        as {@link #union(Collection)}
     172      <li>'minCount=maxCount=number of lists' is the same
     173        as {@link #intersection(Collection)}.
     174    </ul>
     175 
     176    @param lists The lists to look in
     177    @param minCount The minimum number of list an item
     178      is required to be present in
     179    @param maxCount The maximum number of lists an item
     180      is allowed to the present in
     181    @return A set with items. It is always a new
     182      set, modifications to it will not affect anything else
     183  */
     184  private static Set<BioMaterialData> count(Collection<BioMaterialList> lists, final int minCount, final int maxCount)
     185  {
     186    Map<BioMaterialData, Integer> union = new HashMap<BioMaterialData, Integer>();
     187    if (lists != null)
     188    {
     189      Iterator<BioMaterialList> it = lists.iterator();
     190      while (it.hasNext())
     191      {
     192        Iterator<BioMaterialData> e = it.next().getData().getBioMaterials().iterator();
     193        while (e.hasNext())
     194        {
     195          BioMaterialData bm = e.next();
     196          Integer count = union.get(bm);
     197          count = count == null ? 1 : count+1;
     198          union.put(bm, count);
     199        }
     200      }
     201    }
     202    CollectionUtils.filter(union.values(),
     203      new Predicate()
     204    {
     205      @Override
     206      public boolean evaluate(Object o)
     207      {
     208        int count = (Integer)o;
     209        return minCount <= count && count <= maxCount;
     210      }
     211    });
     212    return union.keySet();
     213  }
     214 
    104215  BioMaterialList(BioMaterialListData listData)
    105216  {
     
    168279    }
    169280    getData().setMemberType(memberType.getValue());
     281  }
     282 
     283  /**
     284    Checks if the other type is the same type as the member type of
     285    this list.
     286  */
     287  private void checkMemberType(Item otherType)
     288  {
     289    if (getMemberType() != otherType)
     290    {
     291      throw new InvalidDataException("List '" + getName() + "' can't contain " + otherType);
     292    }
     293  }
     294 
     295  /**
     296    Checks that the lists have the same member type as this list.
     297  */
     298  private void checkMemberType(Collection<BioMaterialList> lists)
     299  {
     300    Item memberType = getMemberType();
     301    for (BioMaterialList list : lists)
     302    {
     303      if (memberType != list.getMemberType())
     304      {
     305        throw new InvalidDataException("List '" + getName() + "' can't contain " + list.getMemberType());
     306      }
     307    }
    170308  }
    171309 
     
    186324    checkPermission(Permission.WRITE);
    187325    if (bioMaterial == null) throw new InvalidUseOfNullException("bioMaterial");
    188     if (bioMaterial.getType() != getMemberType())
    189     {
    190       throw new InvalidDataException("List '" + getName() + "' can't contain " + bioMaterial.getType());
    191     }
     326    checkMemberType(bioMaterial.getType());
    192327    boolean added = getData().getBioMaterials().add((BioMaterialData)bioMaterial.getData());
    193328    if (added) getData().setSize(getSize() + 1);
     
    268403  }
    269404
    270  
     405  /**
     406    Add members to this list.
     407    @param items The items to add
     408    @return The number of new items
     409  */
     410  private int addMembers(Set<BioMaterialData> items)
     411  {
     412    int numAdded = 0;
     413    BioMaterialListData data = getData();
     414    Set<BioMaterialData> target = data.getBioMaterials();
     415    for (BioMaterialData item : items)
     416    {
     417      if (target.add(item)) numAdded++;
     418    }
     419    data.setSize(getSize() + numAdded);
     420    return numAdded;
     421  }
     422 
     423  /**
     424    Remove members from this list
     425    @param items The items to remove
     426    @return The number of removed items
     427  */
     428  private int removeMembers(Set<BioMaterialData> items)
     429  {
     430    int numRemoved = 0;
     431    BioMaterialListData data = getData();
     432    Set<BioMaterialData> target = data.getBioMaterials();
     433   
     434    // We loop over the list that is smallest
     435    if (items.size() <= this.getSize())
     436    {
     437      for (BioMaterialData item : items)
     438      {
     439        if (target.remove(item)) numRemoved++;
     440      }
     441    }
     442    else
     443    {
     444      Iterator<BioMaterialData> it = target.iterator();
     445      while (it.hasNext())
     446      {
     447        if (items.contains(it.next()))
     448        {
     449          it.remove();
     450          numRemoved++;
     451        }
     452      }
     453    }
     454    data.setSize(getSize() - numRemoved);
     455    return numRemoved;
     456  }
     457 
     458  /**
     459    Keep only specified members in this list
     460    @param items The items to keep
     461    @return The number of removed items
     462  */
     463  private int retainMembers(Set<BioMaterialData> items)
     464  {
     465    int numRemoved = 0;
     466    BioMaterialListData data = getData();
     467    Set<BioMaterialData> target = data.getBioMaterials();
     468
     469    if (items.size() == 0)
     470    {
     471      target.clear();
     472      numRemoved = getSize();
     473    }
     474    else
     475    {
     476      Iterator<BioMaterialData> it = target.iterator();
     477      while (it.hasNext())
     478      {
     479        if (!items.contains(it.next()))
     480        {
     481          it.remove();
     482          numRemoved++;
     483        }
     484      }
     485    }
     486    data.setSize(getSize() - numRemoved);
     487    return numRemoved;
     488  }
     489 
     490  /**
     491    Add all items from another biomaterial list to this
     492    list. The new list is the union of the existing list
     493    and the added list. The other list must have the
     494    same member type as this list.
     495   
     496    @param list The list to add items from
     497    @return The number of items added (not including
     498      items that already was in this list)
     499  */
     500  public int addAll(BioMaterialList list)
     501  {
     502    checkPermission(Permission.WRITE);
     503    if (list == null) return 0;
     504    checkMemberType(list.getMemberType());
     505    return addMembers(list.getData().getBioMaterials());
     506  }
     507
     508  /**
     509    Add items that are present in at least ONE OF the given lists to
     510    this list. Eg. the added items is the union from
     511    the given lists.
     512 
     513    @param lists The lists to add items from
     514    @return The number of items added (not including
     515      items that already was in this list)
     516  */
     517  public int addUnion(Collection<BioMaterialList> lists)
     518  {
     519    checkPermission(Permission.WRITE);
     520    if (lists == null) return 0;
     521    checkMemberType(lists);
     522
     523    int numAdded = 0;
     524    if (lists.size() == 1)
     525    {
     526      numAdded = addMembers(lists.iterator().next().getData().getBioMaterials());
     527    }
     528    else if (lists.size() > 1)
     529    {
     530      numAdded = addMembers(union(lists));
     531    }
     532    return numAdded;
     533  }
     534
     535  /**
     536    Add items that are present in the specified number of lists to
     537    this list.
     538    <ul>
     539    <li>Delegate to {@link #addUnion(Collection)} if
     540      <code>minCount &lt;= 1 && maxCount &gt;= size(lists)</code>
     541    <li>Delegate to {@link #addIntersection(Collection)}
     542      if <code>minCount = size(lists) && maxCount >= size(lists)</code>.
     543    <li>If <code>minCount &gt; size(lists) || minCount > maxCount</code> no
     544      items will be added.
     545    </ul>
     546   
     547    @param lists The lists to add items from
     548    @param minCount The minimum number of lists an item is required to
     549      be present in
     550    @param maxCount The maximum number of lists an item is allowed to
     551      be present in
     552    @return The number of items added (not including
     553      items that already was in this list)
     554  */
     555  public int addIfPresentIn(int minCount, int maxCount, Collection<BioMaterialList> lists)
     556  {
     557    checkPermission(Permission.WRITE);
     558    if (lists == null) return 0;
     559    checkMemberType(lists);
     560   
     561    int numAdded = 0;
     562    int numLists = lists.size();
     563    if (minCount <= 1 && maxCount >= numLists)
     564    {
     565      numAdded = addUnion(lists);
     566    }
     567    else if (minCount == numLists && maxCount >= numLists)
     568    {
     569      numAdded = addIntersection(lists);
     570    }
     571    else if (minCount < numLists && minCount <= maxCount)
     572    {
     573      numAdded = addMembers(count(lists, minCount, maxCount));
     574    }
     575    return numAdded;
     576  }
     577
     578  /**
     579    Add items that are present in ALL OF the given lists to
     580    this list. Eg. the added items is the intersection from
     581    the given lists.
     582 
     583    @param lists The lists to add items from
     584    @return The number of items added (not including
     585      items that already was in this list)
     586  */
     587  public int addIntersection(Collection<BioMaterialList> lists)
     588  {
     589    checkPermission(Permission.WRITE);
     590    if (lists == null) return 0;
     591    checkMemberType(lists);
     592   
     593    int numAdded = 0;
     594    if (lists.size() == 1)
     595    {
     596      numAdded = addMembers(lists.iterator().next().getData().getBioMaterials());
     597    }
     598    else if (lists.size() > 1)
     599    {
     600      numAdded = addMembers(intersection(lists));
     601    }
     602    return numAdded;
     603  }
     604
     605  /**
     606    Remove all items from this list that are present
     607    in the other list.
     608   
     609    @param list The list that contains the items
     610      to remove
     611    @return The number of items removed from this list
     612  */
     613  public int removeAll(BioMaterialList list)
     614  {
     615    checkPermission(Permission.WRITE);
     616    if (list == null) return 0;
     617    return removeMembers(list.getData().getBioMaterials());
     618  }
     619
     620  /**
     621    Remove items that are present in at least ONE OF the given lists from
     622    this list. Eg. the removed items is the union from
     623    the given lists.
     624 
     625    @param lists The lists that contains the items to remove
     626    @return The number of items removed from this list
     627  */
     628  public int removeUnion(Collection<BioMaterialList> lists)
     629  {
     630    checkPermission(Permission.WRITE);
     631    if (lists == null) return 0;
     632   
     633    int numRemoved = 0;
     634    if (lists.size() == 1)
     635    {
     636      numRemoved = removeMembers(lists.iterator().next().getData().getBioMaterials());
     637    }
     638    else if (lists.size() > 1)
     639    {
     640      numRemoved = removeMembers(union(lists));
     641    }
     642    return numRemoved;
     643  }
     644
     645  /**
     646    Remove items that are present in the specified number of lists from
     647    this list.
     648    <ul>
     649    <li>Delegate to {@link #removeUnion(Collection)} if
     650      <code>minCount &lt;= 1 && maxCount &gt;= size(lists)</code>
     651    <li>Delegate to {@link #removeIntersection(Collection)}
     652      if <code>minCount = size(lists) && maxCount >= size(lists)</code>.
     653    <li>If <code>minCount &gt; size(lists) || minCount > maxCount</code> no
     654      items will be removed.
     655    </ul>
     656   
     657    @param lists The lists with the items
     658    @param minCount The minimum number of lists an item is required to
     659      be present in
     660    @param maxCount The maximum number of lists an item is allowed to
     661      be present in
     662    @return The number of items removed
     663  */
     664  public int removeIfPresentIn(int minCount, int maxCount, Collection<BioMaterialList> lists)
     665  {
     666    checkPermission(Permission.WRITE);
     667    if (lists == null) return 0;
     668   
     669    int numRemoved = 0;
     670    int numLists = lists.size();
     671    if (minCount <= 1 && maxCount >= numLists)
     672    {
     673      numRemoved = removeUnion(lists);
     674    }
     675    else if (minCount == numLists && maxCount >= numLists)
     676    {
     677      numRemoved = removeIntersection(lists);
     678    }
     679    else if (minCount < numLists && minCount <= maxCount)
     680    {
     681      numRemoved = removeMembers(count(lists, minCount, maxCount));
     682    }
     683    return numRemoved;
     684  }
     685
     686  /**
     687    Remove items that are present in ALL OF the given lists from
     688    this list. Eg. the removed items is the intersection from
     689    the given lists.
     690 
     691    @param lists The lists that contains the items to remove
     692    @return The number of items removed from this list
     693  */
     694  public int removeIntersection(Collection<BioMaterialList> lists)
     695  {
     696    checkPermission(Permission.WRITE);
     697    if (lists == null) return 0;
     698   
     699    int numRemoved = 0;
     700    if (lists.size() == 1)
     701    {
     702      numRemoved = removeMembers(lists.iterator().next().getData().getBioMaterials());
     703    }
     704    else if (lists.size() > 1)
     705    {
     706      numRemoved = removeMembers(intersection(lists));
     707    }
     708    return numRemoved;
     709  }
     710
     711  /**
     712    Remove all items from this list that are NOT present
     713    in the other list. The new list is the intersection
     714    of the existing list and the other list. NOTE! If the
     715    other list is null or empty, all items will be removed
     716    from this list.
     717   
     718    @param list The list that contains the items
     719      to be retained
     720    @return The number of items removed from this list
     721  */
     722  public int retainAll(BioMaterialList list)
     723  {
     724    checkPermission(Permission.WRITE);
     725    int numRemoved = 0;
     726    if (list == null || list.getSize() == 0)
     727    {
     728      getData().getBioMaterials().clear();
     729      numRemoved = getSize();
     730      getData().setSize(0);
     731    }
     732    else
     733    {
     734      numRemoved = retainMembers(list.getData().getBioMaterials());
     735    }
     736    return numRemoved;
     737  }
     738
     739  /**
     740    Retain items that are present in at least ONE OF the given lists
     741    in this list. Eg. items that are not found in any of the given
     742    lists are removed from this list.
     743 
     744    @param lists The lists that contains the items to retain
     745    @return The number of items removed from this list
     746  */
     747  public int retainUnion(Collection<BioMaterialList> lists)
     748  {
     749    checkPermission(Permission.WRITE);
     750    int numRemoved = 0;
     751    if (lists == null || lists.size() == 0)
     752    {
     753      getData().getBioMaterials().clear();
     754      numRemoved = getSize();
     755      getData().setSize(0);
     756    }
     757    else if (lists.size() == 1)
     758    {
     759      numRemoved = retainMembers(lists.iterator().next().getData().getBioMaterials());
     760    }
     761    else
     762    {
     763      numRemoved = retainMembers(union(lists));
     764    }
     765    return numRemoved;
     766  }
     767
     768  /**
     769    Retain items that are present in ALL OF the given lists
     770    in this list. Eg. items that are not found in all
     771    lists of the given lists are removed from this list.
     772 
     773    @param lists The lists that contains the items to retain
     774    @return The number of items removed from this list
     775  */
     776  public int retainIntersection(Collection<BioMaterialList> lists)
     777  {
     778    checkPermission(Permission.WRITE);
     779    int numRemoved = 0;
     780    if (lists == null || lists.size() == 0)
     781    {
     782      getData().getBioMaterials().clear();
     783      numRemoved = getSize();
     784      getData().setSize(0);
     785    }
     786    else if (lists.size() == 1)
     787    {
     788      numRemoved = retainMembers(lists.iterator().next().getData().getBioMaterials());
     789    }
     790    else
     791    {
     792      numRemoved = retainMembers(intersection(lists));
     793    }
     794    return numRemoved;
     795  }
     796
     797  /**
     798    Retain items that are present in the specified number of lists in
     799    this list.
     800    <ul>
     801    <li>Delegate to {@link #retainUnion(Collection)} if
     802      <code>minCount &lt;= 1 && maxCount &gt;= size(lists)</code>
     803    <li>Delegate to {@link #retainIntersection(Collection)}
     804      if <code>minCount = size(lists) && maxCount >= size(lists)</code>.
     805    <li>If <code>minCount &gt; size(lists) || minCount > maxCount</code> no
     806      items will be removed.
     807    </ul>
     808   
     809    @param lists The lists with the items
     810    @param minCount The minimum number of lists an item is required to
     811      be present in
     812    @param maxCount The maximum number of lists an item is allowed to
     813      be present in
     814    @return The number of items removed
     815  */
     816  public int retainIfPresentIn(int minCount, int maxCount, Collection<BioMaterialList> lists)
     817  {
     818    checkPermission(Permission.WRITE);
     819    int numRemoved = 0;
     820    int numLists = lists == null ? 0 : lists.size();
     821    if (minCount <= 1 && maxCount >= numLists)
     822    {
     823      numRemoved = retainUnion(lists);
     824    }
     825    else if (minCount == numLists && maxCount >= numLists)
     826    {
     827      numRemoved = retainIntersection(lists);
     828    }
     829    else if (minCount < numLists && minCount <= maxCount)
     830    {
     831      numRemoved = retainMembers(count(lists, minCount, maxCount));
     832    }
     833    return numRemoved;
     834  }
     835
    271836}
  • trunk/src/test/TestBioMaterialList.java

    r4681 r4705  
    2222  along with BASE. If not, see <http://www.gnu.org/licenses/>.
    2323*/
    24 import net.sf.basedb.core.*;
    25 
     24
     25
     26import java.util.ArrayList;
    2627import java.util.Date;
     28import java.util.List;
     29
     30import net.sf.basedb.core.BaseException;
     31import net.sf.basedb.core.BioMaterial;
     32import net.sf.basedb.core.BioMaterialList;
     33import net.sf.basedb.core.DbControl;
     34import net.sf.basedb.core.Item;
     35import net.sf.basedb.core.ItemQuery;
     36import net.sf.basedb.core.ItemResultList;
     37import net.sf.basedb.core.Permission;
    2738
    2839public class TestBioMaterialList
     
    4455    // Standard tests: create, load, list
    4556    int id1 = test_create(Item.BIOSOURCE, "net.sf.basedb.clients.test.bmlist1", true);
     57    int id2 = test_create(Item.BIOSOURCE, "net.sf.basedb.clients.test.bmlist2", true);
     58    int id3 = test_create(Item.BIOSOURCE, "net.sf.basedb.clients.test.bmlist3", true);
     59    int id4 = test_create(Item.BIOSOURCE, "net.sf.basedb.clients.test.bmlist4", true);
     60    int id5 = test_create(Item.BIOSOURCE, "net.sf.basedb.clients.test.bmlist5", true);
     61    int id6 = test_create(Item.BIOSOURCE, "net.sf.basedb.clients.test.bmlist6", true);
    4662    test_load(id1);
    4763    test_list(-1);
    4864
    4965    // Create items to use in the lists
    50     int bs1 = TestBioSource.test_create(false);
    51     int bs2 = TestBioSource.test_create(false);
     66    int bs1 = TestBioSource.test_create("bs.1", false);
     67    int bs2 = TestBioSource.test_create("bs.2", false);
     68    int bs3 = TestBioSource.test_create("bs.3", false);
     69    int bs4 = TestBioSource.test_create("bs.4", false);
     70    int bs5 = TestBioSource.test_create("bs.5", false);
    5271   
    53     test_add_member(id1, bs1);
    54     test_add_member(id1, bs2);
    55     test_list_members(id1, 2);
     72    test_add_members(id1, bs1, bs2, bs3);
     73    test_list_members(id1, 3);
     74    test_add_members(id2, bs3, bs4, bs5); // One in common with 'id1'
     75   
     76    test_union(id3, 5, id1, id2); // 'id3' is now the union of 'id1' and 'id2'
     77    test_intersect(id4, 1, id1, id2); // 'id4' is now the intersection of 'id1' and 'id2'
     78    test_remove(id5, id3, 4, id4); // 'id5' is now the complement of 'id3' to 'id4'
     79    test_retain(id6, id2, 1, id1); // 'id6' is now the intersection on 'id1' and 'id2'
    5680   
    5781    if (TestUtil.waitBeforeDelete()) TestUtil.waitForEnter();
    5882    test_remove_member(id1, bs1);
    5983    test_remove_member(id1, bs2);
    60     test_list_members(id1, 0);
     84    test_list_members(id1, 1);
    6185   
    6286    // Standard test: Delete
    6387    test_delete(id1);
     88    test_delete(id2);
     89    test_delete(id3);
     90    test_delete(id4);
     91    test_delete(id5);
     92    test_delete(id6);
    6493    TestBioSource.test_delete(bs1);
    6594    TestBioSource.test_delete(bs2);
     95    TestBioSource.test_delete(bs3);
     96    TestBioSource.test_delete(bs4);
     97    TestBioSource.test_delete(bs5);
    6698    write("++Testing biomaterial lists "+(ok ? "OK" : "Failed")+"\n");
    6799    return ok;
     
    205237  }
    206238
    207   static void test_add_member(int id, int itemId)
    208   {
    209     if (id == 0 || itemId == 0) return;
     239  static void test_add_members(int id, int... itemIds)
     240  {
     241    if (id == 0 || itemIds == null || itemIds.length == 0) return;
    210242    DbControl dc = null;
    211243    try
     
    214246      BioMaterialList bl = BioMaterialList.getById(dc, id);
    215247      int oldSize = bl.getSize();
    216       BioMaterial bm = (BioMaterial)bl.getMemberType().getById(dc, itemId);
    217       bl.add(bm);
     248      for (int iid : itemIds)
     249      {
     250        BioMaterial bm = (BioMaterial)bl.getMemberType().getById(dc, iid);
     251        bl.add(bm);
     252      }
    218253      dc.commit();
    219254     
     
    221256      bl = BioMaterialList.getById(dc, id);
    222257      int newSize = bl.getSize();
    223       if (newSize != oldSize + 1)
     258      if (newSize != oldSize + itemIds.length)
    224259      {
    225260        throw new BaseException("new size=" + newSize + "; old size="+oldSize);
     
    304339  }
    305340
     341  static void test_union(int toId, int expectedSize, int... fromId)
     342  {
     343    if (toId == 0) return;
     344    DbControl dc = null;
     345    try
     346    {
     347      dc = TestUtil.getDbControl();
     348      BioMaterialList to = BioMaterialList.getById(dc, toId);
     349      List<BioMaterialList> from = new ArrayList<BioMaterialList>(fromId.length);
     350      for (int rlId : fromId)
     351      {
     352        from.add(BioMaterialList.getById(dc, rlId));
     353      }
     354      to.addUnion(from);
     355      dc.commit();
     356      if (expectedSize != to.getSize())
     357      {
     358        throw new BaseException("Incorrect size; expected=" + expectedSize + "; actual=" + to.getSize());
     359      }
     360      write("--Create union OK (size=" + expectedSize + ")");
     361    }
     362    catch (Throwable ex)
     363    {
     364      write ("--Create union FAILED");
     365      ex.printStackTrace();
     366      ok = false;
     367    }
     368    finally
     369    {
     370      if (dc != null) dc.close();
     371    }
     372  }
     373
     374  static void test_intersect(int toId, int expectedSize, int... fromId)
     375  {
     376    if (toId == 0) return;
     377    DbControl dc = null;
     378    try
     379    {
     380      dc = TestUtil.getDbControl();
     381      BioMaterialList to = BioMaterialList.getById(dc, toId);
     382      List<BioMaterialList> from = new ArrayList<BioMaterialList>(fromId.length);
     383      for (int rlId : fromId)
     384      {
     385        from.add(BioMaterialList.getById(dc, rlId));
     386      }
     387      to.addIntersection(from);
     388      dc.commit();
     389      if (expectedSize != to.getSize())
     390      {
     391        throw new BaseException("Incorrect size; expected=" + expectedSize + "; actual=" + to.getSize());
     392      }
     393      write("--Create intersection OK (size=" + expectedSize + ")");
     394    }
     395    catch (Throwable ex)
     396    {
     397      write ("--Create intersection FAILED");
     398      ex.printStackTrace();
     399      ok = false;
     400    }
     401    finally
     402    {
     403      if (dc != null) dc.close();
     404    }
     405  }
     406
     407  static void test_remove(int toId, int baseId, int expectedSize, int... complementId)
     408  {
     409    if (toId == 0) return;
     410    DbControl dc = null;
     411    try
     412    {
     413      dc = TestUtil.getDbControl();
     414      BioMaterialList to = BioMaterialList.getById(dc, toId);
     415      to.addAll(BioMaterialList.getById(dc, baseId));
     416      List<BioMaterialList> from = new ArrayList<BioMaterialList>(complementId.length);
     417      for (int rlId : complementId)
     418      {
     419        from.add(BioMaterialList.getById(dc, rlId));
     420      }
     421      to.removeUnion(from);
     422      dc.commit();
     423      if (expectedSize != to.getSize())
     424      {
     425        throw new BaseException("Incorrect size; expected=" + expectedSize + "; actual=" + to.getSize());
     426      }
     427      write("--Remove items OK (size=" + expectedSize + ")");
     428    }
     429    catch (Throwable ex)
     430    {
     431      write ("--Remove items FAILED");
     432      ex.printStackTrace();
     433      ok = false;
     434    }
     435    finally
     436    {
     437      if (dc != null) dc.close();
     438    }
     439  }
     440 
     441  static void test_retain(int toId, int baseId, int expectedSize, int... complementId)
     442  {
     443    if (toId == 0) return;
     444    DbControl dc = null;
     445    try
     446    {
     447      dc = TestUtil.getDbControl();
     448      BioMaterialList to = BioMaterialList.getById(dc, toId);
     449      to.addAll(BioMaterialList.getById(dc, baseId));
     450      List<BioMaterialList> from = new ArrayList<BioMaterialList>(complementId.length);
     451      for (int rlId : complementId)
     452      {
     453        from.add(BioMaterialList.getById(dc, rlId));
     454      }
     455      to.retainUnion(from);
     456      dc.commit();
     457      if (expectedSize != to.getSize())
     458      {
     459        throw new BaseException("Incorrect size; expected=" + expectedSize + "; actual=" + to.getSize());
     460      }
     461      write("--Retain items OK (size=" + expectedSize + ")");
     462    }
     463    catch (Throwable ex)
     464    {
     465      write ("--Retain items FAILED");
     466      ex.printStackTrace();
     467      ok = false;
     468    }
     469    finally
     470    {
     471      if (dc != null) dc.close();
     472    }
     473  }
     474 
     475 
    306476}
    307477
  • trunk/src/test/TestBioSource.java

    r4514 r4705  
    4242    write_header();
    4343    // Standard tests: create, load, list
    44     int id = test_create(true);
    45     int id2 = test_create(false);
     44    int id = test_create(null, true);
     45    int id2 = test_create(null, false);
    4646    test_load(id);
    4747    test_list(-1);
     
    5555  }
    5656
    57   static int test_create(boolean setAll)
     57  static int test_create(String name, boolean setAll)
    5858  {
    5959    if (!TestUtil.hasPermission(Permission.CREATE, Item.BIOSOURCE)) return 0;
     
    7070        b.setExternalId("XCV-455");
    7171      }
     72      if (name != null) b.setName(name);
    7273      dc.saveItem(b);
    7374      dc.commit();
  • trunk/src/test/TestSample.java

    r4559 r4705  
    4646    int id2 = test_create(0, null, false);
    4747   
    48     int bioSourceId = TestBioSource.test_create(false);
     48    int bioSourceId = TestBioSource.test_create(null, false);
    4949    int id3 = test_create(bioSourceId, null, false);
    5050    int id4 = test_create_pooled(id, id2, id3);
  • trunk/www/biomaterials/lists/edit_list.jsp

    r4681 r4705  
    4949  String title = null;
    5050  BioMaterialList list = null;
    51 
     51  Item memberType = null;
     52  boolean mergeLists = false;
     53  int numSelectedLists = cc.getSelected().size();
     54 
    5255  if (itemId == 0)
    5356  {
    5457    title = "Create biomaterial list";
    5558    cc.removeObject("item");
     59    memberType = Item.fromValue(Values.getInt(cc.getPropertyValue("memberType")));
     60    mergeLists = numSelectedLists > 0;
    5661  }
    5762  else
    5863  {
    5964    list = BioMaterialList.getById(dc, itemId);
     65    memberType = list.getMemberType();
    6066    cc.setObject("item", list);
    6167    title = "Edit biomaterial list -- " + HTML.encodeTags(list.getName());
     
    106112      %>
    107113    }
     114    function checkRadio(radio, name)
     115    {
     116      Forms.checkRadio(radio, name);
     117    }
    108118    </script>
    109119  </base:head>
     
    112122    <form action="index.jsp?ID=<%=ID%>" method="post" name="list" onsubmit="return false;">
    113123    <input type="hidden" name="cmd" value="UpdateItem">
    114 
    115124    <h3 class="docked"><%=title%> <base:help tabcontrol="settings"/></h3>
    116125    <t:tabcontrol id="settings" contentstyle="<%="height: "+(int)(scale*370)+"px;"%>"
     
    124133          size="40" maxlength="<%=BioMaterialList.MAX_NAME_LENGTH%>"></td>
    125134      </tr>
     135      <tr>
     136        <td class="prompt">Member type</td>
     137        <td>
     138          <select name="memberType">
     139            <option value="BIOSOURCE" <%=memberType == Item.BIOSOURCE ? "selected" : ""%>>Biosource
     140            <option value="SAMPLE" <%=memberType == Item.SAMPLE ? "selected" : ""%>>Sample
     141            <option value="EXTRACT" <%=memberType == Item.EXTRACT ? "selected" : ""%>>Extract
     142            <option value="LABELEDEXTRACT" <%=memberType == Item.LABELEDEXTRACT ? "selected" : ""%>>Labeled extract
     143          </select>
     144        </td>
     145      </tr>
     146      <%
     147      if (mergeLists)
     148      {
     149        %>
     150        <tr valign="top">
     151          <td class="prompt">Add members?</td>
     152          <td>
     153            <input type="radio" name="create" value=""><a
     154              href="javascript:checkRadio(document.forms['list'].create, '');"
     155              title="The new list will be empty"
     156              >No</a><br>
     157            <input type="radio" name="create" value="union" checked><a
     158              href="javascript:checkRadio(document.forms['list'].create, 'union');"
     159              title="The new list contains all items from the selected lists"
     160              >Union of selected lists</a> <base:icon image="set_operations/union_small.png" /><br>
     161            <input type="radio" name="create" value="intersection"><a
     162              href="javascript:checkRadio(document.forms['list'].create, 'intersection');"
     163              title="The new list contains only items that are present in ALL selected lists"
     164              >Intersection of selected lists</a> <base:icon image="set_operations/intersection_small.png" /><br>
     165            <input type="radio" name="create" value="count"><a
     166              href="javascript:checkRadio(document.forms['list'].create, 'count');"
     167              title="The new list contains only items that are present in some of selected lists"
     168              >Present in at least</a>
     169              <input type="text" class="text" name="minCount" size="2" maxlength="2"
     170                value="1"
     171                onkeypress="return Numbers.integerOnly(event)"
     172                onfocus="checkRadio(document.forms['list'].create, 'count');">
     173              of the selected lists (1-<%=numSelectedLists%>).
     174              <br>
     175           
     176          </td>
     177        </tr>
     178        <%
     179      }
     180      %>
    126181      <tr>
    127182        <td class="prompt">External ID</td>
  • trunk/www/biomaterials/lists/index.jsp

    r4681 r4705  
    119119    ItemContext cc = Base.getAndSetCurrentContext(sc, itemType, pageContext, defaultContext);
    120120    cc.setId(0);
    121     redirect = editPage;
     121    forward = editPage;
    122122  }
    123123  else if ("UpdateItem".equals(cmd))
     
    131131      Item memberType = Item.valueOf(request.getParameter("memberType"));
    132132      list = BioMaterialList.getNew(dc, memberType);
    133       message = "List created";
    134133      dc.saveItem(list);
     134
     135      // Add items from other lists?
     136      String create = Values.getStringOrNull(request.getParameter("create"));
     137      if (create != null)
     138      {
     139        List<BioMaterialList> lists = new ArrayList<BioMaterialList>(cc.getSelected().size());
     140        for (int listId : cc.getSelected())
     141        {
     142          lists.add(BioMaterialList.getById(dc, listId));
     143        }
     144        if ("union".equals(create))
     145        {
     146          list.addUnion(lists);
     147        }
     148        else if ("intersection".equals(create))
     149        {
     150          list.addIntersection(lists);
     151        }
     152        else if ("count".equals(create))
     153        {
     154          int minCount = Values.getInt(request.getParameter("minCount"), 1);
     155          list.addIfPresentIn(minCount, lists.size(), lists);
     156        }
     157      }
     158      message = "Biomaterial list created with " + list.getSize() + " item(s)";
    135159    }
    136160    else
     
    280304    redirect = "../../common/plugin/index.jsp?ID="+ID+"&cmd=SelectPlugin&item_type="+itemType.name()+"&context_type=ITEM&main_type=OTHER&title=Run+plugin";
    281305  }
     306  else if ("MergeItem".equals(cmd))
     307  {
     308    ItemContext cc = Base.getAndSetCurrentContext(sc, itemType, null, defaultContext);
     309    dc = sc.newDbControl();
     310    BioMaterialList bl = (BioMaterialList)cc.getObject("item");
     311    dc.reattachItem(bl);
     312   
     313    String mergeType = request.getParameter("mergeType");
     314    String sourceMerge = request.getParameter("sourceMerge");
     315   
     316    String[] sourceListIds = Values.getString(request.getParameter("sourceLists")).split(",");
     317    List<BioMaterialList> sourceLists = new ArrayList<BioMaterialList>(sourceListIds.length);
     318    for (int i = 0; i < sourceListIds.length; ++i)
     319    {
     320      int listId = Values.getInt(sourceListIds[i], -1);
     321      if (listId != -1) sourceLists.add(BioMaterialList.getById(dc, listId));
     322    }
     323   
     324    int numAdded = 0;
     325    int numRemoved = 0;
     326    if ("union".equals(mergeType))
     327    {
     328      if ("union".equals(sourceMerge))
     329      {
     330        numAdded = bl.addUnion(sourceLists);
     331      }
     332      else if ("intersection".equals(sourceMerge))
     333      {
     334        numAdded = bl.addIntersection(sourceLists);
     335      }
     336      message = numAdded + " items added to this list";
     337    }
     338    else if ("intersection".equals(mergeType))
     339    {
     340      if ("union".equals(sourceMerge))
     341      {
     342        numRemoved = bl.retainUnion(sourceLists);
     343      }
     344      else if ("intersection".equals(sourceMerge))
     345      {
     346        numRemoved = bl.retainIntersection(sourceLists);
     347      }
     348      message = numRemoved + " items removed from this list";
     349    }
     350    else if ("complement".equals(mergeType))
     351    {
     352      if ("union".equals(sourceMerge))
     353      {
     354        numRemoved = bl.removeUnion(sourceLists);
     355      }
     356      else if ("intersection".equals(sourceMerge))
     357      {
     358        numRemoved = bl.removeIntersection(sourceLists);
     359      }
     360      message = numRemoved + " items removed from this list";
     361    }
     362    dc.commit();
     363  }
    282364  else
    283365  {
  • trunk/www/biomaterials/lists/list_lists.jsp

    r4681 r4705  
    9797    function newItem()
    9898    {
    99       Main.viewOrEditItem('<%=ID%>', '<%=itemType.name()%>', 0, true);
     99      var controller = Main.getController('BIOMATERIALLIST');
     100      Table.submitToPopup(formId, 'NewItem', controller.width, controller.height);
    100101    }
    101102    function editItem(itemId)
     
    212213      />
    213214      <tbl:columndef
    214         id="size"
    215         property="size"
    216         datatype="int"
    217         title="Size"
     215        id="externalId"
     216        property="externalId"
     217        datatype="string"
     218        title="External ID"
    218219        sortable="true"
    219220        filterable="true"
  • trunk/www/biomaterials/lists/view_list.jsp

    r4681 r4705  
    140140      }
    141141    }
     142    function merge(mergeType)
     143    {
     144      Main.openPopup('merge.jsp?ID=<%=ID%>&item_id=<%=itemId%>&mergeType='+mergeType, 'Union', 600, 440);
     145    }
    142146    </script>
    143147  </base:head>
     
    189193        title="Set owner&hellip;"
    190194        tooltip="<%=setOwnerPermission ? "Change owner of this item" : "You do not have permission to change ownership of this item"%>"
     195      />
     196      <tbl:button
     197        visible="<%=writePermission%>"
     198        image="set_operations/union_small.png"
     199        onclick="merge('union')"
     200        title="Union&hellip;"
     201        tooltip="Add items from other lists to this list"
     202      />
     203      <tbl:button
     204        visible="<%=writePermission%>"
     205        image="set_operations/intersection_small.png"
     206        onclick="merge('intersection')"
     207        title="Intersection&hellip;"
     208        tooltip="Keep only items that are present in other lists"
     209      />
     210      <tbl:button
     211        visible="<%=writePermission%>"
     212        image="set_operations/complement_small.png"
     213        onclick="merge('complement')"
     214        title="Complement&hellip;"
     215        tooltip="Remove items found in other lists from this list"
    191216      />
    192217      <tbl:button
Note: See TracChangeset for help on using the changeset viewer.