Changeset 6474


Ignore:
Timestamp:
Nov 4, 2021, 3:30:00 PM (15 months ago)
Author:
Nicklas Nordborg
Message:

Merge Reggie 4.33.4 to the trunk

Location:
extensions/net.sf.basedb.reggie/trunk
Files:
17 edited

Legend:

Unmodified
Added
Removed
  • extensions/net.sf.basedb.reggie/trunk

  • extensions/net.sf.basedb.reggie/trunk/resources/batch/import-external-specimen.js

    r6353 r6474  
    5555    html += '<th class="dottedleft">JSON file</th>'
    5656    html += '<th>Date</th>';
     57    html += '<th>Reads</th>';
    5758    html += '<th>FASTQ files</th>';
    5859    html += '<th class="icon"></th>'
     
    8990      html += '<td style="white-space: nowrap;">';
    9091      if (jsonFile && jsonFile.lastModified) html += Reggie.reformatDate(jsonFile.lastModified);
     92      html += '</td>';
     93      html += '<td>';
     94      if (jsonFile && jsonFile.PF_READS) html += Reggie.formatCount(jsonFile.PF_READS);
    9195      html += '</td>';
    9296      html += '<td class="fastq" style="white-space: nowrap;">';
  • extensions/net.sf.basedb.reggie/trunk/resources/personal/map-external-data.js

    r5740 r6474  
    5656    var lineNo = 0;
    5757    var mapFrom = null;
     58    var separator = null;
    5859    var preview = '';
    5960    while (lineNo < lines.length && lineNo < 5)
    6061    {
    6162      var line = lines[lineNo];
    62       if (lineNo < 3)
     63      if (lineNo < 4)
    6364      {
    6465        preview += Strings.encodeTags(line) + '\n';
    6566      }
     67      if (separator == null) separator = map.detectSeparator(line);
    6668      if (mapFrom == null)
    6769      {
    68         if (line.match(/^[QCS]\d+\t.*$/))// We look for lines starting with 'Q', 'C' or 'S' followed by {digits} and a {tab}
     70        if (line.match(/^[QCS]\d+([\t,;].*)?$/))// We look for lines starting with 'Q', 'C' or 'S' followed by {digits} and a {tab/comma/semicolon}
    6971        {
    7072          var firstChar = line.charAt(0);
     
    8284          }
    8385        }
    84         else if (lineNo == 0 && line.match(/^[^\t]*pad/i)) // If the first header column contains 'pad' (ignoring case) we assume it contains PAD values
     86        else if (lineNo == 0 && line.match(/^[^\t,;]*pad/i)) // If the first header column contains 'pad' (ignoring case) we assume it contains PAD values
    8587        {
    8688          mapFrom = 'PAD';
     
    8991      lineNo++;
    9092    }
    91     if (lines.length > 3) preview += '<div id="more-lines">+' + (lines.length-3) + ' more lines...</div>';
     93    if (lines.length > 4) preview += '<div id="more-lines">+' + (lines.length-4) + ' more lines...</div>';
     94    frm.separator.value = separator ? separator.id : 'tab';
    9295    frm.mapFrom.value = mapFrom || 'PersonalNo';
    9396    Events.sendChangeEvent(frm.mapFrom);
     
    9598  }
    9699
     100  /**
     101    Detect the "best" separator to use by selecting the one
     102    that appear the most times in the given text line. If no
     103    separator is found null is returned.
     104  */
     105  map.detectSeparator = function(text)
     106  {
     107    var separators =
     108    [
     109      { 'id': 'tab', 'test': /\t/g, 'sep': '\t'},
     110      { 'id': 'comma', 'test': /,/g, 'sep': ','},
     111      { 'id': 'semicolon', 'test': /;/g, 'sep': ';'}
     112    ];
     113    var maxCount = 0;
     114    var bestMatch = 0;
     115    for (var i=0; i < separators.length; i++)
     116    {
     117      var sep = separators[i];
     118      var m = text.match(sep.test);
     119      if (m && m.length > maxCount)
     120      {
     121        maxCount = m.length;
     122        bestMatch = i;
     123      }
     124    }
     125    return maxCount == 0 ? null : separators[bestMatch];
     126  }
    97127 
    98128  map.validateStep1 = function(event)
     
    113143    var url = '../Export.servlet?ID='+App.getSessionId();
    114144    url += '&cmd=MapDataToReleases';
     145    url += '&separator='+frm.separator.value;
    115146    url += '&mapFrom='+Strings.encodeTags(frm.mapFrom.value);
    116147    url += '&exportCaseId='+(frm.exportCaseId.checked ? 1 : 0);
  • extensions/net.sf.basedb.reggie/trunk/resources/personal/map-external-data.jsp

    r5740 r6474  
    8181        <td class="help" rowspan="2"><span id="file.message" class="message"></span>
    8282          <ul>
    83           <li>Select a tab-separated text file in UTF-8 encoding.
     83          <li>Select a tab-, comma-, or semicolon-separated text file in UTF-8 encoding.
    8484          <li>The first line should contain column headers.
    8585          <li>The first column should contain the personal number, or a release id value as specified by the <b>Map from</b> option.
     
    9393        <td>
    9494          <div id="preview"><i>No file loaded...</i></div>
     95        </td>
     96        <td></td>
     97      </tr>
     98      <tr>
     99        <td class="prompt">Separator</td>
     100        <td>
     101          <select name="separator" id="separator">
     102            <option value="tab">Tab
     103            <option value="comma">Comma
     104            <option value="semicolon">Semi-colon
     105          </select>
    95106        </td>
    96107        <td></td>
  • extensions/net.sf.basedb.reggie/trunk/src/net/sf/basedb/reggie/dao/BioplateType.java

    r6049 r6474  
    109109  /**
    110110    The definition of the "External library plate" type. It is locked to extracts
    111     of subtype {@link Subtype#LIBRARY} and uses 8x12 geometry. TODO -- different geometry??
     111    of subtype {@link Subtype#LIBRARY} and uses 8x12 geometry.
    112112    @since 2.12
    113113  */
    114114  public static final BioplateType EXTERNAL_LIBRARY =
    115115    new BioplateType("External library plate", Item.EXTRACT, Subtype.LIBRARY, LockMode.LOCKED_AFTER_ADD, Geometry.EIGHT_BY_TWELVE, "ExternalLibPlate", 4);
    116    
     116 
     117  /**
     118    The definition of the "External library strip" type. It is locked to extracts
     119    of subtype {@link Subtype#LIBRARY} and uses 1x8 geometry.
     120    @since 4.33.4
     121  */
     122  public static final BioplateType EXTERNAL_LIBRARY_STRIP =
     123    new BioplateType("External library strip", Item.EXTRACT, Subtype.LIBRARY, LockMode.LOCKED_AFTER_ADD, Geometry.ONE_BY_EIGHT, "ExternalLibStrip", 5);
     124
     125 
    117126  /**
    118127    The definition of the "MIPs plate" type. It is locked to extracts
  • extensions/net.sf.basedb.reggie/trunk/src/net/sf/basedb/reggie/dao/Geometry.java

    r3571 r6474  
    4848  public static final Geometry ONE_BY_TWELVE = new Geometry("12-well (1 × 12)", 1, 12);
    4949 
     50  /**
     51    Plate geometry with 1 row and 8 columns.
     52    @since 4.33.4
     53  */
     54  public static final Geometry ONE_BY_EIGHT = new Geometry("8-well (1 × 8)", 1, 8);
     55
    5056  /**
    5157    Plate geometry with 8 rows and 2 columns.
  • extensions/net.sf.basedb.reggie/trunk/src/net/sf/basedb/reggie/grid/ImportFastqJobCreator.java

    r6421 r6474  
    187187            demuxName + " must have two values: " + rawFastqNames);
    188188      }
     189      String fastqNameR1 = null;
     190      String fastqNameR2 = null;
     191      // NOTE! Order in the list is not specified so we don't know which is R1 and R2
     192      // Search for _R1 and _R2
     193      for (String fqName : rawFastqNames)
     194      {
     195        if (fqName.contains("_R1")) fastqNameR1 = fqName;
     196        if (fqName.contains("_R2")) fastqNameR2 = fqName;
     197      }
     198      if (fastqNameR1 == null)
     199      {
     200        throw new InvalidDataException("Annotation RawFASTQ on " +
     201            demuxName + " is missing an R1 fastq file: " + rawFastqNames);
     202      }
     203      if (fastqNameR2 == null)
     204      {
     205        throw new InvalidDataException("Annotation RawFASTQ on " +
     206            demuxName + " is missing an R2 fastq file: " + rawFastqNames);
     207      }
    189208     
    190209      // Get SequencingRun so that we can get the path to the FASTQ folder.
     
    272291      // If not, we need to copy from ImportGateway
    273292      // If they don't exists at all we generate an error
    274       int fileNo = 0;
    275293      script.cmd("mkdir -p ${ImportArchive}");
    276       for (String fastqName : rawFastqNames)
    277       {
    278         fileNo++;
    279         // NOTE! Order in the list is not specified so we don't know which is R1 and R2
    280         script.cmd("FASTQ="+ScriptUtil.checkValidFilename(fastqName));
    281         script.progress(5+fileNo*5, "Copying FASTQ files: ${FASTQ}");
    282         script.cmd("if [ ! -f \"${ImportArchive}/${FASTQ}\" ]; then");
    283         script.cmd("  if [ ! -f \"${ImportGateway}/${FASTQ}\" ]; then");
    284         script.cmd("    echo \"Can't find FASTQ file ${FASTQ} in ${ImportGateway} or ${ImportArchive}\" 1>&2");
     294      script.cmd("FASTQ1="+ScriptUtil.checkValidFilename(fastqNameR1));
     295      script.cmd("FASTQ2="+ScriptUtil.checkValidFilename(fastqNameR2));
     296      for (int fileNo = 1; fileNo <= 2; fileNo++)
     297      {
     298        script.progress(5+fileNo*5, "Copying FASTQ files: ${FASTQ"+fileNo+"}");
     299        script.cmd("if [ ! -f \"${ImportArchive}/${FASTQ"+fileNo+"}\" ]; then");
     300        script.cmd("  if [ ! -f \"${ImportGateway}/${FASTQ"+fileNo+"}\" ]; then");
     301        script.cmd("    echo \"Can't find FASTQ file ${FASTQ"+fileNo+"} in ${ImportGateway} or ${ImportArchive}\" 1>&2");
    285302        script.cmd("    exit 1");
    286303        script.cmd("   fi");
    287         script.cmd("   cp \"${ImportGateway}/${FASTQ}\" \"${ImportArchive}/${FASTQ}\"");
     304        script.cmd("   cp \"${ImportGateway}/${FASTQ"+fileNo+"}\" \"${ImportArchive}/${FASTQ"+fileNo+"}\"");
    288305        if (!debug)
    289306        {
    290           script.cmd("   rm -f \"${ImportGateway}/${FASTQ}\"");
     307          script.cmd("   rm -f \"${ImportGateway}/${FASTQ"+fileNo+"}\"");
    291308        }
    292309        script.cmd("fi");
    293         script.cmd("cp \"${ImportArchive}/${FASTQ}\" fastq");
     310        script.cmd("cp \"${ImportArchive}/${FASTQ"+fileNo+"}\" fastq");
    294311        script.newLine();
    295312      }
    296      
    297       script.comment("Find FASTQ files");
    298       script.cmd("FASTQ1=`find fastq -name \"*_R1*.fastq.gz\" -print -quit 2> /dev/null`");
    299       script.cmd("FASTQ2=`find fastq -name \"*_R2*.fastq.gz\" -print -quit 2> /dev/null`");
    300       script.newLine();
    301313
    302314      script.comment("Run Bowtie2");
    303       script.progress(40, "Bowtie2: " + mergedName + " (${NumThreads} threads)");
     315      script.progress(20, "Bowtie2: " + mergedName + " (${NumThreads} threads)");
    304316      String alignCmd = "./stdwrap.sh " + bowtie_path;
    305317      alignCmd += " -p ${NumThreads}";
     
    307319      alignCmd += " --un-conc fastq.aligned/R%.fastq";
    308320      alignCmd += " -x ${Gidx}";
    309       alignCmd += " -1 ${FASTQ1}";
    310       alignCmd += " -2 ${FASTQ2}";
     321      alignCmd += " -1 fastq/${FASTQ1}";
     322      alignCmd += " -2 fastq/${FASTQ2}";
    311323      alignCmd += " -S fastq.aligned/aligned.sam";
    312324      alignCmd += " > fastq.aligned/aligned.out";
     
    319331      String trimCmd1 = "./stdwrap.sh ./trimmomatic PE";
    320332      trimCmd1 += " -threads ${NumThreads}";
    321       trimCmd1 += " ${FASTQ1}";
    322       trimCmd1 += " ${FASTQ2}";
     333      trimCmd1 += " fastq/${FASTQ1}";
     334      trimCmd1 += " fastq/${FASTQ2}";
    323335      trimCmd1 += " fastq.trimmomatic.1/"+R1_name;
    324336      trimCmd1 += " fastq.trimmomatic.1/un_"+R1_name;
     
    443455        if (m.matches())
    444456        {
    445           metrics.passedFilter = Values.getLong(m.group(1), -1);
     457          metrics.reads = Values.getLong(m.group(1), -1);
     458          metrics.passedFilter = metrics.reads;
    446459        }
    447460      }
     
    494507        int bowtie_fragment_count_limit = Values.getInt(cfg.getConfig("demux/bowtie-fragment-count-limit", mergeParameterSet, "20000"));
    495508 
    496         // We may have READS from the JSON import, but if not we should do the best and use the PF_READS value
    497         Long reads = (Long)Annotationtype.READS.getAnnotationValue(dc, merged);
    498         if (reads == null)
    499         {
    500           metrics.reads = metrics.passedFilter;
    501           Annotationtype.READS.setAnnotationValue(dc, merged, metrics.reads);
    502         }
    503         else
    504         {
    505           metrics.reads = reads;
    506         }
     509        Annotationtype.READS.setAnnotationValue(dc, merged, metrics.reads);
    507510        Annotationtype.PF_READS.setAnnotationValue(dc, merged, metrics.passedFilter);
    508511        Annotationtype.ADAPTER_READS.setAnnotationValue(dc, merged, metrics.passedFilter - metrics.passedTrimmomatic[0]);
  • extensions/net.sf.basedb.reggie/trunk/src/net/sf/basedb/reggie/plugins/FutureSpecimenImporter.java

    r6353 r6474  
    415415    else
    416416    {
    417       BioplateType plateType = BioplateType.EXTERNAL_LIBRARY;
     417      BioplateType plateType = info.libPlateType;
     418      if (plateType == null) plateType = BioplateType.EXTERNAL_LIBRARY; // Should not happen if LibraryInfo.valid==TRUE
    418419      plate = BioPlate.getNew(dc, plateType.getPlateGeometry(dc), plateType.get(dc));
    419420      plate.setName(plateType.getNextPlateName(dc, true));
  • extensions/net.sf.basedb.reggie/trunk/src/net/sf/basedb/reggie/plugins/cmd/DemuxInfo.java

    r6240 r6474  
    3939      software = demuxSection.getRequiredEntry("Software", SoftwareValidator.INSTANCE);
    4040      readString = demuxSection.getRequiredEntry("ReadString", PatternValidator.READ_STRING);
    41       pfReads = mergeSection.getRequiredEntry("PF_READS", LongValidator.POSITIVE.warnIf(10000000l, null)); // Warn if less than 10M reads
     41      pfReads = mergeSection.getRequiredEntry("PF_READS", LongValidator.POSITIVE.warnIf(20000000l, 50000000l)); // Warn if less than 20M or more than 50M reads
    4242      reads = pfReads; //
    4343      valid = !demuxSection.hasError() && !mergeSection.hasError();
  • extensions/net.sf.basedb.reggie/trunk/src/net/sf/basedb/reggie/plugins/cmd/FastqInfo.java

    r6457 r6474  
    33import java.io.InputStream;
    44import java.util.Date;
     5import java.util.Locale;
    56
    67import org.json.simple.JSONObject;
     
    3738      {
    3839        //R1.md5 = fastq.getOptionalEntry("R1 MD5", PatternValidator.MD5);
    39         R1.expectedSize = fastq.getOptionalEntry("R11size", LongValidator.POSITIVE_OR_NULL);
     40        R1.expectedSize = fastq.getOptionalEntry("R1size", LongValidator.POSITIVE_OR_NULL);
    4041      }
    4142      if (R2 != null)
     
    7071      else if (f.expectedSize != null && f.actualSize != f.expectedSize)
    7172      {
    72         section.addErrorMessage("FASTQ file size: "+f.name+"="+f.actualSize+" (expected "+f.expectedSize+" bytes)");
     73        section.addErrorMessage("FASTQ file size: "+f.name+"="+String.format(Locale.US, "%,d", f.actualSize)+" bytes (expected "+String.format(Locale.US, "%,d", f.expectedSize)+" bytes)");
    7374      }
    7475    }
  • extensions/net.sf.basedb.reggie/trunk/src/net/sf/basedb/reggie/plugins/cmd/IntValidator.java

    r6217 r6474  
    104104      catch (Exception ex)
    105105      {
    106         section.addErrorMessage("Invalid integer in JSON: "+entryKey+"="+value);
     106        section.addErrorMessage("Invalid "+entryKey+" in JSON: "+value);
    107107      }
    108108    }
     
    111111      if (minValue != null && result < minValue)
    112112      {
    113         section.addErrorMessage("Invalid integer in JSON: "+entryKey+"="+value+" (expected >="+minValue+")");
     113        section.addErrorMessage("Invalid "+entryKey+" in JSON: "+value+" (expected >="+minValue+")");
    114114        result = null;
    115115      }
    116116      if (maxValue != null && result > maxValue)
    117117      {
    118         section.addErrorMessage("Invalid integer in JSON: "+entryKey+"="+value+" (expected <="+maxValue+")");
     118        section.addErrorMessage("Invalid "+entryKey+" in JSON: "+value+" (expected <="+maxValue+")");
    119119        result = null;
    120120      }
     
    123123        if (allowed.indexOf(result) == -1)
    124124        {
    125           section.addErrorMessage("Invalid integer in JSON: "+entryKey+"="+value+" (expected one of "+allowed+")");
     125          section.addErrorMessage("Invalid "+entryKey+" in JSON: "+value+" (expected one of "+allowed+")");
    126126          result = null;
    127127        }
     
    132132      if (softMin != null && result < softMin)
    133133      {
    134         section.addWarningMessage("Unexpected integer in JSON: "+entryKey+"="+value+" (expected >="+softMin+")");
     134        section.addWarningMessage("Low value for "+entryKey+" in JSON: "+value+" (expected >="+softMin+")");
    135135      }
    136136      if (softMax != null && result > softMax)
    137137      {
    138         section.addWarningMessage("Unexpected integer in JSON: "+entryKey+"="+value+" (expected <="+softMax+")");
     138        section.addWarningMessage("High value for "+entryKey+" in JSON: "+value+" (expected <="+softMax+")");
    139139      }
    140140    }
  • extensions/net.sf.basedb.reggie/trunk/src/net/sf/basedb/reggie/plugins/cmd/JsonFile.java

    r6353 r6474  
    197197    }
    198198   
     199    if (demuxInfo != null)
     200    {
     201      j.put("PF_READS", demuxInfo.pfReads);
     202    }
     203   
    199204    if (hasError())
    200205    {
  • extensions/net.sf.basedb.reggie/trunk/src/net/sf/basedb/reggie/plugins/cmd/LibraryInfo.java

    r6346 r6474  
    4747  public Protocol protocol;
    4848  public BioPlate libPlate;
     49  public BioplateType libPlateType = BioplateType.EXTERNAL_LIBRARY;
    4950 
    5051  public boolean valid;
     
    5556    {
    5657      plateId = section.getRequiredEntry("Plate name", PatternValidator.CMD_ID);
    57       well = section.getRequiredEntry("Plate well", PlateWellValidator.PLATE_8x12);
     58      ValidPlateCoordinateWithType plateWell = section.getRequiredEntry("Plate well", PlateOrStripValidator.INSTANCE);
     59      if (plateWell != null)
     60      {
     61        well = plateWell.plateCoordinate;
     62        libPlateType = plateWell.plateType;
     63      }
    5864 
    5965      if (plateId != null && well != null && ctx != null)
     
    6369        {
    6470          String coordinate = Coordinate.numericToAlpha(well.getRow()+1)+(well.getColumn()+1);
    65           String msg = "LibPlate well ["+coordinate+"; ExternalRef="+plateId+"] duplicated in file: ";
     71          String msg = "Plate well ["+coordinate+"; ExternalRef="+plateId+"] duplicated in file: ";
    6672          section.addErrorMessage(msg+duplicate.getFile().getName());
    6773          duplicate.addErrorMessage(msg+section.getFile().getName());
     
    6975      }
    7076     
    71       if (plateId != null) libPlate = findExistingLibPlate(plateId, section);
     77      if (plateId != null) libPlate = findExistingLibPlate(plateId, libPlateType, section);
    7278      if (libPlate != null && well != null)
    7379      {
     
    7682     
    7783      libDate = section.getRequiredEntry("Date", DateValidator.YYYY_MM_DD.warnIfFutureOrOlder(365));
    78       libSize = section.getRequiredEntry("Library size", IntValidator.POSITIVE.warnIf(150, 400));
     84      libSize = section.getRequiredEntry("Library size", IntValidator.POSITIVE.warnIf(150, 500));
    7985      libMolarity = section.getRequiredEntry("Library molarity", FloatValidator.POSITIVE);
    8086      qubitConc = section.getRequiredEntry("Qubit concentration (ng/ul)", FloatValidator.POSITIVE);
     
    8288     
    8389      barcode = section.getRequiredEntry("Barcode", BarcodeValidator.INSTANCE);
    84       // TODO -- protocol
    8590      protocol = section.getRequiredEntry("Protocol", ProtocolValidator.LIB_PROTOCOL);
    8691    }
     
    8893  }
    8994 
    90   private BioPlate findExistingLibPlate(String plateId, JsonSection section)
     95  private BioPlate findExistingLibPlate(String plateId, BioplateType plateType, JsonSection section)
    9196  {
    9297    BioPlate libPlate = null;
     
    9499    ItemQuery<BioPlate> query = BioPlate.getQuery();
    95100    query.setIncludes(Reggie.INCLUDE_IN_CURRENT_PROJECT);
    96     BioplateType.EXTERNAL_LIBRARY.addFilter(dc, query, false);
     101    if (plateType != null)
     102    {
     103      plateType.addFilter(dc, query, false);
     104    }
    97105    query.join(Annotations.innerJoin(null, Annotationtype.EXTERNAL_REF.load(dc), "eref"));
    98106    query.restrict(Restrictions.eq(Hql.alias("eref"), Expressions.string(plateId)));
     
    196204  }
    197205
     206  /**
     207    Validator implementation that delegates to either STRIP_1x8 validator if
     208    the coordinate is specified as 'digit:digit' or to PLATE_8x12 otherwise.
     209    @since 4.33.4
     210  */
     211  static class PlateOrStripValidator
     212    implements ValueValidator<String, ValidPlateCoordinateWithType>
     213  {
     214    static final PlateOrStripValidator INSTANCE = new PlateOrStripValidator();
     215   
     216    @Override
     217    public Class<String> getExpectedClass()
     218    {
     219      return String.class;
     220    }
     221
     222    @Override
     223    public ValidPlateCoordinateWithType isValid(DbControl dc, String value, JsonSection section, String entryKey)
     224    {
     225      ValidPlateCoordinateWithType result = new ValidPlateCoordinateWithType();
     226      PlateWellValidator validator;
     227      if (value.matches("\\d\\:\\d"))
     228      {
     229        validator = PlateWellValidator.STRIP_1x8;
     230        result.plateType = BioplateType.EXTERNAL_LIBRARY_STRIP;
     231      }
     232      else
     233      {
     234        validator = PlateWellValidator.PLATE_8x12;
     235        result.plateType = BioplateType.EXTERNAL_LIBRARY;
     236      }
     237      result.plateCoordinate = validator.isValid(dc, value, section, entryKey);
     238      return result;
     239    }
     240  }
     241 
     242  /**
     243    Holds the validated plate type and coordinate.
     244  */
     245  static class ValidPlateCoordinateWithType
     246  {
     247    PlateCoordinate plateCoordinate;
     248    BioplateType plateType;
     249  }
    198250}
  • extensions/net.sf.basedb.reggie/trunk/src/net/sf/basedb/reggie/plugins/cmd/LongValidator.java

    r6457 r6474  
    22
    33import java.util.List;
     4import java.util.Locale;
    45
    56import net.sf.basedb.core.DbControl;
     
    119120      catch (Exception ex)
    120121      {
    121         section.addErrorMessage("Invalid long in JSON: "+entryKey+"="+value);
     122        section.addErrorMessage("Invalid "+entryKey+" in JSON: "+value);
    122123      }
    123124    }
     
    126127      if (minValue != null && result < minValue)
    127128      {
    128         section.addErrorMessage("Invalid long in JSON: "+entryKey+"="+value+" (expected >="+minValue+")");
     129        section.addErrorMessage("Invalid "+entryKey+" in JSON: "+String.format(Locale.US, "%,d", value)+" (expected >="+String.format(Locale.US, "%,d", minValue)+")");
    129130        result = null;
    130131      }
    131132      if (maxValue != null && result > maxValue)
    132133      {
    133         section.addErrorMessage("Invalid long in JSON: "+entryKey+"="+value+" (expected <="+maxValue+")");
     134        section.addErrorMessage("Invalid "+entryKey+" in JSON: "+String.format(Locale.US, "%,d", value)+" (expected <="+String.format(Locale.US, "%,d", maxValue)+")");
    134135        result = null;
    135136      }
     
    138139        if (allowed.indexOf(result) == -1)
    139140        {
    140           section.addErrorMessage("Invalid long in JSON: "+entryKey+"="+value+" (expected one of "+allowed+")");
     141          section.addErrorMessage("Invalid "+entryKey+" in JSON: "+value+" (expected one of "+allowed+")");
    141142          result = null;
    142143        }
     
    147148      if (softMin != null && result < softMin)
    148149      {
    149         section.addWarningMessage("Unexpected long in JSON: "+entryKey+"="+value+" (expected >="+softMin+")");
     150        section.addWarningMessage("Low value for "+entryKey+" in JSON: "+String.format(Locale.US, "%,d", value)+" (expected >="+String.format(Locale.US, "%,d", softMin)+")");
    150151      }
    151152      if (softMax != null && result > softMax)
    152153      {
    153         section.addWarningMessage("Unexpected long in JSON: "+entryKey+"="+value+" (expected <="+softMax+")");
     154        section.addWarningMessage("High value for "+entryKey+" in JSON: "+String.format(Locale.US, "%,d", value)+" (expected <="+String.format(Locale.US, "%,d", softMax)+")");
    154155      }
    155156    }
  • extensions/net.sf.basedb.reggie/trunk/src/net/sf/basedb/reggie/plugins/cmd/PlateWellValidator.java

    r6207 r6474  
    66import net.sf.basedb.core.DbControl;
    77import net.sf.basedb.core.data.PlateCoordinate;
     8import net.sf.basedb.util.Coordinate;
    89
    910/**
    1011  Validator for plate well coordinates that are expected to
    1112  be strings in the format "row:column", where 'row' and 'column'
    12   are 1-based integer values up to a specified max number of
    13   rows/columns. If the coordinates are valid they are converted
    14   to 0-bases and returned as a PlateCoordinate instance.
     13  are either A1B1-style or 1-based integer values up to a specified
     14  max number of rows/columns. If the coordinates are valid they are
     15  converted to 0-bases and returned as a PlateCoordinate instance.
    1516 
    1617  @since 4.32
     
    2627 
    2728  /**
     29    Validator for strips with 1 row and 8 columns.
     30    @since 4.33.4
     31  */
     32  public static final PlateWellValidator STRIP_1x8 = new PlateWellValidator(1, 8);
     33 
     34  /**
    2835    Validator fow Qiacube positions which are represented as 6 rows with 2 columns.
    2936  */
    3037  public static final PlateWellValidator QIACUBE = new PlateWellValidator(6, 2);
    3138
    32   private final Pattern pattern;
     39  private final Pattern a1b1Pattern;
     40  private final Pattern numericPattern;
    3341  private final int maxRows;
    3442  private final int maxCols;
     
    3644  public PlateWellValidator(int maxRows, int maxCols)
    3745  {
    38     this.pattern = Pattern.compile("(\\d+)\\:(\\d+)");
     46    this.a1b1Pattern = Pattern.compile("([A-Z]+)\\:(\\d+)");
     47    this.numericPattern = Pattern.compile("(\\d+)\\:(\\d+)");
    3948    this.maxRows = maxRows;
    4049    this.maxCols = maxCols;
     
    4453  public PlateCoordinate isValid(DbControl dc, String value, JsonSection section, String entryKey)
    4554  {
    46     Matcher m = pattern.matcher(value);
    47     if (!m.matches())
     55    Matcher mA1B1 = a1b1Pattern.matcher(value);
     56    int row;
     57    int col;
     58    boolean useA1B1;
     59    if (!mA1B1.matches())
    4860    {
    49       section.addErrorMessage("Invalid plate well in JSON: "+entryKey+"="+value);
    50       return null;
     61      Matcher mNumeric = numericPattern.matcher(value);
     62      if (!mNumeric.matches())
     63      {
     64        section.addErrorMessage("Invalid plate well in JSON: "+entryKey+"="+value);
     65        return null;
     66      }
     67      row = Integer.parseInt(mNumeric.group(1));
     68      col = Integer.parseInt(mNumeric.group(2));
     69      useA1B1 = false;
    5170    }
    52     int row = Integer.parseInt(m.group(1));
    53     int col = Integer.parseInt(m.group(2));
     71    else
     72    {
     73      row = Coordinate.alphaToNumeric(mA1B1.group(1));
     74      col = Integer.parseInt(mA1B1.group(2));
     75      useA1B1 = true;
     76    }   
     77
    5478    boolean valid = true;
    5579    if (row < 1 || row > maxRows)
    5680    {
    57       section.addErrorMessage("Row coordinate "+(row<1?"<1" : ">"+maxRows)+" in JSON: "+entryKey+"="+value);
     81      if (useA1B1)
     82      {
     83        section.addErrorMessage("Row coordinate "+(row<1?"<A" : ">"+Coordinate.numericToAlpha(maxRows))+" in JSON: "+entryKey+"="+value);
     84      }
     85      else
     86      {
     87        section.addErrorMessage("Row coordinate "+(row<1?"<1" : ">"+maxRows)+" in JSON: "+entryKey+"="+value);
     88      }
    5889      valid = false;
    5990    }
  • extensions/net.sf.basedb.reggie/trunk/src/net/sf/basedb/reggie/servlet/ExportServlet.java

    r6336 r6474  
    538538        ReggieRole.checkPermission(dc, "'" + cmd + "' wizard", ReggieRole.PATIENT_CURATOR, ReggieRole.ADMINISTRATOR);
    539539       
     540        String separator = Values.getString(req.getParameter("separator"), "tab");
    540541        String mapFrom = Values.getString(req.getParameter("mapFrom"), "PersonalNo");
    541542        boolean exportCaseId = Values.getBoolean(req.getParameter("exportCaseId"));
     
    544545        boolean sortOutput = Values.getBoolean(req.getParameter("sortOutput"));
    545546
     547        String separatorChar = "\t";
     548        if ("comma".equals(separator))
     549        {
     550          separatorChar = ",";
     551        }
     552        else if ("semicolon".equals(separator))
     553        {
     554          separatorChar = ";";
     555        }
     556       
    546557        SnapshotManager manager = new SnapshotManager();
    547558        List<OutputColumn> outColumns = new ArrayList<>();
     
    605616          String header = uploadReader.readLine();
    606617          long parsedCharacters = header.length()+1;
    607           String[] dataIn = header.split("\t", 2);
    608           if (dataIn.length != 2)
    609           {
    610             throw new IOException("The file need at least 2 header columns");
    611           }
     618          String[] dataIn = header.split(separatorChar, 2);
     619          if (dataIn.length == 2) outColumns.add(new RestOfData(dataIn[1]));
    612620       
    613621          int lastCol = outColumns.size();
    614           Object[] headerOut = new Object[lastCol+1];
     622          Object[] headerOut = new Object[lastCol];
    615623          for (int colNo = 0; colNo < lastCol; colNo++)
    616624          {
    617625            headerOut[colNo] = outColumns.get(colNo).getHeader();
    618626          }
    619           headerOut[lastCol] = dataIn[1];
    620627       
    621628          int lineOut = 0;
     
    631638            progress.display((int)(100*parsedCharacters / totalBytes), "Working... " + inputLine.lineNo + " lines parsed so far...");
    632639           
    633             dataIn = data.split("\t", 2);
    634             if (dataIn.length != 2)
    635             {
    636               throw new IOException("On line " + inputLine.lineNo + ": The file need at least 2 data columns");
    637             }
    638 
    639             inputLine.fromId = Values.getStringOrNull(dataIn[0]);
     640            inputLine.cols = data.split(separatorChar, 2);
     641            inputLine.fromId = Values.getStringOrNull(inputLine.cols[0]);
    640642            if (inputLine.fromId == null)
    641643            {
     
    660662                output[colNo] = outColumns.get(colNo).convert(inputLine);
    661663              }
    662               output[lastCol] = dataIn[1];
    663664              dataOut.add(output);
    664665              lineOut++;
     
    679680          tmpOut = new CipherOutputStream(Application.getStaticCache().write(outputFilePath, 5), cipher);
    680681          tmpWriter = new TableWriter(new OutputStreamWriter(tmpOut, "UTF-8"));
     682          tmpWriter.setDataSeparator(separatorChar);
    681683          tmpWriter.tablePrintData(headerOut);
    682684          for (Object[] outLines : dataOut)
     
    14861488  {
    14871489    int lineNo;
     1490    String[] cols;
    14881491    String fromId;
    14891492    BioSource patient;
     
    16961699 
    16971700  /**
     1701    Get the rest of the data on the line.
     1702    @since 4.33.4
     1703  */
     1704  static class RestOfData
     1705    extends OutputColumn
     1706  {
     1707   
     1708    RestOfData(String restHeader)
     1709    {
     1710      super(restHeader);
     1711    }
     1712   
     1713    @Override
     1714    public String convert(InputLine ctx)
     1715    {
     1716      return ctx.cols.length == 2 ? ctx.cols[1] : null;
     1717    }
     1718  }
     1719 
     1720  /**
    16981721    Get the external (release) ID from the patient.
    16991722  */
  • extensions/net.sf.basedb.reggie/trunk/src/net/sf/basedb/reggie/servlet/InstallServlet.java

    r6461 r6474  
    360360        jsonChecks.add(checkPlateGeometry(dc, Geometry.THREE_BY_TWO, createIfMissing));
    361361        jsonChecks.add(checkPlateGeometry(dc, Geometry.ONE_BY_TWELVE, createIfMissing));
     362        jsonChecks.add(checkPlateGeometry(dc, Geometry.ONE_BY_EIGHT, createIfMissing));
    362363        jsonChecks.add(checkPlateGeometry(dc, Geometry.NINE_BY_NINE, createIfMissing));
    363364        jsonChecks.add(checkPlateGeometry(dc, Geometry.EIGHT_BY_TWELVE, createIfMissing));
     
    375376        jsonChecks.add(checkBioplateType(dc, BioplateType.LIBRARY, createIfMissing));
    376377        jsonChecks.add(checkBioplateType(dc, BioplateType.EXTERNAL_LIBRARY, createIfMissing));
     378        jsonChecks.add(checkBioplateType(dc, BioplateType.EXTERNAL_LIBRARY_STRIP, createIfMissing));
    377379        jsonChecks.add(checkBioplateType(dc, BioplateType.NEOPREP, createIfMissing));
    378380        jsonChecks.add(checkBioplateType(dc, BioplateType.MIPS, createIfMissing));
Note: See TracChangeset for help on using the changeset viewer.