Changeset 3523


Ignore:
Timestamp:
Jun 20, 2007, 2:32:41 PM (14 years ago)
Author:
Nicklas Nordborg
Message:

Fixes #583: Allow changing the array design of a raw bioasay when it has raw data

Location:
trunk
Files:
8 edited

Legend:

Unmodified
Added
Removed
  • trunk/doc/src/docbook/userdoc/rawbioassays.xml

    r3487 r3523  
    105105            since some optimzations can be used when assigning
    106106            positions in bioassay sets.
    107             The array design cannot be changed after raw data has been
    108             imported.
     107            The array design can be changed after raw data has been
     108            imported, but this triggers a new validation. If the raw data
     109            is stored in the database, the position, coordinates and reporter of all features
     110            on the new array design must exactly match the position,
     111            coordinates and reporter of the raw data. For Affymetrix data, the
     112            CEL file is validated against the CDF file of the new array design.
     113            If the validation fails, the array design is not changed.
    109114          </para>
    110115        </listitem>
  • trunk/src/core/net/sf/basedb/core/Affymetrix.java

    r3483 r3523  
    201201      File cdfFile = getCdfFile(design);
    202202      FusionCDFData cdf = loadCdfFile(cdfFile);
     203      validateCelAndCdf(cel, cdf, cdfFile.getName());
    203204     
    204       String celChipType = cel.getChipType();
    205       String cdfChipType = cdfFile.getName();
    206       if (!cdfChipType.startsWith(celChipType))
    207       {
    208         throw new InvalidDataException("CEL chip type (" + celChipType +
    209           ") doesn't match CDF chip type (" + cdfChipType + ")");
    210       }
    211      
    212       if (cel.getRows() != cdf.getHeader().getRows() || cel.getCols() != cdf.getHeader().getRows())
    213       {
    214         throw new InvalidDataException("CEL size (rows=" + cel.getRows() + ", cols=" + cel.getCols() +
    215           ") doesn't match CDF size (rows=" +
    216           cdf.getHeader().getRows() + ", cols=" + cdf.getHeader().getCols()+")");
    217       }
    218 
    219205      file.checkPermission(Permission.USE);
    220206      AnyToAny ata = AnyToAny.getNewOrExisting(dc, rawBioAssay, CEL_LINK_NAME, file, true);
     
    285271    {}
    286272    return celFile;
     273  }
     274 
     275  /**
     276    Check if the CEL file on the raw bioassay matches the CDF file on the
     277    array design.
     278   
     279    @param rawBioAssay The raw bioassay
     280    @param design The array design
     281    @param required TRUE if the absense of either a CEL or a CDF file is an
     282      error condition
     283    @throws InvalidDataException If the raw bioassay or array design are not
     284      Affymetrix type, or if the CEL doesn't match the CDF
     285    @since 2.4
     286  */
     287  public static void validateCelAndCdf(RawBioAssay rawBioAssay, ArrayDesign design, boolean required)
     288  {
     289    File celFile = getCelFile(rawBioAssay);
     290    File cdfFile = getCdfFile(design);
     291    if (celFile != null && cdfFile != null)
     292    {
     293      String cdfChipType = cdfFile.getName();
     294      FusionCELData cel = loadCelFile(celFile);
     295      FusionCDFData cdf = loadCdfFile(cdfFile);
     296      validateCelAndCdf(cel, cdf, cdfChipType);
     297    }
     298    else if (required)
     299    {
     300      if (celFile == null)
     301      {
     302        throw new InvalidDataException("Raw bioassay has no CEL file: " + rawBioAssay);
     303      }
     304      else
     305      {
     306        throw new InvalidDataException("Array design has no CDF file: " + design);       
     307      }
     308    }
     309  }
     310 
     311  private static void validateCelAndCdf(FusionCELData cel, FusionCDFData cdf, String cdfChipType)
     312    throws InvalidDataException
     313  {
     314    String celChipType = cel.getChipType();
     315    if (!cdfChipType.startsWith(celChipType))
     316    {
     317      throw new InvalidDataException("CEL chip type (" + celChipType +
     318        ") doesn't match CDF chip type (" + cdfChipType + ")");
     319    }
     320   
     321    if (cel.getRows() != cdf.getHeader().getRows() || cel.getCols() != cdf.getHeader().getRows())
     322    {
     323      throw new InvalidDataException("CEL size (rows=" + cel.getRows() + ", cols=" + cel.getCols() +
     324        ") doesn't match CDF size (rows=" +
     325        cdf.getHeader().getRows() + ", cols=" + cdf.getHeader().getCols()+")");
     326    }   
    287327  }
    288328 
  • trunk/src/core/net/sf/basedb/core/Job.java

    r3480 r3523  
    545545  {
    546546    checkPermission(Permission.WRITE);
    547     if (getStatus() != Status.WAITING)
     547    if (getStatus() != Status.WAITING && getStatus() != Status.UNCONFIGURED)
    548548    {
    549549      throw new PermissionDeniedException("Can't prepare a job with status '"+getStatus()+"': "+toString());
     
    577577    data.setStarted(new Date());
    578578    data.setPercentComplete(0);
     579  }
     580 
     581  /**
     582    Get a progress reporter that reports progress by updating the information
     583    in the database.
     584   
     585    @param chained An optional chained progress reporter to which all
     586      updates will be forwarded
     587    @return A progress reporter object
     588    @since 2.4
     589  */
     590  public ProgressReporter getProgressReporter(ProgressReporter chained)
     591  {
     592    return new ProgressReporterImpl(this, null, chained);
    579593  }
    580594 
  • trunk/src/core/net/sf/basedb/core/RawBioAssay.java

    r3483 r3523  
    2424package net.sf.basedb.core;
    2525
     26import net.sf.basedb.core.data.FeatureData;
    2627import net.sf.basedb.core.data.RawBioAssayData;
    2728import net.sf.basedb.core.data.RawData;
     29import net.sf.basedb.core.data.ReporterData;
    2830import net.sf.basedb.core.data.SpotImagesData;
    2931
     
    3335import net.sf.basedb.core.query.Expressions;
    3436
     37import java.util.HashMap;
     38import java.util.Map;
    3539import java.util.Set;
    3640import java.util.HashSet;
    3741import java.util.Collections;
    3842import java.util.TreeSet;
     43
     44import org.hibernate.EntityMode;
     45import org.hibernate.metadata.ClassMetadata;
    3946
    4047/**
     
    426433 
    427434  /**
    428     Set the {@link ArrayDesign} this raw data uses. The array design can't be changed
    429     once raw data spots has been added.
    430 
     435    Set the {@link ArrayDesign} this raw data uses. The array design can't be
     436    changed with this method once raw data spots has been added. Use
     437    the {@link #updateArrayDesign(ArrayDesign, ProgressReporter)} to
     438    do that.
     439 
    431440    @param arrayDesign The <code>ArrayDesign</code> item or null if not known
    432441    @throws PermissionDeniedException If the logged in user doesn't have
     
    446455    getData().setArrayDesign(arrayDesign == null ? null : arrayDesign.getData());
    447456  }
     457 
     458  /**
     459    Set the {@link ArrayDesign} this raw data uses. If data has already been
     460    imported to the raw bioassay, the reporters for each position on the
     461    new array design must match the positions of reporters already present in
     462    the raw bioassay.
     463 
     464    @param arrayDesign The <code>ArrayDesign</code> item or null if not known
     465    @param progress An optional progress reporter
     466    @throws PermissionDeniedException If the logged in user doesn't have
     467      write permission for the raw bioassay use permission for the array design
     468    @throws InvalidDataException If the features of the new array design doesn't
     469      match the raw data
     470    @throws BaseException If there is another error
     471    @since 2.4
     472  */
     473  public void updateArrayDesign(ArrayDesign arrayDesign, ProgressReporter progress)
     474    throws PermissionDeniedException, InvalidDataException
     475  {
     476    checkPermission(Permission.WRITE);
     477    if (arrayDesign != null) arrayDesign.checkPermission(Permission.USE);
     478    if (getData().getSpots() > 0 && arrayDesign != null)
     479    {
     480      // No need to validate if there is no change
     481      if (arrayDesign.getData().equals(getData().getArrayDesign())) return;
     482 
     483      if (getRawDataType().isAffymetrix())
     484      {
     485        // Verify CEL and CDF files
     486        Affymetrix.validateCelAndCdf(this, arrayDesign, false);
     487      }
     488      else if (getRawDataType().isStoredInDb())
     489      {
     490        validateFeatures(getDbControl(), arrayDesign, true, progress);
     491      }
     492    }
     493    getData().setArrayDesign(arrayDesign == null ? null : arrayDesign.getData());
     494  }
    448495
    449496  /**
     
    687734  }
    688735
     736  /**
     737    Validate that the features/reporters of the raw data matches the
     738    features/reporter on the array design.
     739    @param dc The DbControl to use for database access
     740    @param design The array design to validate agains
     741    @param update If the raw data should be linked to the new feature or not
     742    @param progress An optional progress reporter
     743    @since 2.4
     744  */
     745  private void validateFeatures(DbControl dc, ArrayDesign design, boolean update, ProgressReporter progress)
     746  {
     747    if (design.isAffyChip())
     748    {
     749      throw new InvalidDataException("The array design is an Affymetrix chip: " + design.getName());
     750    }
     751    if (design.hasFeatures())
     752    {
     753      if (progress != null) progress.display(5, "Loading features from array design...");
     754     
     755      // Hibernate metadata for setting new features
     756      ClassMetadata metaData = HibernateUtil.getClassMetadata(getRawDataType().getEntityName());
     757      org.hibernate.Session session = dc.getHibernateSession();
     758      String entityName = getRawDataType().getEntityName();
     759     
     760      // Preload features from array design
     761      org.hibernate.Query query = HibernateUtil.getPredefinedQuery(dc.getStatelessSession(),
     762        "COUNT_FEATURES_FOR_ARRAYDESIGN");
     763      /*
     764        SELECT count(*)
     765        FROM FeatureData f
     766        WHERE f.arrayDesignBlock.arrayDesign = :arrayDesign
     767      */
     768      query.setInteger("arrayDesign", design.getId());
     769      int numFeatures = HibernateUtil.loadData(Long.class, query).intValue();
     770      Map<Integer, FeatureData> features = new HashMap<Integer, FeatureData>(numFeatures);
     771      query = HibernateUtil.getPredefinedQuery(dc.getStatelessSession(), "PRELOAD_FEATURES");
     772      /*
     773        SELECT f
     774        FROM FeatureData f
     775        JOIN FETCH f.arrayDesignBlock b
     776        LEFT JOIN FETCH f.reporter
     777        WHERE b.arrayDesign = :arrayDesign
     778      */
     779      query.setInteger("arrayDesign", design.getId());
     780      ScrollIterator<FeatureData> si = HibernateUtil.loadIterator(FeatureData.class, query);
     781      while (si.hasNext())
     782      {
     783        FeatureData f = si.next();
     784        features.put(f.getPosition(), f);
     785      }
     786      si.close();
     787     
     788      // Load raw data
     789      if (progress != null) progress.display(10, "Loading raw data from raw bioassay...");
     790      DataQuery<RawData> rawQuery = getRawData();
     791      DataResultIterator<RawData> result = rawQuery.iterate(dc);
     792      int numValidated = 0;
     793      int numTotal = getSpots();
     794      while (result.hasNext())
     795      {
     796        RawData raw = result.next();
     797        int position = raw.getPosition();
     798        FeatureData feature = features.get(position);
     799        if (feature == null)
     800        {
     801          throw new InvalidDataException("Array design '" + design.getName() +
     802            "' is missing a feature at position " + raw.getPosition());
     803        }
     804       
     805        // Check that reporters are the same
     806        ReporterData rawReporter = raw.getReporter();
     807        ReporterData featureReporter = feature.getReporter();
     808        if (rawReporter == null)
     809        {
     810          if (featureReporter != null)
     811          {
     812            throw new InvalidDataException("Reporter mismatch at position " + position +
     813              "; raw reporter=none, feature reporter=" + featureReporter.getExternalId());
     814          }
     815        }
     816        else
     817        {
     818          if (featureReporter == null)
     819          {
     820            throw new InvalidDataException("Reporter mismatch at position " + position +
     821              "; raw reporter=" + rawReporter.getExternalId() + ", feature reporter=none");
     822          }
     823          else if (rawReporter.getId() != featureReporter.getId())
     824          {
     825            throw new InvalidDataException("Reporter mismatch at position " + position +
     826              "; raw reporter=" + rawReporter.getExternalId() +
     827              ", feature reporter=" + featureReporter.getExternalId());
     828          }
     829        }
     830         
     831        // Check that coordinates are the same
     832        FeatureCoordinate featureCoordinate = Feature.getFeatureCoordinate(feature);
     833        FeatureCoordinate rawCoordinate = new FeatureCoordinate(raw.getBlock(),
     834          raw.getMetaGridX(), raw.getMetaGridY(), raw.getRow(), raw.getColumn());
     835       
     836        if (!featureCoordinate.equals(rawCoordinate))
     837        {
     838          throw new InvalidDataException("Coordinate mismatch at position " + position +
     839            "; raw=" + rawCoordinate +", feature=" + featureCoordinate);
     840        }
     841       
     842        // All is ok, re-assign raw data to the new feature
     843        if (update)
     844        {
     845          metaData.setPropertyValue(raw, "feature", feature, EntityMode.POJO);
     846          session.update(entityName, raw);
     847        }
     848       
     849        // Report progress
     850        numValidated++;
     851        if (progress != null && numValidated % 100 == 0)
     852        {
     853          int percent = 10 + (90 * numValidated) / numTotal;
     854          progress.display(percent, "Validated " + numValidated + " of " + numTotal + " spots.");
     855        }
     856      }
     857    }
     858  }
    689859}
  • trunk/src/core/net/sf/basedb/core/templates/hibernate-properties-RawData.xml

    r2304 r3523  
    7070      cascade="evict"
    7171      fetch="select"
    72       update="false"
     72      update="true"
    7373      insert="true"
    7474      column="`feature_id`"
  • trunk/www/views/jobs/view_job.jsp

    r2978 r3523  
    421421      %>
    422422      <%
    423       if (job.getStatus() == Job.Status.ERROR)
     423      if (job.getStatus() == Job.Status.ERROR && job.getJobType() == Job.Type.RUN_PLUGIN)
    424424      {
    425425        %>
  • trunk/www/views/rawbioassays/edit_rawbioassay.jsp

    r3400 r3523  
    576576        <td>
    577577          <%
    578           if (rawBioAssay == null || !rawBioAssay.hasData())
     578          //if (rawBioAssay == null || !rawBioAssay.hasData())
    579579          {
    580580            %>
     
    593593            <%
    594594          }
     595          /*
    595596          else
    596597          {
     
    601602            <%
    602603          }
     604          */
    603605          %>
    604606        </td>
  • trunk/www/views/rawbioassays/index.jsp

    r2978 r3523  
    2626--%>
    2727<%@ page session="false"
     28  import="net.sf.basedb.core.Application"
    2829  import="net.sf.basedb.core.SessionControl"
    2930  import="net.sf.basedb.core.DbControl"
     
    5152  import="net.sf.basedb.core.PluginDefinition"
    5253  import="net.sf.basedb.core.Job"
     54  import="net.sf.basedb.core.ProgressReporter"
    5355  import="net.sf.basedb.core.IntegerParameterType"
    5456  import="net.sf.basedb.core.FloatParameterType"
     
    6971  import="java.util.List"
    7072  import="java.util.ArrayList"
     73  import="java.util.Arrays"
    7174  import="java.util.Collections"
    7275%>
     
    7578  private static final ItemContext defaultContext = Base.createDefaultContext("name", "name,rawDataType,spots,description");
    7679  private static final Item itemType = Item.RAWBIOASSAY;
     80 
     81  private static class UpdateArrayDesign
     82    implements Runnable
     83  {
     84    private final int jobId;
     85    private final int rawBioAssayId;
     86    private final int arrayDesignId;
     87    private final SessionControl sc;
     88   
     89    private UpdateArrayDesign(Job job, RawBioAssay rba, ArrayDesign design)
     90    {
     91      this.jobId = job.getId();
     92      this.rawBioAssayId = rba.getId();
     93      this.arrayDesignId = design.getId();
     94      this.sc = job.getSessionControl();
     95    }
     96   
     97    public void run()
     98    {
     99      DbControl dc = sc.newDbControl();
     100      try
     101      {
     102        Job j = Job.getById(dc, jobId);
     103        j.start("Initialising...", Application.getHostName());
     104        dc.commit();
     105        dc = sc.newDbControl();
     106        RawBioAssay rba = RawBioAssay.getById(dc, rawBioAssayId);
     107        ArrayDesign design = ArrayDesign.getById(dc, arrayDesignId);
     108        ProgressReporter progress = j.getProgressReporter(null);
     109        try
     110        {
     111          rba.updateArrayDesign(design, progress);
     112          progress.display(99, "Committing changes to database...");
     113          dc.commit();
     114          dc = sc.newDbControl();
     115          j = Job.getById(dc, jobId);
     116          j.doneOk("Array design updated successfully");
     117          j.setRemoved(true);
     118          dc.commit();
     119        }
     120        catch (Throwable t)
     121        {
     122          dc = sc.newDbControl();
     123          j = Job.getById(dc, jobId);
     124          j.doneError(t.getMessage(), Arrays.asList(t));
     125          j.setRemoved(true);
     126          dc.commit();
     127        }
     128      }
     129      finally
     130      {
     131        if (dc != null) dc.close();
     132      }
     133    }
     134  }
    77135%>
    78136<%
     
    192250      if (scan != null) cc.setRecent(scan, maxRecent);
    193251    }
     252    Job job = null;
     253    ArrayDesign ad = null;
    194254    int arrayDesignId = Values.getInt(request.getParameter("arraydesign_id"), -1);
    195255    if (arrayDesignId >= 0) // < 0 = denied or unchanged
    196256    {
    197       ArrayDesign ad = arrayDesignId == 0 ? null : ArrayDesign.getById(dc, arrayDesignId);
    198       rba.setArrayDesign(ad);
     257      ad = arrayDesignId == 0 ? null : ArrayDesign.getById(dc, arrayDesignId);
     258      if (rba.getSpots() > 0)
     259      {
     260        if (rba.getRawDataType().isStoredInDb() && ad != null && ad.hasFeatures())
     261        {
     262          // Create job and assign it to another thread
     263          job = Job.getNew(dc, null, null);
     264          job.setName("Validating array design on " + rba.getName());
     265          job.setPrepared(Application.getHostName());
     266          dc.saveItem(job);
     267        }
     268        else
     269        {
     270          rba.updateArrayDesign(ad, null);
     271        }
     272      }
     273      else
     274      {
     275        rba.setArrayDesign(ad);
     276      }
    199277      if (ad != null) cc.setRecent(ad, maxRecent);
    200278    }
     
    214292    dc.commit();
    215293    cc.removeObject("item");
     294    if (job != null)
     295    {
     296      redirect = "../jobs/index.jsp?ID="+ID+"&cmd=ViewItem&item_id="+job.getId();
     297      Thread updateThread = new Thread(new UpdateArrayDesign(job, rba, ad));
     298      updateThread.setPriority(Thread.currentThread().getPriority() - 1);
     299      updateThread.start();
     300    }
    216301  }
    217302  else if ("DeleteItem".equals(cmd))
Note: See TracChangeset for help on using the changeset viewer.