Changeset 6091


Ignore:
Timestamp:
Aug 24, 2012, 2:23:25 PM (11 years ago)
Author:
Nicklas Nordborg
Message:

References #1707: Make it possible for a derived bioassay to have multiple physical bioassays as parents

Fixes problems with finding the correct parent items when inheriting annotations from parents. This should now consider all extracts encountered when moving upstreams from raw bioassay and derived bioassays.

Location:
trunk
Files:
2 added
6 edited

Legend:

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

    r6082 r6091  
    2727import net.sf.basedb.core.query.Restrictions;
    2828import net.sf.basedb.core.query.Hql;
    29 
     29import net.sf.basedb.util.collections.BasicItemToIdTransformer;
     30
     31import java.util.Collection;
     32import java.util.Collections;
    3033import java.util.Date;
    3134import java.util.Set;
     
    157160    throws BaseException
    158161  {
    159     return getAnnotatableParents(0, null);
    160   }
     162    return getAnnotatableParents(0, (Collection<Extract>)null);
     163  }
     164 
    161165  /**
    162166    Get the protocol from the creation event.
     
    273277    @since 3.0
    274278  */
     279  public Set<Annotatable> getAnnotatableParents(int position, Extract extract)
     280    throws BaseException
     281  {
     282    return getAnnotatableParents(position, extract == null ? null : Collections.singleton(extract));
     283  }
     284
     285  /**
     286    Get the extracts, possible on a specific assay position or only a specific
     287    extract, and the array slide.
     288    @param position If > 0 only include the extracts on that
     289      position in the bioassay (see {@link BioMaterialEventSource#getPosition()}.
     290      If <= 0 include all extracts.
     291    @param extract If not null, only include that extract (if present on the
     292      bioassay)
     293    @since 3.2
     294  */
    275295  @SuppressWarnings("unchecked")
    276   public Set<Annotatable> getAnnotatableParents(int position, Extract extract)
     296  public Set<Annotatable> getAnnotatableParents(int position, Collection<Extract> extracts)
    277297    throws BaseException
    278298  {
     
    292312        );
    293313      }
    294       if (extract != null)
     314      if (extracts != null && extracts.size() > 0)
    295315      {
    296         query.restrict(Restrictions.eq(Hql.property("id"), Expressions.integer(extract.getId())));
     316        query.restrict(Restrictions.in(Hql.property("id"), Expressions.parameter("extracts")));
     317        Set<Integer> extractIds = new HashSet<Integer>();
     318        new BasicItemToIdTransformer().transform(extracts, extractIds);
     319        query.setParameter("extracts", extractIds, Type.INT);
    297320      }
    298321      annotatable.addAll(query.list(getDbControl()));
     
    304327  }
    305328
     329 
    306330  /**
    307331    Get the event that represents the creation of this hybridization.
  • trunk/src/core/net/sf/basedb/util/AnnotationUtil.java

    r5749 r6091  
    2222package net.sf.basedb.util;
    2323
     24import java.util.Collection;
    2425import java.util.Collections;
     26import java.util.HashMap;
    2527import java.util.HashSet;
     28import java.util.LinkedHashSet;
    2629import java.util.LinkedList;
     30import java.util.Map;
    2731import java.util.Queue;
    2832import java.util.Set;
     
    4650public class AnnotationUtil
    4751{
     52  /**
     53    Create a new cache object that can be used with
     54    {@link #getAllAnnotatableParentItems(DbControl, Annotatable, Filter, Cache)}
     55    @since 3.2
     56  */
     57  public static Cache createCache()
     58  {
     59    return new Cache();
     60  }
    4861 
    4962  /**
     
    6073      which parents to include
    6174    @return A set containing the parent items
     75    @see #getAllAnnotatableParentItems(DbControl, Annotatable, Filter, Cache)
    6276  */
    6377  public static Set<Annotatable> getAllAnnotatableParentItems(DbControl dc,
    6478    Annotatable item, Filter<Annotatable> filter)
    6579  {
    66     Set<AnnotatableWrapper> processed = new HashSet<AnnotatableWrapper>();
     80    return getAllAnnotatableParentItems(dc, item, filter, null);
     81  }
     82
     83  /**
     84    Get all annotatable parent items for a given item. A {@link Filter}
     85    may be used to filter the returned collection. If a filter
     86    is specified only parent items for which the {@link Filter#evaluate(Object)}
     87    method returns true are included in the returned collection. Note
     88    that all parent items are loaded before the filter is evaluated
     89    and that the evaluation order is undefined. A cache may be used
     90    to improve performance if this method is called multiple times
     91    with different items that have overlapping parent trees.
     92   
     93    @param dc The DbControl to use for database access
     94    @param item The item to find the parents for
     95    @param filter An optional filter that can be used to filter
     96      which parents to include
     97    @param cache An optional cache object
     98    @return A set containing the parent items
     99    @see #createCache()
     100    @since 3.2
     101  */
     102  public static Set<Annotatable> getAllAnnotatableParentItems(DbControl dc,
     103    Annotatable item, Filter<Annotatable> filter, Cache cache)
     104  {
     105    Set<AnnotatableWrapper> processed = new LinkedHashSet<AnnotatableWrapper>();
    67106    Queue<AnnotatableWrapper> unprocessed = new LinkedList<AnnotatableWrapper>();
    68     unprocessed.add(new AnnotatableWrapper(item, null));
    69 
     107    unprocessed.add(new AnnotatableWrapper(item, cache));
     108 
    70109    // As long as we have unprocessed entries...
    71110    while (!unprocessed.isEmpty())
     
    81120   
    82121    // All parents are now loaded...
    83     Set<Annotatable> allParents = new HashSet<Annotatable>(processed.size());
     122    Set<Annotatable> allParents = new LinkedHashSet<Annotatable>(processed.size());
    84123    for (AnnotatableWrapper wrapper : processed)
    85124    {
     
    96135  /**
    97136    This wrapper class is needed because we need to keep
    98     track of the {@link RawBioAssay#getParentExtract()} property
     137    track of extracts linked with raw bioassays and derived bioassays
    99138    until we have loaded the Extracts of a Physical Bioassay.
    100139    <p>
    101     When we reach a {@link RawBioAssay} item, we remember the parent extract on
    102     that as we move up to DerivedBioAssaySet and PhysicalBioAssay.
    103     When the PhysicalBioAssay is reached we use the extract to call
    104     {@link PhysicalBioAssay#getAnnotatableParents(int, Extract)} so that we only
    105     get extracts that are linked with the correct raw bioassay.
     140    When we reach a {@link RawBioAssay} item or {@link DerivedBioAssay} item, we
     141    remember the extract on that as we move up towards PhysicalBioAssay.
     142    When the PhysicalBioAssay is reached we use the extracts to call
     143    {@link PhysicalBioAssay#getAnnotatableParents(int, Collection)}.
    106144  */
    107145  static class AnnotatableWrapper
     
    112150      <ul>
    113151      <li>If the item is a raw bioassay, {@link RawBioAssay#getParentExtract()}
    114       <li>If the item is a derived bioassay, extract if it is not null,
    115         otherwise {@link DerivedBioAssay#getExtract()}
    116       <li>If the item is a physical bioassay, the extract parameter
     152      <li>If the item is a derived bioassay, {@link DerivedBioAssay#getExtract()}
    117153      <li>null in all other cases.
    118     */
    119     private static Extract getExtract(Annotatable item, Extract extract)
     154      </ul>
     155    */
     156    private static Extract getExtract(Annotatable item)
    120157    {
    121158      Extract result = null;
     
    126163      else if (item instanceof DerivedBioAssay)
    127164      {
    128         if (extract != null)
     165        result = ((DerivedBioAssay)item).getExtract();
     166      }
     167      return result;
     168    }
     169   
     170    private final Annotatable item;
     171    private final AnnotatableWrapper chain;
     172    private final Cache cache;
     173    private boolean hasLoadedExtract;
     174    private Extract extract;
     175
     176    AnnotatableWrapper(Annotatable item, Cache cache)
     177    {
     178      this.item = item;
     179      this.chain = null;
     180      this.cache = cache;
     181    }
     182   
     183    AnnotatableWrapper(Annotatable item, AnnotatableWrapper chain)
     184    {
     185      this.item = item;
     186      this.chain = chain;
     187      this.cache = chain.cache;
     188    }
     189   
     190   
     191    /**
     192      The annotatable that we are wrapping.
     193    */
     194    Annotatable getAnnotatable()
     195    {
     196      return item;
     197    }
     198   
     199    Collection<Extract> loadExtracts(Collection<Extract> extractsInChain)
     200    {
     201      if (chain != null) chain.loadExtracts(extractsInChain);
     202      if (!hasLoadedExtract)
     203      {
     204        extract = getExtract(item);
     205        hasLoadedExtract = true;
     206      }
     207      if (extract != null) extractsInChain.add(extract);
     208      return extractsInChain;
     209    }
     210   
     211    /**
     212      Get all annotatable parents wrapped inside AnnotatableWrapper:s
     213    */
     214    Set<AnnotatableWrapper> getAnnotatableParentWrappers()
     215      throws BaseException
     216    {
     217      Set<Annotatable> parents = null;
     218      Set<AnnotatableWrapper> wrappedParents = Collections.emptySet();
     219     
     220      if (cache != null && cache.contains(item))
     221      {
     222        wrappedParents = cache.get(item);
     223      }
     224      else
     225      {
     226        boolean useCache = true;
     227        if (item instanceof PhysicalBioAssay)
    129228        {
    130           result = extract;
     229          Collection<Extract> extractsInChain = loadExtracts(new HashSet<Extract>());
     230          parents = ((PhysicalBioAssay)item).getAnnotatableParents(0, extractsInChain);
     231          useCache = false;
    131232        }
    132233        else
    133234        {
    134           result = ((DerivedBioAssay)item).getExtract();
     235          parents = item.getAnnotatableParents();
    135236        }
    136       }
    137       else if (item instanceof PhysicalBioAssay)
    138       {
    139         result = extract;
    140       }
    141       return result;
    142     }
    143    
    144     private final Annotatable item;
    145     private final Extract extract;
    146 
    147     AnnotatableWrapper(Annotatable item, Extract extract)
    148     {
    149       this.item = item;
    150       this.extract = getExtract(item, extract);
    151     }
    152    
    153     /**
    154       The annotatable that we are wrapping.
    155     */
    156     Annotatable getAnnotatable()
    157     {
    158       return item;
    159     }
    160    
    161     /**
    162       Get all annotatable parents wrapped inside AnnotatableWrapper:s
    163     */
    164     Set<AnnotatableWrapper> getAnnotatableParentWrappers()
    165       throws BaseException
    166     {
    167       Set<Annotatable> parents = null;
    168       Set<AnnotatableWrapper> wrappedParents = Collections.emptySet();
    169       if (item instanceof PhysicalBioAssay)
    170       {
    171         parents = ((PhysicalBioAssay)item).getAnnotatableParents(0, extract);
    172       }
    173       else
    174       {
    175         parents = item.getAnnotatableParents();
    176       }
    177       if (parents != null)
    178       {
    179         wrappedParents = new HashSet<AnnotatableWrapper>(parents.size());
    180         for (Annotatable parent : parents)
     237        if (parents != null)
    181238        {
    182           wrappedParents.add(new AnnotatableWrapper(parent, extract));
     239          wrappedParents = new HashSet<AnnotatableWrapper>(parents.size());
     240          for (Annotatable parent : parents)
     241          {
     242            wrappedParents.add(new AnnotatableWrapper(parent, this));
     243          }
    183244        }
     245        if (cache != null && useCache) cache.put(item, wrappedParents);
    184246      }
    185247      return wrappedParents;
     
    188250    /**
    189251      A wrapper is equal to another if they references the same item
    190       and extract.
     252      and chain of wrappers.
    191253    */
    192254    @Override
     
    196258      if (o == null || o.getClass() != this.getClass()) return false;
    197259      AnnotatableWrapper other = (AnnotatableWrapper)o;
    198       return this.item.equals(other.item) && EqualsHelper.equals(this.extract, other.extract);
     260      return this.item.equals(other.item) && EqualsHelper.equals(this.chain, other.chain);
    199261    }
    200262
     
    202264    public int hashCode()
    203265    {
    204       return item.hashCode() + EqualsHelper.hashCode(extract);
    205     }
     266      return item.hashCode() + EqualsHelper.hashCode(chain);
     267    }
     268  }
     269 
     270  public static class Cache
     271  {
     272    private final Map<Annotatable, Set<AnnotatableWrapper>> cmap;
     273   
     274    Cache()
     275    {
     276      this.cmap = new HashMap<Annotatable, Set<AnnotatableWrapper>>();
     277    }
     278   
     279    boolean contains(Annotatable item)
     280    {
     281      return cmap.containsKey(item);
     282    }
     283   
     284    Set<AnnotatableWrapper> get(Annotatable item)
     285    {
     286      return cmap.get(item);
     287    }
     288   
     289    void put(Annotatable item, Set<AnnotatableWrapper> parents)
     290    {
     291      cmap.put(item, parents);
     292    }
     293   
    206294  }
    207295}
  • trunk/src/core/net/sf/basedb/util/overview/OverviewUtil.java

    r6088 r6091  
    3838import net.sf.basedb.core.BasicItem;
    3939import net.sf.basedb.core.DbControl;
    40 import net.sf.basedb.core.DerivedBioAssay;
    41 import net.sf.basedb.core.Extract;
    4240import net.sf.basedb.core.ItemSubtype;
    43 import net.sf.basedb.core.PermissionDeniedException;
    4441import net.sf.basedb.core.Presets;
    45 import net.sf.basedb.core.PhysicalBioAssay;
    4642import net.sf.basedb.core.Item;
    4743import net.sf.basedb.core.ItemQuery;
     
    4945import net.sf.basedb.core.Project;
    5046import net.sf.basedb.core.SessionControl;
    51 import net.sf.basedb.core.RawBioAssay;
    5247import net.sf.basedb.core.Subtypable;
    5348import net.sf.basedb.core.Type;
     
    5550import net.sf.basedb.core.query.Hql;
    5651import net.sf.basedb.core.query.Restrictions;
     52import net.sf.basedb.util.AnnotationUtil;
     53import net.sf.basedb.util.AnnotationUtil.Cache;
    5754import net.sf.basedb.util.extensions.ClientContext;
    5855import net.sf.basedb.util.extensions.ExtensionsInvoker;
     
    409406  public static Set<Annotatable> getAnnotatableParents(DbControl dc, OverviewContext context, Annotatable item)
    410407  {
    411     return getAnnotatableParents(dc, context, item, item);
    412   }
    413  
    414   /**
    415     The internal implementation needs to keep track of the special case when we
    416     start with raw bioassay or derived bioassay as the root item. This is because when
    417     we reach the associated physical bioassay we should only load the extract
    418     that is associated with the raw/derived bioassay
    419   */
    420   @SuppressWarnings("unchecked")
    421   private static Set<Annotatable> getAnnotatableParents(DbControl dc, OverviewContext context, Annotatable item, Annotatable root)
    422   {
    423     String cacheKey = "annotatable.parent." + item.getType().name() + "." + item.getId();
    424 
    425     // Special case when starting with a raw/derived bioassay with an extract
    426     // since the extract is the
    427     Extract extract = null;
    428     PhysicalBioAssay bioAssay = null;
    429     try
    430     {
    431       if (root instanceof RawBioAssay)
    432       {
    433         RawBioAssay rba = (RawBioAssay)root;
    434         extract = rba.getParentExtract();
    435       }
    436       else if (root instanceof DerivedBioAssay)
    437       {
    438         DerivedBioAssay dba = (DerivedBioAssay)root;
    439         extract = dba.getExtract();
    440       }
    441     }
    442     catch (PermissionDeniedException ex)
    443     {}
    444    
    445     if (extract != null)
    446     {
    447       if (item instanceof DerivedBioAssay)
    448       {
    449         cacheKey += "#" + extract.getId();
    450       }
    451       else if (item instanceof PhysicalBioAssay)
    452       {
    453         bioAssay = (PhysicalBioAssay)item;
    454         cacheKey += "#" + extract.getId();
    455       }
    456     }
    457  
    458     Set<Annotatable> parents = (Set<Annotatable>)context.getCachedObject(cacheKey);
    459     if (parents == null)
    460     {
    461       parents = new HashSet<Annotatable>();
    462       context.setCachedObject(cacheKey, parents);
    463       Set<? extends Annotatable> temp = bioAssay != null ?
    464           bioAssay.getAnnotatableParents(0, extract) : item.getAnnotatableParents();
    465       if (temp != null)
    466       {
    467         for (Annotatable a : temp)
    468         {
    469           parents.add(a);
    470           parents.addAll(getAnnotatableParents(dc, context, a, root));
    471         }
    472       }
    473     }
    474     return parents;
    475   }
     408    Cache cache = (Cache)context.getCachedObject("annotatable.parent.cache");
     409    if (cache == null)
     410    {
     411      cache = AnnotationUtil.createCache();
     412      context.setCachedObject("annotatable.parent.cache", cache);
     413    }
     414    return AnnotationUtil.getAllAnnotatableParentItems(dc, item, null, cache);
     415  }
     416
    476417 
    477418}
  • trunk/src/core/net/sf/basedb/util/overview/loader/ExtractLoader.java

    r6090 r6091  
    2323
    2424import java.util.HashSet;
     25import java.util.Iterator;
    2526import java.util.List;
    2627import java.util.Set;
     
    5253import net.sf.basedb.util.overview.Node;
    5354import net.sf.basedb.util.overview.node.NodeFactory;
     55import net.sf.basedb.util.query.MultiQueryIterator;
    5456
    5557/**
     
    308310    are the extracts that has been used on a bioassay.
    309311  */
     312  @SuppressWarnings("unchecked")
    310313  private Node createReverseNode(PhysicalBioAssay bioAssay, DbControl dc, OverviewContext context, Node bioAssayNode)
    311314  {
     
    314317
    315318    ItemQuery<Extract> query = context.initQuery(bioAssay.getExtracts(0), "name");
     319    ItemQuery<Extract> extraQuery = null;
    316320
    317321    // If we have followed this path from derived bioassays that has specified an
    318322    // extract we should only load the same extracts when following the path upstreams
     323    // We look for both
    319324    Set<Integer> extractIds = getExtractChain(bioAssayNode);
    320325    if (extractIds.size() > 0)
     
    324329        );
    325330      query.setParameter("extracts", extractIds, Type.INT);
    326     }
    327     ItemResultIterator<Extract> it = query.iterate(dc);
     331
     332      extraQuery = context.initQuery(bioAssay.getExtracts(0), "name");
     333      extraQuery.join(Hql.leftJoin("creationEvent", "cevt"));
     334      extraQuery.join(Hql.leftJoin("cevt", "sources", "sss", null, false));
     335     
     336      extraQuery.restrict(
     337        Restrictions.in(Hql.property("sss", "bioMaterial"), Expressions.parameter("extracts"))
     338        );
     339      extraQuery.setParameter("extracts", extractIds, Type.INT);
     340    }
     341    Iterator<Extract> it = MultiQueryIterator.get(dc, query, extraQuery);
    328342    while (it.hasNext())
    329343    {
  • trunk/www/common/annotations/inherit.jsp

    r6037 r6091  
    2828  @version 2.0
    2929--%>
    30 <%@page import="net.sf.basedb.core.Subtypable"%>
    3130<%@ page pageEncoding="UTF-8" session="false"
    3231  import="net.sf.basedb.core.SessionControl"
     
    5049  import="net.sf.basedb.core.AnnotationType"
    5150  import="net.sf.basedb.core.PermissionDeniedException"
     51  import="net.sf.basedb.util.AnnotationUtil"
     52  import="net.sf.basedb.core.Subtypable"
    5253  import="net.sf.basedb.core.query.Orders"
    5354  import="net.sf.basedb.core.query.Hql"
     
    6768<%@ taglib prefix="base" uri="/WEB-INF/base.tld" %>
    6869<%!
    69 private void loadParents(Set<AnnotationSet> parentAnnotations, Set<Annotatable> parentItems, Annotatable current, Annotatable root)
     70private void loadParents(DbControl dc, Set<AnnotationSet> parentAnnotations, Set<Annotatable> parentItems, Annotatable current)
    7071{
     72  Set<Annotatable> parents = AnnotationUtil.getAllAnnotatableParentItems(dc, current, null);
     73  for (Annotatable parent : parents)
     74  {
     75    if (parent != null && parentItems.add(parent))
     76    {
     77      if (parent.hasPermission(Permission.USE) && parent.isAnnotated())
     78      {
     79        parentAnnotations.add(parent.getAnnotationSet());
     80      }
     81    }
     82  }
     83  /*
    7184  Set<Annotatable> parents = null;
    7285  if (current instanceof PhysicalBioAssay)
     
    105118    }
    106119  }
     120  */
    107121}
    108122
     
    205219  {
    206220    // Get all annotated parents and their annotation sets
    207     loadParents(parentAnnotations, parentItems, item, item);
     221    loadParents(dc, parentAnnotations, parentItems, item);
    208222  }
    209223  if (standalone)
     
    237251              parentAnnotations.add(parentItem.getAnnotationSet());
    238252            }
    239             loadParents(parentAnnotations, parentItems, parentItem, item);
     253            loadParents(dc, parentAnnotations, parentItems, parentItem);
    240254          }
    241255        }
  • trunk/www/views/derivedbioassays/edit_bioassay.jsp

    r6085 r6091  
    341341     
    342342      var parents = new Array();
    343       if (frm.isRoot[0].checked)
     343      if (frm.physicalBioassays && (!frm.isRoot || frm.isRoot[0].checked))
    344344      {
    345345        var ids = Link.getListIds(frm.physicalBioAssays, 'P');
     
    349349        }
    350350      }
    351       else
     351      else if (frm.parents && (!frm.isRoot || frm.isRoot[1].checked))
    352352      {
    353353        var ids = Link.getListIds(frm.parents, 'D');
Note: See TracChangeset for help on using the changeset viewer.