src/core/net/sf/basedb/util/overview/loader/ExtractLoader.java

Code
Comments
Other
Rev Date Author Line
4740 05 Feb 09 nicklas 1 /**
4740 05 Feb 09 nicklas 2   $Id$
4740 05 Feb 09 nicklas 3
4740 05 Feb 09 nicklas 4   Copyright (C) 2008 Nicklas Nordborg
4740 05 Feb 09 nicklas 5
4740 05 Feb 09 nicklas 6   This file is part of BASE - BioArray Software Environment.
4740 05 Feb 09 nicklas 7   Available at http://base.thep.lu.se/
4740 05 Feb 09 nicklas 8
4740 05 Feb 09 nicklas 9   BASE is free software; you can redistribute it and/or
4740 05 Feb 09 nicklas 10   modify it under the terms of the GNU General Public License
4740 05 Feb 09 nicklas 11   as published by the Free Software Foundation; either version 3
4740 05 Feb 09 nicklas 12   of the License, or (at your option) any later version.
4740 05 Feb 09 nicklas 13
4740 05 Feb 09 nicklas 14   BASE is distributed in the hope that it will be useful,
4740 05 Feb 09 nicklas 15   but WITHOUT ANY WARRANTY; without even the implied warranty of
4740 05 Feb 09 nicklas 16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
4740 05 Feb 09 nicklas 17   GNU General Public License for more details.
4740 05 Feb 09 nicklas 18
4740 05 Feb 09 nicklas 19   You should have received a copy of the GNU General Public License
4740 05 Feb 09 nicklas 20   along with BASE. If not, see <http://www.gnu.org/licenses/>.
4740 05 Feb 09 nicklas 21 */
4740 05 Feb 09 nicklas 22 package net.sf.basedb.util.overview.loader;
4740 05 Feb 09 nicklas 23
6090 22 Aug 12 nicklas 24 import java.util.HashSet;
6091 24 Aug 12 nicklas 25 import java.util.Iterator;
6090 22 Aug 12 nicklas 26 import java.util.List;
6090 22 Aug 12 nicklas 27 import java.util.Set;
6090 22 Aug 12 nicklas 28
4740 05 Feb 09 nicklas 29 import net.sf.basedb.core.DbControl;
5653 13 Jun 11 nicklas 30 import net.sf.basedb.core.DerivedBioAssay;
4740 05 Feb 09 nicklas 31 import net.sf.basedb.core.Extract;
5985 24 Feb 12 nicklas 32 import net.sf.basedb.core.ItemSubtype;
5653 13 Jun 11 nicklas 33 import net.sf.basedb.core.PermissionDeniedException;
5642 26 May 11 nicklas 34 import net.sf.basedb.core.PhysicalBioAssay;
4740 05 Feb 09 nicklas 35 import net.sf.basedb.core.Item;
4740 05 Feb 09 nicklas 36 import net.sf.basedb.core.ItemQuery;
4740 05 Feb 09 nicklas 37 import net.sf.basedb.core.ItemResultIterator;
5748 19 Sep 11 nicklas 38 import net.sf.basedb.core.RawBioAssay;
6959 01 Oct 15 nicklas 39 import net.sf.basedb.core.RootRawBioAssay;
4740 05 Feb 09 nicklas 40 import net.sf.basedb.core.Sample;
6090 22 Aug 12 nicklas 41 import net.sf.basedb.core.Type;
5748 19 Sep 11 nicklas 42 import net.sf.basedb.core.query.Expressions;
5748 19 Sep 11 nicklas 43 import net.sf.basedb.core.query.Hql;
5748 19 Sep 11 nicklas 44 import net.sf.basedb.core.query.Restrictions;
6799 25 Mar 15 nicklas 45 import net.sf.basedb.util.listable.ExtractToChildExtractTransformer;
6799 25 Mar 15 nicklas 46 import net.sf.basedb.util.listable.SourceItemTransformer;
6799 25 Mar 15 nicklas 47 import net.sf.basedb.util.listable.TransformContext;
4740 05 Feb 09 nicklas 48 import net.sf.basedb.util.overview.Fix;
5748 19 Sep 11 nicklas 49 import net.sf.basedb.util.overview.NodeAttribute;
4740 05 Feb 09 nicklas 50 import net.sf.basedb.util.overview.OverviewContext;
4740 05 Feb 09 nicklas 51 import net.sf.basedb.util.overview.OverviewUtil;
4740 05 Feb 09 nicklas 52 import net.sf.basedb.util.overview.Validator;
5748 19 Sep 11 nicklas 53 import net.sf.basedb.util.overview.filter.HasAttributeFilter;
4740 05 Feb 09 nicklas 54 import net.sf.basedb.util.overview.node.ChildNodeDirection;
5651 08 Jun 11 nicklas 55 import net.sf.basedb.util.overview.node.ExtractNameGenerator;
4740 05 Feb 09 nicklas 56 import net.sf.basedb.util.overview.Node;
4740 05 Feb 09 nicklas 57 import net.sf.basedb.util.overview.node.NodeFactory;
4740 05 Feb 09 nicklas 58
4740 05 Feb 09 nicklas 59 /**
4740 05 Feb 09 nicklas 60   Node loader implementation for extracts. The forward-loading
4740 05 Feb 09 nicklas 61   direction goes from {@link Sample}:s -&gt; {@link Extract}:s -&gt; 
5642 26 May 11 nicklas 62   {@link PhysicalBioAssay}:s. The reverse-loading direction is the opposite 
4740 05 Feb 09 nicklas 63   direction. In both cases we also need to consider pooled extracts.
4740 05 Feb 09 nicklas 64
4740 05 Feb 09 nicklas 65   @author Nicklas
4740 05 Feb 09 nicklas 66   @version 2.10
4740 05 Feb 09 nicklas 67   @base.modified $Date$
4740 05 Feb 09 nicklas 68 */
4740 05 Feb 09 nicklas 69 public class ExtractLoader
4740 05 Feb 09 nicklas 70   extends BasicItemNodeLoader<Extract>
4740 05 Feb 09 nicklas 71 {
4740 05 Feb 09 nicklas 72
4740 05 Feb 09 nicklas 73   public ExtractLoader()
4740 05 Feb 09 nicklas 74   {
4740 05 Feb 09 nicklas 75     super(Item.EXTRACT, ALLOW_ROOT_NODE, 
5651 08 Jun 11 nicklas 76         new ExtractNameGenerator("extract", "Extract"));
4740 05 Feb 09 nicklas 77   }
4740 05 Feb 09 nicklas 78   
4740 05 Feb 09 nicklas 79   /*
4740 05 Feb 09 nicklas 80     From the NodeLoader interface
4740 05 Feb 09 nicklas 81     ------------------------------
4740 05 Feb 09 nicklas 82   */
4740 05 Feb 09 nicklas 83   /**
4740 05 Feb 09 nicklas 84     Create forward-loading extract nodes from a given parent sample
5641 25 May 11 nicklas 85     or extract. In both cases the returned node is a folder-type node
6043 03 Apr 12 nicklas 86     that contains the child extracts. It can also create all-loading
6043 03 Apr 12 nicklas 87     node from a biomaterial list for the member samples.
6043 03 Apr 12 nicklas 88     @return The folder node for the extracts (or null if used with a list)
4740 05 Feb 09 nicklas 89   */
4740 05 Feb 09 nicklas 90   @Override
4740 05 Feb 09 nicklas 91   public Node createForwardNode(DbControl dc, OverviewContext context, Node parentNode)
4740 05 Feb 09 nicklas 92   {
4740 05 Feb 09 nicklas 93     Node returnNode = null;
4740 05 Feb 09 nicklas 94     Item parentType = parentNode.getItemType();
4740 05 Feb 09 nicklas 95     if (parentType == Item.SAMPLE)
4740 05 Feb 09 nicklas 96     {
5985 24 Feb 12 nicklas 97       returnNode = createForwardNode((Sample)parentNode.getItem(dc), dc, context, parentNode, false);
4740 05 Feb 09 nicklas 98     }
4740 05 Feb 09 nicklas 99     else if (parentType == Item.EXTRACT)
4740 05 Feb 09 nicklas 100     {
5985 24 Feb 12 nicklas 101       returnNode = createForwardNode((Extract)parentNode.getItem(dc), dc, context, parentNode, false);
4740 05 Feb 09 nicklas 102     }
6755 20 Feb 15 nicklas 103     else if (parentType == Item.ITEMLIST)
6755 20 Feb 15 nicklas 104     {
6755 20 Feb 15 nicklas 105       ItemListLoader.loadMemberNodes(this, dc, context, parentNode);
6755 20 Feb 15 nicklas 106     }
4740 05 Feb 09 nicklas 107     return returnNode;
4740 05 Feb 09 nicklas 108   }
4740 05 Feb 09 nicklas 109   
4740 05 Feb 09 nicklas 110   /**
5748 19 Sep 11 nicklas 111     The parent node can be one of:
5748 19 Sep 11 nicklas 112     <ul>
5748 19 Sep 11 nicklas 113     <li>Physical bioassay: Load the source extract(s) and return a folder-type node
5748 19 Sep 11 nicklas 114     <li>Extract: Load the parent extracts and return either a folder-type or
5748 19 Sep 11 nicklas 115       item-type node depending on the number of parents
5748 19 Sep 11 nicklas 116     <li>Raw bioassay: Load the parent extract and return an item-type node
5748 19 Sep 11 nicklas 117     <li>Derived bioassay: Load the parent extract and return an item-type node
5748 19 Sep 11 nicklas 118     </ul>
4740 05 Feb 09 nicklas 119     @return A folder-type or item-type node
4740 05 Feb 09 nicklas 120   */
4740 05 Feb 09 nicklas 121   @Override
4740 05 Feb 09 nicklas 122   public Node createReverseNode(DbControl dc, OverviewContext context, Node parentNode)
4740 05 Feb 09 nicklas 123   {
4740 05 Feb 09 nicklas 124     Node returnNode = null;
4740 05 Feb 09 nicklas 125     Item parentItem = parentNode.getItemType();
5642 26 May 11 nicklas 126     if (parentItem == Item.PHYSICALBIOASSAY)
4740 05 Feb 09 nicklas 127     {
5642 26 May 11 nicklas 128       returnNode = createReverseNode((PhysicalBioAssay)parentNode.getItem(dc), dc, context, parentNode);
4740 05 Feb 09 nicklas 129     }
4740 05 Feb 09 nicklas 130     else if (parentItem == Item.EXTRACT)
4740 05 Feb 09 nicklas 131     {
5663 22 Jun 11 nicklas 132       Extract e = (Extract)parentNode.getItem(dc);
5663 22 Jun 11 nicklas 133       if (e.hasSingleParent())
5663 22 Jun 11 nicklas 134       {
5807 14 Oct 11 nicklas 135         // We already know that we have an extract as parent, since otherwise we would be in SampleLoader
5807 14 Oct 11 nicklas 136         returnNode = createSingleParentReverseNode(e, dc, context, parentNode);
5663 22 Jun 11 nicklas 137       }
5663 22 Jun 11 nicklas 138       else
5663 22 Jun 11 nicklas 139       {
5663 22 Jun 11 nicklas 140         returnNode = createPooledReverseNode(e, dc, context, parentNode);
5663 22 Jun 11 nicklas 141       }
4740 05 Feb 09 nicklas 142     }
5653 13 Jun 11 nicklas 143     else if (parentItem == Item.DERIVEDBIOASSAY)
5653 13 Jun 11 nicklas 144     {
5653 13 Jun 11 nicklas 145       returnNode = createReverseNode((DerivedBioAssay)parentNode.getItem(dc), dc, context, parentNode);
5653 13 Jun 11 nicklas 146     }
5748 19 Sep 11 nicklas 147     else if (parentItem == Item.RAWBIOASSAY)
5748 19 Sep 11 nicklas 148     {
5748 19 Sep 11 nicklas 149       returnNode = createReverseNode((RawBioAssay)parentNode.getItem(dc), dc, context, parentNode);
5748 19 Sep 11 nicklas 150     }
6959 01 Oct 15 nicklas 151     else if (parentItem == Item.ROOTRAWBIOASSAY)
6959 01 Oct 15 nicklas 152     {
6959 01 Oct 15 nicklas 153       returnNode = createReverseNode(((RootRawBioAssay)parentNode.getItem(dc)).getRawBioAssay(), dc, context, parentNode);
6959 01 Oct 15 nicklas 154     }
4740 05 Feb 09 nicklas 155     return returnNode;
4740 05 Feb 09 nicklas 156   }
5985 24 Feb 12 nicklas 157   
5985 24 Feb 12 nicklas 158   /**
5985 24 Feb 12 nicklas 159     A property node is created when moving in the reverse direction so that we
5985 24 Feb 12 nicklas 160     can load child extracts+physical bioassays with the {@link ItemSubtype#getPushAnnotations()} 
5985 24 Feb 12 nicklas 161     flag set. The parent node should be a sample or extract node.
5985 24 Feb 12 nicklas 162     @since 3.1
5985 24 Feb 12 nicklas 163   */
5985 24 Feb 12 nicklas 164   @Override
5985 24 Feb 12 nicklas 165   public Node createPropertyNode(DbControl dc, OverviewContext context, Node parentNode) 
5985 24 Feb 12 nicklas 166   {
5985 24 Feb 12 nicklas 167     Node returnNode = null;
5985 24 Feb 12 nicklas 168     Item parentType = parentNode.getItemType();
5985 24 Feb 12 nicklas 169     if (parentType == Item.SAMPLE)
5985 24 Feb 12 nicklas 170     {
5985 24 Feb 12 nicklas 171       returnNode = createForwardNode((Sample)parentNode.getItem(dc), dc, context, parentNode, true);
5985 24 Feb 12 nicklas 172     }
5985 24 Feb 12 nicklas 173     else if (parentType == Item.EXTRACT)
5985 24 Feb 12 nicklas 174     {
5985 24 Feb 12 nicklas 175       returnNode = createForwardNode((Extract)parentNode.getItem(dc), dc, context, parentNode, true);
5985 24 Feb 12 nicklas 176     }
5985 24 Feb 12 nicklas 177     return returnNode;
5985 24 Feb 12 nicklas 178   }
4740 05 Feb 09 nicklas 179   // --------------------------------
4740 05 Feb 09 nicklas 180   /*
4740 05 Feb 09 nicklas 181     From the AbstractNodeLoader class
4740 05 Feb 09 nicklas 182     ----------------------------------
4740 05 Feb 09 nicklas 183   */
4740 05 Feb 09 nicklas 184   /**
4740 05 Feb 09 nicklas 185     Loads property nodes of an extract. 
4740 05 Feb 09 nicklas 186     <ul>
4740 05 Feb 09 nicklas 187     <li>Annotations: {@link AnnotationLoader#createPropertyNode(DbControl, OverviewContext, Node)}
6041 02 Apr 12 nicklas 188     <li>Bioplate/well: {@link BioPlateLoader#createPropertyNode(DbControl, OverviewContext, Node)}
4740 05 Feb 09 nicklas 189     <li>Protocol: {@link ProtocolLoader#createPropertyNode(DbControl, OverviewContext, Node)}
7004 09 Nov 15 nicklas 190     <li>Kit: {@link KitLoader#createPropertyNode(DbControl, OverviewContext, Node)}
5651 08 Jun 11 nicklas 191     <li>Hardware: {@link HardwareLoader#createPropertyNode(DbControl, OverviewContext, Node)}
5748 19 Sep 11 nicklas 192     <li>Tag: {@link TagLoader#createPropertyNode(DbControl, OverviewContext, Node)}
4740 05 Feb 09 nicklas 193     </ul>
4740 05 Feb 09 nicklas 194   */
4740 05 Feb 09 nicklas 195   @Override
4740 05 Feb 09 nicklas 196   protected void loadPropertyChildNodes(DbControl dc, OverviewContext context, Node extractNode)
4740 05 Feb 09 nicklas 197   {
6042 03 Apr 12 nicklas 198     Node parentNode = extractNode.getParent();
4740 05 Feb 09 nicklas 199     getNodeLoader(context, Item.ANNOTATION).createPropertyNode(dc, context, extractNode);
5651 08 Jun 11 nicklas 200     getNodeLoader(context, Item.TAG).createPropertyNode(dc, context, extractNode);
6042 03 Apr 12 nicklas 201     if (parentNode == null || parentNode.getItemType() != Item.BIOPLATE)
6042 03 Apr 12 nicklas 202     {
6042 03 Apr 12 nicklas 203       // Do not load the bioplate if we just started from it
6042 03 Apr 12 nicklas 204       getNodeLoader(context, Item.BIOPLATE).createPropertyNode(dc, context, extractNode);
6042 03 Apr 12 nicklas 205     }
4740 05 Feb 09 nicklas 206     getNodeLoader(context, Item.PROTOCOL).createPropertyNode(dc, context, extractNode);
7004 09 Nov 15 nicklas 207     getNodeLoader(context, Item.KIT).createPropertyNode(dc, context, extractNode);
5651 08 Jun 11 nicklas 208     getNodeLoader(context, Item.HARDWARE).createPropertyNode(dc, context, extractNode);
5500 18 Nov 10 nicklas 209     getNodeLoader(context, Item.ANYTOANY).createPropertyNode(dc, context, extractNode);
4740 05 Feb 09 nicklas 210   }
4740 05 Feb 09 nicklas 211
4740 05 Feb 09 nicklas 212   /**
5748 19 Sep 11 nicklas 213     Loads the child extracts and physical bioassays that has been created from
7301 01 Mar 17 nicklas 214     this extract. Derived and raw bioassays linking to this parent extract and doesn't have
7301 01 Mar 17 nicklas 215     a parent derived bioassay are also loaded.
4740 05 Feb 09 nicklas 216     @see ExtractLoader#createForwardNode(DbControl, OverviewContext, Node)
5651 08 Jun 11 nicklas 217     @see PhysicalBioAssayLoader#createForwardNode(DbControl, OverviewContext, Node)
7301 01 Mar 17 nicklas 218     @see DerivedBioAssayLoader#createForwardNode(DbControl, OverviewContext, Node)
7301 01 Mar 17 nicklas 219     @see RawBioAssayLoader#createForwardNode(DbControl, OverviewContext, Node)
4740 05 Feb 09 nicklas 220   */
4740 05 Feb 09 nicklas 221   @Override
4740 05 Feb 09 nicklas 222   protected void loadForwardChildNodes(DbControl dc, OverviewContext context, Node extractNode)
4740 05 Feb 09 nicklas 223   {
5642 26 May 11 nicklas 224     getNodeLoader(context, Item.PHYSICALBIOASSAY).createForwardNode(dc, context, extractNode);
4740 05 Feb 09 nicklas 225     getNodeLoader(context, Item.EXTRACT).createForwardNode(dc, context, extractNode);
7301 01 Mar 17 nicklas 226     getNodeLoader(context, Item.DERIVEDBIOASSAY).createForwardNode(dc, context, extractNode);
5748 19 Sep 11 nicklas 227     getNodeLoader(context, Item.RAWBIOASSAY).createForwardNode(dc, context, extractNode);
4740 05 Feb 09 nicklas 228   }
4740 05 Feb 09 nicklas 229   
4740 05 Feb 09 nicklas 230   /**
5985 24 Feb 12 nicklas 231     Load either the parent sample or extract(s) and child extracts+physical bioassays
5985 24 Feb 12 nicklas 232     with a subtype that has {@link ItemSubtype#getPushAnnotations()} flag set.
4740 05 Feb 09 nicklas 233     @see ExtractLoader#createReverseNode(DbControl, OverviewContext, Node)
4740 05 Feb 09 nicklas 234     @see SampleLoader#createReverseNode(DbControl, OverviewContext, Node)
4740 05 Feb 09 nicklas 235   */
4740 05 Feb 09 nicklas 236   @Override
4740 05 Feb 09 nicklas 237   protected void loadReverseChildNodes(DbControl dc, OverviewContext context, Node extractNode)
4740 05 Feb 09 nicklas 238   {
5748 19 Sep 11 nicklas 239     Extract extract = (Extract)extractNode.getItem(dc);
5663 22 Jun 11 nicklas 240     if (extract.getParentType() == Item.EXTRACT)
4740 05 Feb 09 nicklas 241     {
4740 05 Feb 09 nicklas 242       getNodeLoader(context, Item.EXTRACT).createReverseNode(dc, context, extractNode);
4740 05 Feb 09 nicklas 243     }
4740 05 Feb 09 nicklas 244     else
4740 05 Feb 09 nicklas 245     {
4740 05 Feb 09 nicklas 246       getNodeLoader(context, Item.SAMPLE).createReverseNode(dc, context, extractNode);
4740 05 Feb 09 nicklas 247     }
5985 24 Feb 12 nicklas 248     if (extractNode.getChildNodeDirection() == ChildNodeDirection.REVERSE)
5985 24 Feb 12 nicklas 249     {
5985 24 Feb 12 nicklas 250       // Only if we are moving in the reverse direction (eg. not when the extract is a root node)
5985 24 Feb 12 nicklas 251       getNodeLoader(context, Item.EXTRACT).createPropertyNode(dc, context, extractNode);
5985 24 Feb 12 nicklas 252       getNodeLoader(context, Item.PHYSICALBIOASSAY).createPropertyNode(dc, context, extractNode);
5985 24 Feb 12 nicklas 253     }
4740 05 Feb 09 nicklas 254   }
4740 05 Feb 09 nicklas 255   // ---------------------------------------
4740 05 Feb 09 nicklas 256   /**
4740 05 Feb 09 nicklas 257     Create reverse-loading extract nodes of a pooled extract. Eg. the child nodes
4740 05 Feb 09 nicklas 258     are the source extracts that was pooled to create the given product.
4740 05 Feb 09 nicklas 259   */
5663 22 Jun 11 nicklas 260   private Node createPooledReverseNode(Extract product, DbControl dc, OverviewContext context, Node parentNode)
4740 05 Feb 09 nicklas 261   {
4740 05 Feb 09 nicklas 262     NodeFactory<Extract> nf = getNodeFactory(dc, context);
4740 05 Feb 09 nicklas 263     Node folderNode = null;
7605 26 Feb 19 nicklas 264     ItemQuery<Extract> query = context.initQuery(
4740 05 Feb 09 nicklas 265         product.getCreationEvent().getSources(), "name");
6455 09 May 14 nicklas 266     
6455 09 May 14 nicklas 267     // Check if we are follwing a specific paths of extracts due to DerivedBioAssay.getExtract
6455 09 May 14 nicklas 268     Node extractPath = parentNode.getFirstParent(new HasAttributeFilter(NodeAttribute.EXTRACT_PATH));
6455 09 May 14 nicklas 269     if (extractPath != null)
6455 09 May 14 nicklas 270     {
6455 09 May 14 nicklas 271       // Yes, we are following a specific paths of extracts...
6455 09 May 14 nicklas 272       // Is the parent item still on the path?
6455 09 May 14 nicklas 273       if (extractPath.getAttribute(NodeAttribute.EXTRACT_PATH).contains(product.getId()))
6455 09 May 14 nicklas 274       {
6455 09 May 14 nicklas 275         // Yes, but is the parent item one of the specified extract on a DerivedBioassay?
6455 09 May 14 nicklas 276         if (parentNode.getFirstParent(new HasAttributeFilter(NodeAttribute.EXTRACT, product)) == null)
6455 09 May 14 nicklas 277         {
6455 09 May 14 nicklas 278           // No, so we have not found the 'exit' extract
6455 09 May 14 nicklas 279           // and we must only load extracts that are part of the path
6455 09 May 14 nicklas 280           query.restrict(Restrictions.in(Hql.property("id"), Expressions.parameter("extracts")));
6455 09 May 14 nicklas 281           query.setParameter("extracts", extractPath.getAttribute(NodeAttribute.EXTRACT_PATH), Type.INT);
6455 09 May 14 nicklas 282         }
6455 09 May 14 nicklas 283       }
6455 09 May 14 nicklas 284     }
6455 09 May 14 nicklas 285     
4740 05 Feb 09 nicklas 286     ItemResultIterator<Extract> it = query.iterate(dc);
4755 12 Feb 09 nicklas 287     int numExtracts = 0;
4740 05 Feb 09 nicklas 288     while (it.hasNext())
4740 05 Feb 09 nicklas 289     {
4755 12 Feb 09 nicklas 290       numExtracts++;
4740 05 Feb 09 nicklas 291       Extract source = it.next();
4740 05 Feb 09 nicklas 292       // We need to handle circular references inline because
4740 05 Feb 09 nicklas 293       // we can never require that a validator implementation handles this
4755 12 Feb 09 nicklas 294       Node circularNode = OverviewUtil.getCircularRef(parentNode, source);
4755 12 Feb 09 nicklas 295       if (circularNode != null)
4740 05 Feb 09 nicklas 296       {
4740 05 Feb 09 nicklas 297         context.createFailure(Validator.CIRCULAR_REFERENCE, parentNode, 
4740 05 Feb 09 nicklas 298             "Circular reference to '" + source.getName() + "'", 
4755 12 Feb 09 nicklas 299             new Fix("Modify parent extracts of '" + product.getName() + "'", product),
4755 12 Feb 09 nicklas 300             new Fix("Modify parent extracts of '" + source.getName() + "'", source)
4740 05 Feb 09 nicklas 301           );
4740 05 Feb 09 nicklas 302       }
4740 05 Feb 09 nicklas 303       else
4740 05 Feb 09 nicklas 304       {
4740 05 Feb 09 nicklas 305         if (folderNode == null)
4740 05 Feb 09 nicklas 306         {
4755 12 Feb 09 nicklas 307           folderNode = new Node("pooled", "Parent extracts", parentNode, ChildNodeDirection.REVERSE);
4740 05 Feb 09 nicklas 308         }
4766 17 Feb 09 nicklas 309         createItemNode(nf, source, source, false, folderNode, ChildNodeDirection.REVERSE);
4740 05 Feb 09 nicklas 310       }
4740 05 Feb 09 nicklas 311     }
4755 12 Feb 09 nicklas 312     postValidateFolder(nf, folderNode, parentNode, numExtracts == 0);
4740 05 Feb 09 nicklas 313     return folderNode;
4740 05 Feb 09 nicklas 314   }
4740 05 Feb 09 nicklas 315
4740 05 Feb 09 nicklas 316   /**
5663 22 Jun 11 nicklas 317     Create a reverse-loading extract node from an extract. Eg. the child node
5663 22 Jun 11 nicklas 318     is the extract that is the parent of the (non-pooled) extract.
5663 22 Jun 11 nicklas 319   */
5663 22 Jun 11 nicklas 320   private Node createSingleParentReverseNode(Extract bioMaterial, DbControl dc, OverviewContext context, Node parentNode)
5663 22 Jun 11 nicklas 321   {
5663 22 Jun 11 nicklas 322     NodeFactory<Extract> nf = getNodeFactory(dc, context);
5663 22 Jun 11 nicklas 323     Extract extract = null;
5663 22 Jun 11 nicklas 324     boolean denied = false;
5663 22 Jun 11 nicklas 325     try
5663 22 Jun 11 nicklas 326     {
5663 22 Jun 11 nicklas 327       extract = (Extract)bioMaterial.getParent();
5663 22 Jun 11 nicklas 328     }
5663 22 Jun 11 nicklas 329     catch (PermissionDeniedException ex)
5663 22 Jun 11 nicklas 330     {
5663 22 Jun 11 nicklas 331       denied = true;
5663 22 Jun 11 nicklas 332     }
5807 14 Oct 11 nicklas 333     Node extractNode = createItemNode(nf, extract, extract, denied, 
5663 22 Jun 11 nicklas 334         parentNode, ChildNodeDirection.REVERSE);
5807 14 Oct 11 nicklas 335     return extractNode;
5663 22 Jun 11 nicklas 336   }
5663 22 Jun 11 nicklas 337
5663 22 Jun 11 nicklas 338   /**
5642 26 May 11 nicklas 339     Create reverse-loading extract nodes from a physical bioassay. Eg. the child nodes
5642 26 May 11 nicklas 340     are the extracts that has been used on a bioassay.
5641 25 May 11 nicklas 341   */
5748 19 Sep 11 nicklas 342   private Node createReverseNode(PhysicalBioAssay bioAssay, DbControl dc, OverviewContext context, Node bioAssayNode)
5641 25 May 11 nicklas 343   {
5641 25 May 11 nicklas 344     Node folderNode = null;
5641 25 May 11 nicklas 345     NodeFactory<Extract> nf = getNodeFactory(dc, context);
6090 22 Aug 12 nicklas 346
5748 19 Sep 11 nicklas 347     ItemQuery<Extract> query = context.initQuery(bioAssay.getExtracts(0), "name");
6090 22 Aug 12 nicklas 348     // If we have followed this path from derived bioassays that has specified an 
6090 22 Aug 12 nicklas 349     // extract we should only load the same extracts when following the path upstreams
6799 25 Mar 15 nicklas 350     Set<Integer> extracts = getExtractChain(bioAssayNode);
6455 09 May 14 nicklas 351     if (extracts.size() > 0) 
5748 19 Sep 11 nicklas 352     {
6455 09 May 14 nicklas 353       // Since we don't know exactly how far upstreams the given extrcts are we
6455 09 May 14 nicklas 354       // must first find all child items (recursively)
6455 09 May 14 nicklas 355       Set<Integer> allChildren = getAllChildren(dc, extracts);
6455 09 May 14 nicklas 356       // We keep the set of all child extracts since we need that later
6455 09 May 14 nicklas 357       // when moving up the parent chain (see createPooledReverseNode)
6455 09 May 14 nicklas 358       bioAssayNode.setAttribute(NodeAttribute.EXTRACT_PATH, allChildren);
6091 24 Aug 12 nicklas 359       
6455 09 May 14 nicklas 360       // An we must of course limit the extracts on this level also
6455 09 May 14 nicklas 361       query.restrict(Restrictions.in(Hql.property("id"), Expressions.parameter("extracts")));
6455 09 May 14 nicklas 362       query.setParameter("extracts", allChildren, Type.INT);
5748 19 Sep 11 nicklas 363     }
6455 09 May 14 nicklas 364     Iterator<Extract> it = query.iterate(dc);
5641 25 May 11 nicklas 365     while (it.hasNext())
5641 25 May 11 nicklas 366     {
6090 22 Aug 12 nicklas 367       Extract extract = it.next();
5641 25 May 11 nicklas 368       if (folderNode == null)
5641 25 May 11 nicklas 369       {
5748 19 Sep 11 nicklas 370         folderNode = new Node("extracts", "Extracts", bioAssayNode, ChildNodeDirection.REVERSE);
5641 25 May 11 nicklas 371       }
5641 25 May 11 nicklas 372       createItemNode(nf, extract, extract, false, folderNode, ChildNodeDirection.REVERSE);
5641 25 May 11 nicklas 373     }
6455 09 May 14 nicklas 374     postValidateFolder(nf, folderNode, bioAssayNode, extracts.size() > 0);
5641 25 May 11 nicklas 375     return folderNode;
5641 25 May 11 nicklas 376   }
5641 25 May 11 nicklas 377
5748 19 Sep 11 nicklas 378   private Node createReverseNode(DerivedBioAssay bioAssay, DbControl dc, OverviewContext context, Node bioAssayNode)
5653 13 Jun 11 nicklas 379   {
5653 13 Jun 11 nicklas 380     NodeFactory<Extract> nf = getNodeFactory(dc, context);
5653 13 Jun 11 nicklas 381     Extract extract = null;
5653 13 Jun 11 nicklas 382     boolean denied = false;
5653 13 Jun 11 nicklas 383     try
5653 13 Jun 11 nicklas 384     {
5748 19 Sep 11 nicklas 385       extract = bioAssay.getExtract();
5653 13 Jun 11 nicklas 386     }
5653 13 Jun 11 nicklas 387     catch (PermissionDeniedException ex)
5653 13 Jun 11 nicklas 388     {
5653 13 Jun 11 nicklas 389       denied = true;
5653 13 Jun 11 nicklas 390     }
5653 13 Jun 11 nicklas 391     Node extractNode = createItemNode(nf, extract, extract, denied, 
5748 19 Sep 11 nicklas 392         bioAssayNode, ChildNodeDirection.REVERSE);
5653 13 Jun 11 nicklas 393     return extractNode;
5653 13 Jun 11 nicklas 394   }
5653 13 Jun 11 nicklas 395   
5748 19 Sep 11 nicklas 396   private Node createReverseNode(RawBioAssay raw, DbControl dc, OverviewContext context, Node rawNode)
5748 19 Sep 11 nicklas 397   {
5748 19 Sep 11 nicklas 398     NodeFactory<Extract> nf = getNodeFactory(dc, context);
5748 19 Sep 11 nicklas 399     Extract extract = null;
5748 19 Sep 11 nicklas 400     boolean denied = false;
5748 19 Sep 11 nicklas 401     try
5748 19 Sep 11 nicklas 402     {
5748 19 Sep 11 nicklas 403       extract = raw.getParentExtract();
5748 19 Sep 11 nicklas 404     }
5748 19 Sep 11 nicklas 405     catch (PermissionDeniedException ex)
5748 19 Sep 11 nicklas 406     {
5748 19 Sep 11 nicklas 407       denied = true;
5748 19 Sep 11 nicklas 408     }
5748 19 Sep 11 nicklas 409     Node extractNode = createItemNode(nf, extract, extract, denied, 
5748 19 Sep 11 nicklas 410         rawNode, ChildNodeDirection.REVERSE);
5748 19 Sep 11 nicklas 411     return extractNode;
5748 19 Sep 11 nicklas 412   }
5748 19 Sep 11 nicklas 413   
5641 25 May 11 nicklas 414   /**
4740 05 Feb 09 nicklas 415     Create forward-loading extract nodes for the extracts that has a given
4740 05 Feb 09 nicklas 416     sample as their parent.
4740 05 Feb 09 nicklas 417   */
5985 24 Feb 12 nicklas 418   private Node createForwardNode(Sample sample, DbControl dc, OverviewContext context, Node parentNode,
5985 24 Feb 12 nicklas 419     boolean onlyPushAnnotationTypes)
4740 05 Feb 09 nicklas 420   {
4740 05 Feb 09 nicklas 421     NodeFactory<Extract> nf = getNodeFactory(dc, context);
4740 05 Feb 09 nicklas 422     Node folderNode = null;
4740 05 Feb 09 nicklas 423     ItemQuery<Extract> query = context.initQuery(sample.getExtracts(), "name");
5985 24 Feb 12 nicklas 424     if (onlyPushAnnotationTypes) OverviewUtil.restrictToPushAnnotationSubtypes(query);
4740 05 Feb 09 nicklas 425     ItemResultIterator<Extract> it = query.iterate(dc);
4740 05 Feb 09 nicklas 426     while (it.hasNext())
4740 05 Feb 09 nicklas 427     {
4740 05 Feb 09 nicklas 428       Extract extract = it.next();
4740 05 Feb 09 nicklas 429       if (folderNode == null)
4740 05 Feb 09 nicklas 430       {
4755 12 Feb 09 nicklas 431         folderNode = new Node("extracts", "Child extracts", parentNode, ChildNodeDirection.FORWARD);
4740 05 Feb 09 nicklas 432       }
4766 17 Feb 09 nicklas 433       createItemNode(nf, extract, extract, false, folderNode, ChildNodeDirection.FORWARD);
4740 05 Feb 09 nicklas 434     }
4740 05 Feb 09 nicklas 435     postValidateFolder(nf, folderNode, parentNode, false);
4740 05 Feb 09 nicklas 436     return folderNode;
4740 05 Feb 09 nicklas 437   }
4740 05 Feb 09 nicklas 438   
4740 05 Feb 09 nicklas 439   /**
4740 05 Feb 09 nicklas 440     Create forward-loading extract nodes for the (pooled) extract that has a given
5985 24 Feb 12 nicklas 441     extract among their parents. If the parent node is a forward-loading node all child 
5985 24 Feb 12 nicklas 442     nodes are loaded, otherwise only child nodes that have an item with a subtype that
5985 24 Feb 12 nicklas 443     has {@link ItemSubtype#getPushAnnotations()} set.
4740 05 Feb 09 nicklas 444   */
5985 24 Feb 12 nicklas 445   private Node createForwardNode(Extract parentExtract, DbControl dc, OverviewContext context, Node parentNode, 
5985 24 Feb 12 nicklas 446     boolean onlyPushAnnotationTypes)
4740 05 Feb 09 nicklas 447   {
4740 05 Feb 09 nicklas 448     NodeFactory<Extract> nf = getNodeFactory(dc, context);
4740 05 Feb 09 nicklas 449     Node folderNode = null;
4740 05 Feb 09 nicklas 450     ItemQuery<Extract> query = context.initQuery(parentExtract.getChildExtracts(), "name");
5985 24 Feb 12 nicklas 451     if (onlyPushAnnotationTypes) OverviewUtil.restrictToPushAnnotationSubtypes(query);
4740 05 Feb 09 nicklas 452     ItemResultIterator<Extract> it = query.iterate(dc);
4740 05 Feb 09 nicklas 453     while (it.hasNext())
4740 05 Feb 09 nicklas 454     {
4740 05 Feb 09 nicklas 455       Extract childExtract = it.next();
4740 05 Feb 09 nicklas 456       // We need to handle circular references inline because
4740 05 Feb 09 nicklas 457       // we can never require that a validator implementation handles this
4740 05 Feb 09 nicklas 458       Node circularNode = OverviewUtil.getCircularRef(parentNode, childExtract);
4740 05 Feb 09 nicklas 459       if (circularNode != null)
4740 05 Feb 09 nicklas 460       {
4755 12 Feb 09 nicklas 461         context.createFailure(Validator.CIRCULAR_REFERENCE, parentNode, 
4740 05 Feb 09 nicklas 462             "Circular reference to '" + childExtract.getName() + "'", 
4755 12 Feb 09 nicklas 463             new Fix("Modify parent extracts of '" + childExtract.getName() + "'", childExtract),
4755 12 Feb 09 nicklas 464             new Fix("Modify parent extracts of '" + parentExtract.getName() + "'", parentExtract)
4755 12 Feb 09 nicklas 465             );
4740 05 Feb 09 nicklas 466       }
4740 05 Feb 09 nicklas 467       else
4740 05 Feb 09 nicklas 468       {
4740 05 Feb 09 nicklas 469         if (folderNode == null)
4740 05 Feb 09 nicklas 470         {
4755 12 Feb 09 nicklas 471           folderNode = new Node("extracts", "Child extracts", parentNode, ChildNodeDirection.FORWARD);
4740 05 Feb 09 nicklas 472         }
4766 17 Feb 09 nicklas 473         createItemNode(nf, childExtract, childExtract, false, folderNode, ChildNodeDirection.FORWARD);
4740 05 Feb 09 nicklas 474       }
4740 05 Feb 09 nicklas 475     }
4740 05 Feb 09 nicklas 476     postValidateFolder(nf, folderNode, parentNode, false);
4740 05 Feb 09 nicklas 477     return folderNode;
4740 05 Feb 09 nicklas 478   }
4740 05 Feb 09 nicklas 479
6799 25 Mar 15 nicklas 480   private Set<Integer> getExtractChain(Node node)
6090 22 Aug 12 nicklas 481   {
6090 22 Aug 12 nicklas 482     List<Node> nodesWithExtract = node.findAll(new HasAttributeFilter(NodeAttribute.EXTRACT));
6799 25 Mar 15 nicklas 483     Set<Integer> extracts = new HashSet<Integer>(nodesWithExtract.size());
6090 22 Aug 12 nicklas 484     for (Node n : nodesWithExtract)
6090 22 Aug 12 nicklas 485     {
6799 25 Mar 15 nicklas 486       extracts.add(n.getAttribute(NodeAttribute.EXTRACT).getId());
6090 22 Aug 12 nicklas 487     }
6455 09 May 14 nicklas 488     return extracts;
6090 22 Aug 12 nicklas 489   }
6090 22 Aug 12 nicklas 490   
6799 25 Mar 15 nicklas 491   private Set<Integer> getAllChildren(DbControl dc, Set<Integer> parents)
6455 09 May 14 nicklas 492   {
6799 25 Mar 15 nicklas 493     SourceItemTransformer transformer = new ExtractToChildExtractTransformer(true);
6799 25 Mar 15 nicklas 494     return transformer.transform(new TransformContext(dc), parents);
6455 09 May 14 nicklas 495   }
6455 09 May 14 nicklas 496   
4740 05 Feb 09 nicklas 497 }