Changeset 3045


Ignore:
Timestamp:
Dec 20, 2006, 3:37:29 PM (17 years ago)
Author:
Nicklas Nordborg
Message:

References #262 and #340. The overview and validation is now complete.
Still missing possibility to save validation options as presets.

Location:
trunk
Files:
4 added
20 edited

Legend:

Unmodified
Added
Removed
  • trunk/doc/development/drafts/experiment_overview.txt

    r3033 r3045  
    4949warnings for each node.
    5050
     51After the first prototype we have found that warnings should be attached to
     52the nodes that has the possibility to correct the warning/error. In most cases
     53this means that the warnings should be attached to: rawbioassay, scan, hybridization,
     54labeled extract, extract, sample, biosource, array slide, array batch and array
     55design. One exception is 'Access denied' warnings that can't be corrected by the
     56logged in user anyway.
     57
     58We will also try to add a list of possible "fixes" to a warning. A fix consists
     59of an explaining text and an item that should be edited.
     60
    5161If an item can't be reached due to a PermissionDeniedException, it should be
    5262displayed as a question mark icon for the item that is linking to it.
     
    6373Warnings:
    6474 - the raw data type is not the same as the project default raw data type
     75   (possible fix: change project default)
     76   (done)
    6577 - the raw bioassays has different array designs
     78   (no fix)
     79   (done)
    6680 - if there is more than one item of the same type and name
    6781   (checked against all items in the project)
     82   (possible fix: rename the item)
     83   (done)
    6884
    6985 
     
    86102 - Protocol
    87103 
    88 Warnnings:
    89  - the raw data type is not the same as the project default raw data type
     104Warnings:
     105 - the raw data type is not the same as the project default raw data type
     106   (possible fix: change project default)
     107   (done)
    90108 - missing array design
     109   (no fix)
     110   (done)
    91111 - missing value for experimental factor
     112   (possible fix: add value or inherit from parent item)
     113   (done)
    92114 - array design is different from array design via hybridization
     115   (possible fix: change array slide of hyb)
     116   (done)
    93117 - missing scan
    94  - missing protocol
     118   (possible fix: add scan)
     119   (done)
     120 - missing protocol
     121   (possible fix: add protocol)
     122   (done)
    95123 - missing software
     124   (possible fix: add software)
     125   (done)
    96126
    97127
     
    100130Subnodes: none
    101131Warnings:
    102  - not same as the project default
    103 
    104  
     132 - not same as the project default (warning is added to parent item)
     133   (possible fix: change project default)
     134   (done)
     135
    105136Protocol
    106137========
     
    112143Warnings:
    113144 - not same as the project default
     145   (possible fix: change protocol, change project default)
     146   (done)
    114147 - incorrect protocol type
     148   (possible fix: change protocol, change protocol type)
     149   (done)
    115150 - missing value for a parameter
    116 
    117 Note! Protocols are always validated together with the item they are attached to
     151   (possible fix: add parameter value)
     152   (done)
     153
     154Note! Protocols are always validated together with the item they are attached
     155to and are added to the parent item
    118156
    119157Annotation
     
    123161Warnings:
    124162 - invalid annotation value according to annotation type
     163   (possible fix: change annotation value)
     164   (done)
    125165 - inheriting value from non-parent
     166   (possible fix: change inherited annotations)
     167   (done)
    126168 - inheriting multiple annotation of the same type (from different parents)
     169   (possible fix: change inherited annotations)
     170   (done)
    127171 - annotation type is a protocol parameter
     172   (possible fix: remove annotation value, remove 'parameter' flag from annotation type)
     173   (done)
    128174 - annotation type is not valid for the current item type
     175   (possible fix: remove annotation value, add item type to annotation type)
     176   (done)
    129177 - missing value for a "Required by MIAME" annotation type (on folder node)
    130 
    131 Note! Annotations are always validated together with the item they are attached to
     178   (possible fix: add annotation value, uncheck the 'Required by MIAME' flag)
     179   (done)
     180
     181Note! Annotations are always validated together with the item they are attached
     182to and the warnnings are added to that item
    132183
    133184Software
    134185========
    135186Subnodes: none
    136 Warnings:
     187Warnings (added to parent item):
    137188 - incorrect software type
     189   (possible fix: change software, change software type)
     190   (done)
     191 - not same as project default
     192   (possible fix: change software, change project default)
     193   (done)
    138194 
    139195Hardware
    140196========
    141197Subnodes: none
    142 Warnings:
     198Warnings (added to parent item):
    143199 - incorrect hardware type
     200   (possible fix: change hardware, change hardware type)
     201   (done)
     202 - not same as project default
     203   (possible fix: change software, change project default)
     204   (done)
    144205 
    145206Scan
     
    156217Warnings:
    157218 - missing scanner
    158  - missing protocol
     219   (possible fix: add scanner)
     220   (done)
     221 - missing protocol
     222   (possible fix: add protocol)
     223   (done)
    159224 - missing hybridization
     225   (possible fix: add hybridization)
     226   (done)
    160227
    161228Hybridization
     
    172239Warnings:
    173240 - missing hybridization station
    174  - missing protocol
     241   (possible fix: add hyb station)
     242   (done)
     243 - missing protocol
     244   (possible fix: add protocol)
     245   (done)
    175246 - missing array slide
     247   (possible fix: add array slide)
     248   (done)
    176249 - wrong number of labeled extracts (checked against experiment raw data type)
     250   (possible fix: add/remove labeled extracts)
     251   (done)
    177252 - the labeled extracts doesn't have unique labels
     253   (possible fix: add/remove labeled extracts, change label of labeled extract)
     254   (done)
    178255 
    179256Array slide
     
    199276Warnings:
    200277 - missing print robot
    201  - missing protocol
    202  
     278   (possible fix: add print robot)
     279   (done)
     280 - missing protocol
     281   (possible fix: add protocol)
     282   (done)
    203283
    204284Labeled extract (non-pooled)
     
    213293Warnings:
    214294 - missing protocol
     295   (possible fix: add protocol)
     296   (done)
    215297 - missing extract
     298   (possible fix: add extract)
     299   (done)
    216300 
    217301Labeled extract (pooled)
     
    226310Warnings:
    227311 - parents use different label
     312   (possible fix: add/remove parents, change label of parents)
     313   (done)
    228314 - missing parents
     315   (possible fix: add parents)
     316   (done)
    229317 - circular reference
     318   (possible fix: add/remove parents)
     319   (done)
    230320 
    231321Extract (non-pooled)
     
    240330Warnings:
    241331 - missing protocol
     332   (possible fix: add protocol)
     333   (done)
    242334 - missing sample
     335   (possible fix: add sample)
     336   (done)
    243337 
    244338Extract (pooled)
     
    253347Warnings:
    254348 - missing protocol
     349   (possible fix: add protocol)
     350   (done)
     351 - missing parents
     352   (possible fix: add parents)
     353   (done)
    255354 - circular reference
     355   (possible fix: add/remove parents)
     356   (done)
    256357 
    257358Sample (non-pooled)
     
    266367Warnings:
    267368 - missing protocol
     369   (possible fix: add protocol)
     370   (done)
    268371 - missing biosource
     372   (possible fix: add biosource)
     373   (done)
    269374
    270375Sample (pooled)
     
    279384Warnings:
    280385 - missing protocol
     386   (possible fix: add protocol)
     387   (done)
     388 - missing parents
     389   (possible fix: add parents)
     390   (done)
    281391 - circular reference
     392   (possible fix: add/remove parents)
     393   (done)
    282394 
    283395Biosource
  • trunk/src/clients/web/net/sf/basedb/clients/web/Base.java

    r2942 r3045  
    948948        {
    949949          AnnotationType at = AnnotationType.getById(dc, annotationTypeId);
    950           Annotation oldAn = oldAs == null ? null : oldAs.getAnnotation(at);
     950          Annotation oldAn = oldAs == null || !oldAs.hasAnnotation(at) ?
     951            null : oldAs.getAnnotation(at);
    951952          Annotation newAn = newAs.getAnnotation(at);
    952953          if (oldAn == null && newAn.isInDatabase() || oldAn != null && oldAn.getValuesVersion() != newAn.getValuesVersion())
  • trunk/src/core/net/sf/basedb/core/Project.java

    r2941 r3045  
    606606  public enum Default
    607607  {   
    608     SOFTWARE("default_software", "Software", Item.SOFTWARE, null),
     608    SOFTWARE("default_software", "Software", Item.SOFTWARE, SoftwareType.FEATURE_EXTRACTION),
    609609    ARRAYDESIGN("default_arraydesign", "Array design", Item.ARRAYDESIGN, null),
    610610    HYBRIDIZATION_HARDWARE("default_hybridization_hardware", "Hybridization station", Item.HARDWARE, HardwareType.HYBRIDIZATION_STATION),
  • trunk/src/core/net/sf/basedb/util/overview/ExperimentOverview.java

    r3033 r3045  
    2626import java.util.Arrays;
    2727import java.util.Collections;
     28import java.util.HashMap;
     29import java.util.HashSet;
    2830import java.util.LinkedHashMap;
    2931import java.util.LinkedList;
    3032import java.util.List;
    3133import java.util.Map;
     34import java.util.Set;
    3235
    3336import net.sf.basedb.core.Annotatable;
     
    3841import net.sf.basedb.core.ArrayDesign;
    3942import net.sf.basedb.core.ArraySlide;
     43import net.sf.basedb.core.BaseException;
    4044import net.sf.basedb.core.BasicItem;
    4145import net.sf.basedb.core.BioSource;
     
    4448import net.sf.basedb.core.Extract;
    4549import net.sf.basedb.core.Hardware;
     50import net.sf.basedb.core.HardwareType;
    4651import net.sf.basedb.core.Hybridization;
    4752import net.sf.basedb.core.Image;
    4853import net.sf.basedb.core.Include;
     54import net.sf.basedb.core.InvalidDataException;
    4955import net.sf.basedb.core.Item;
    5056import net.sf.basedb.core.ItemQuery;
    5157import net.sf.basedb.core.Label;
    5258import net.sf.basedb.core.LabeledExtract;
     59import net.sf.basedb.core.Nameable;
    5360import net.sf.basedb.core.PermissionDeniedException;
    5461import net.sf.basedb.core.Project;
    5562import net.sf.basedb.core.Protocol;
     63import net.sf.basedb.core.ProtocolType;
    5664import net.sf.basedb.core.RawBioAssay;
    5765import net.sf.basedb.core.Sample;
     
    5967import net.sf.basedb.core.SessionControl;
    6068import net.sf.basedb.core.Software;
     69import net.sf.basedb.core.SoftwareType;
     70import net.sf.basedb.core.Type;
     71import net.sf.basedb.core.query.Expressions;
    6172import net.sf.basedb.core.query.Hql;
    6273import net.sf.basedb.core.query.Orders;
     74import net.sf.basedb.core.query.Restrictions;
    6375
    6476/**
     
    8597{
    8698
    87   public static final Validator PROJECT_DEFAULT_VALIDATOR = new Validator(
    88     "project.usenondefault", "Use of non-default value",
    89     "Checks if a property is the same as the default specified for the active project",
    90     "Use of non-default value", Severity.WARNING
    91   );
    92  
    9399  private static Map<String, List<Validator>> validators;
    94100
     
    101107          Arrays.asList(new Validator[]
    102108          {
    103             PROJECT_DEFAULT_VALIDATOR
     109            Validator.NONDEFAULT_RAWDATATYPE, Validator.NONDEFAULT_ARRAYDESIGN,
     110            Validator.NONDEFAULT_PROTOCOL, Validator.NONDEFAULT_HARDWARE,
     111            Validator.NONDEFAULT_SOFTWARE
    104112          })
    105113        );
     
    108116          {
    109117            Validator.MISSING_BIOSOURCE, Validator.MISSING_SAMPLE, Validator.MISSING_EXTRACT,
    110             Validator.MISSING_HYBRIDIZATION, Validator.MISSING_SCAN, Validator.MISSING_ARRAYDESIGN,
    111             Validator.MISSING_PROTOCOL, Validator.MISSING_HARDWARE, Validator.MISSING_SOFTWARE,
    112             Validator.MISSING_ARRAYSLIDE
     118            Validator.MISSING_LABELED_EXTRACT, Validator.MISSING_HYBRIDIZATION,
     119            Validator.MISSING_SCAN, Validator.MISSING_ARRAYDESIGN, Validator.MISSING_PROTOCOL,
     120            Validator.MISSING_HARDWARE, Validator.MISSING_SOFTWARE,
     121            Validator.MISSING_ARRAYSLIDE, Validator.MISSING_ARRAYBATCH
    113122          })
    114123        );
    115       temp.put("Missing annotations",
     124      temp.put("Annotations",
    116125          Arrays.asList(new Validator[]
    117126          {
    118127            Validator.MISSING_MIAME_ANNOTATION, Validator.MISSING_FACTORVALUE,
    119             Validator.MISSING_PARAMETER
     128            Validator.MISSING_PARAMETER, Validator.ANNOTATION_IS_PARAMETER,
     129            Validator.ANNOTATION_INVALID_VALUE, Validator.ANNOTATION_INVALID_ITEM,
     130            Validator.ANNOTATION_INHERIT_FROM_NONPARENT, Validator.ANNOTATION_INHERIT_MULTIPLE
    120131          })
    121132        );
     133     
     134      temp.put("Denied access",
     135          Arrays.asList(new Validator[]
     136           {
     137            Validator.DENIED_BIOSOURCE, Validator.DENIED_SAMPLE, Validator.DENIED_EXTRACT,
     138            Validator.DENIED_LABEL, Validator.DENIED_HYBRIDIZATION, Validator.DENIED_SCAN,
     139            Validator.DENIED_ARRAYDESIGN, Validator.DENIED_PROTOCOL, Validator.DENIED_HARDWARE,
     140            Validator.DENIED_SOFTWARE, Validator.DENIED_ARRAYSLIDE, Validator.DENIED_ARRAYBATCH
     141           })
     142        );
     143     
     144      temp.put("Other",
     145          Arrays.asList(new Validator[]
     146          {
     147            Validator.NONMATHCING_ARRAYDESIGN, Validator.MULTIPLE_ARRAYDESIGNS,
     148            Validator.INCORRECT_PROTOCOLTYPE, Validator.INCORRECT_SOFTWARETYPE,
     149            Validator.INCORRECT_HARDWARETYPE, Validator.INCORRECT_NUM_LABELEDEXTRACTS,
     150            Validator.NONUNIQUE_LABEL, Validator.DIFFERENT_LABEL,
     151            Validator.NONUNIQUE_NAME_FOR_TYPE, Validator.NONUNIQUE_NAME_GLOBAL,
     152            Validator.CIRCULAR_REFERENCE
     153          })
     154        );
     155     
    122156      validators = Collections.unmodifiableMap(temp);
    123157    }
     
    161195  private ValidationOptions validationOptions;
    162196  private List<Failure> failures;
     197  private Map<String, Node> allNodes;
     198  private Map<Item, Set<AnnotationType>> miameAnnotations;
     199  private Map<Annotatable, Set<Annotatable>> annotatableParents;
    163200 
    164201  /**
     
    187224  {
    188225    this.experiment = Experiment.getById(dc, experiment.getId());
    189     this.project = Project.getById(dc, project.getId());
     226    this.project = project == null ? null : Project.getById(dc, project.getId());
    190227    generateOverview(dc);
    191228  }
     
    197234  {
    198235    this.failures = new LinkedList<Failure>();
     236    this.annotatableParents = new HashMap<Annotatable, Set<Annotatable>>();
     237   
     238    // Load 'Required for MIAME' annotation types
     239    ItemQuery<AnnotationType> query = initQuery(AnnotationType.getQuery(null), "name");
     240    query.restrict(
     241      Restrictions.eq(
     242        Hql.property("requiredForMiame"),
     243        Expressions.parameter("flag", true, Type.BOOLEAN)
     244      )
     245    );
     246    this.miameAnnotations = new HashMap<Item, Set<AnnotationType>>();
     247    for (AnnotationType at : query.list(dc))
     248    {
     249      for (Item itemType : at.getEnabledItems())
     250      {
     251        Set<AnnotationType> types = miameAnnotations.get(itemType);
     252        if (types == null)
     253        {
     254          types = new HashSet<AnnotationType>();
     255          miameAnnotations.put(itemType, types);
     256        }
     257        types.add(at);
     258      }
     259    }
    199260   
    200261    // Node and subnodes
     
    208269      if (experiment.getRawDataType() != project.getDefaultRawDataType())
    209270      {
    210         failures.add(new Failure(PROJECT_DEFAULT_VALIDATOR, rootNode));
    211       }
    212     }
     271        failures.add(
     272          new Failure(Validator.NONDEFAULT_RAWDATATYPE, rootNode, null,
     273            new Fix("Change default raw data type of project", project)
     274          )
     275        );
     276      }
     277    }
     278   
     279    this.allNodes = new HashMap<String, Node>();
     280    allNodes.put(rootNode.getId(), rootNode);
     281    cacheChildNodes(rootNode);
     282
     283    // Validate the names of items
     284    Map<String, Map<Item, List<Node>>> names = new HashMap<String, Map<Item, List<Node>>>();
     285    Set<Node> nonUniqueGlobal = new HashSet<Node>();
     286    Set<Node> nonUniqueForType = new HashSet<Node>();
     287    for (Node node : allNodes.values())
     288    {
     289      if (node.getNodeType() == Node.Type.ITEM)
     290      {
     291        BasicItem item = node.getItem();
     292        if (item instanceof Nameable)
     293        {
     294          String name = ((Nameable)item).getName();
     295          Map<Item, List<Node>> typeMap = names.get(name);
     296          if (typeMap != null)
     297          {
     298            List<Node> otherNodes = typeMap.get(item.getType());
     299            if (otherNodes != null)
     300            {
     301              // Possible non-unique match; but check for self-match
     302              if (!item.equals(otherNodes.get(0).getItem()))
     303              {
     304                nonUniqueForType.add(node);
     305                for (Node otherNode : otherNodes)
     306                {
     307                  nonUniqueForType.add(otherNode);
     308                }
     309              }
     310              else
     311              {
     312                otherNodes.add(node);
     313              }
     314            }
     315            else
     316            {
     317              nonUniqueGlobal.add(node);
     318              if (typeMap.size() == 1)
     319              {
     320                nonUniqueGlobal.add(typeMap.values().iterator().next().get(0));
     321              }
     322              List<Node> nodeList = new LinkedList<Node>();
     323              nodeList.add(node);
     324              typeMap.put(item.getType(), nodeList);
     325            }
     326          }
     327          else
     328          {
     329            List<Node> nodeList = new LinkedList<Node>();
     330            nodeList.add(node);
     331            typeMap = new HashMap<Item, List<Node>>();
     332            typeMap.put(item.getType(), nodeList);
     333            names.put(name, typeMap);
     334          }
     335        }
     336      }
     337    }
     338    names.clear();
     339   
     340    // Non-unique of same type
     341    for (Node node : nonUniqueForType)
     342    {
     343      failures.add(new Failure(Validator.NONUNIQUE_NAME_FOR_TYPE, node, null,
     344        new Fix("Change name of item", node.getItem())
     345      ));
     346    }
     347    nonUniqueForType.clear();
     348   
     349    // Non-unique of different types
     350    for (Node node : nonUniqueGlobal)
     351    {
     352      failures.add(new Failure(Validator.NONUNIQUE_NAME_GLOBAL, node, null,
     353        new Fix("Change name of item", node.getItem())
     354      ));
     355    }
     356    nonUniqueGlobal.clear();
     357
    213358    updateFailureCountOnNodes();
    214359  }
     
    228373  {
    229374    return project;
     375  }
     376 
     377  /**
     378    Get the annotation types that have the 'Required for MIAME' flag
     379    set to true and is enabled for the specified item type.
     380    @param itemType The item type
     381    @return An set containing the annotation types or null if no annotation
     382      types exists
     383  */
     384  public Set<AnnotationType> getMiameAnnotationTypes(Item itemType)
     385  {
     386    return miameAnnotations.get(itemType);
     387  }
     388 
     389  public Set<Annotatable> getAnnotatableParents(Annotatable item)
     390  {
     391    Set<Annotatable> parents = annotatableParents.get(item);
     392    if (parents == null)
     393    {
     394      parents = new HashSet<Annotatable>();
     395      annotatableParents.put(item, parents);
     396      Set<Annotatable> temp = item.getAnnotatableParents();
     397      if (temp != null)
     398      {
     399        for (Annotatable a : temp)
     400        {
     401          parents.add(a);
     402          parents.addAll(getAnnotatableParents(a));
     403        }
     404      }
     405    }
     406    return parents;
    230407  }
    231408 
     
    269446      }
    270447    }
     448  }
     449 
     450  private void cacheChildNodes(Node node)
     451  {
     452    if (node.getChildren() != null)
     453    {
     454      for (Node child : node.getChildren())
     455      {
     456        allNodes.put(child.getId(), child);
     457        cacheChildNodes(child);
     458      }
     459    }
     460  }
     461 
     462  public Node getNode(String nodeId)
     463  {
     464    return allNodes.get(nodeId);
    271465  }
    272466 
     
    314508    Experiment experiment = (Experiment)rootNode.getItem();
    315509    ItemQuery<RawBioAssay> rbaQuery = initQuery(experiment.getRawBioAssays(), "name");
     510    Set<BasicItem> arrayDesigns = new HashSet<BasicItem>();
    316511    for (RawBioAssay rba : rbaQuery.list(dc))
    317512    {
    318       addRawBioAssay(dc, rawBioAssaysNode, rba);
    319     }
     513      Node rbaNode = addRawBioAssay(dc, rawBioAssaysNode, rba);
     514      Node adNode = rbaNode.getChild("arraydesign");
     515      arrayDesigns.add(adNode == null ? null : adNode.getItem());
     516    }
     517   
     518    // Check if all raw bioassays use the same array design
     519    if (arrayDesigns.size() > 1)
     520    {
     521      failures.add(new Failure(Validator.MULTIPLE_ARRAYDESIGNS, rootNode));
     522    }
     523   
    320524    return rawBioAssaysNode;
    321525  }
     
    329533  {
    330534    Node rbaNode = new Node("rawbioassay."+rba.getId(), rba.getName(), rawBioAssaysNode, rba);
    331     addAnnotations(dc, rbaNode);
    332     addArrayDesign(dc, rbaNode);
    333     addScan(dc, rbaNode);
     535    Node annotationsNode = addAnnotations(dc, rbaNode);
     536    Node adNode = addArrayDesign(dc, rbaNode);
     537    Node scanNode = addScan(dc, rbaNode);
    334538    addSoftware(dc, rbaNode);
    335     addProtocol(dc, rbaNode);
     539    addProtocol(dc, rbaNode, Project.Default.FEATURE_EXTRACTION_PROTOCOL);
     540   
     541    // Check for project default raw data type
     542    if (project != null)
     543    {
     544      if (rba.getRawDataType() != project.getDefaultRawDataType())
     545      {
     546        failures.add(
     547          new Failure(Validator.NONDEFAULT_RAWDATATYPE, rbaNode, null,
     548            new Fix("Change default raw data type of project", project)
     549          )
     550        );
     551      }
     552    }
     553   
     554    // Check for missing experimental factor values
     555    Node efNode = rootNode.getChild("experimental.factors");
     556    if (efNode != null && efNode.getChildren() != null)
     557    {
     558      for (Node factorNode : efNode.getChildren())
     559      {
     560        Node annotationNode = annotationsNode.getChild("annotationtype." + factorNode.getItem().getId());
     561        if (annotationNode == null)
     562        {
     563          AnnotationType at = (AnnotationType)factorNode.getItem();
     564          Fix addFactor = at.isEnabledForItem(Item.RAWBIOASSAY) ?
     565            new Fix("Add value to experimental factor", rba, at, false) :
     566            new Fix("Inherit annotation from a parent item", rba, at, true);
     567          failures.add(new Failure(Validator.MISSING_FACTORVALUE, rbaNode,
     568            "Missing factor value for " + at.getName(), addFactor));
     569        }
     570      }
     571    }
     572
     573    // Check that the array design is same as hybridizations array design
     574    Scan scan = scanNode == null ? null : (Scan)scanNode.getItem();
     575    if (scan != null)
     576    {
     577      BasicItem ad1 = adNode == null ? null : adNode.getItem();
     578      try
     579      {
     580        BasicItem ad2 = scan.getArrayDesign();
     581        if ((ad1 == null && ad2 != null) || (ad1 != null && !ad1.equals(ad2)))
     582        {
     583          Fix fix = null;
     584          try
     585          {
     586            Hybridization hyb = scan.getHybridization();
     587            if (hyb != null) fix = new Fix("Change array slide of hybridization", hyb);
     588          }
     589          catch (PermissionDeniedException ex)
     590          {}
     591          failures.add(new Failure(Validator.NONMATHCING_ARRAYDESIGN, rbaNode, null,
     592            fix));
     593        }
     594      }
     595      catch (PermissionDeniedException ex)
     596      {}
     597    }
     598   
    336599    return rbaNode;
    337600  }
     
    360623    {
    361624      adNode = new Node("arraydesign", "Array design: denied", parentNode, null);
     625      failures.add(new Failure(Validator.DENIED_ARRAYDESIGN, adNode));
    362626    }
    363627    if (ad != null)
    364628    {
    365629      adNode = new Node("arraydesign", "Array design: " + ad.getName(), parentNode, ad);
     630     
     631      // Check if the array design is the same as the project default
     632      if (project != null)
     633      {
     634        try
     635        {
     636          BasicItem defaultItem = project.getDefaultItem(dc, Project.Default.ARRAYDESIGN);
     637          if (defaultItem != null && !ad.equals(defaultItem))
     638          {
     639            failures.add(new Failure(Validator.NONDEFAULT_ARRAYDESIGN, parentNode, null,
     640              new Fix("Change default array design for project", project)));
     641          }
     642        }
     643        catch (BaseException ex)
     644        {}
     645      }
    366646    }
    367647    if (adNode == null)
     
    388668    {
    389669      scanNode = new Node("scan", "Scan: denied", rawBioAssayNode, null);
     670      failures.add(new Failure(Validator.DENIED_SCAN, scanNode));
    390671    }
    391672    if (scan != null)
     
    397678      addHardware(dc, scanNode, "Scanner");
    398679      addHybridization(dc, scanNode);
    399       addProtocol(dc, scanNode);
     680      addProtocol(dc, scanNode, Project.Default.SCANNING_PROTOCOL);
    400681    }
    401682    if (scanNode == null)
    402683    {
    403       failures.add(new Failure(Validator.MISSING_SCAN, rawBioAssayNode));
     684      failures.add(new Failure(Validator.MISSING_SCAN, rawBioAssayNode, null,
     685        new Fix("Add scan to raw bioassay", rba)));
    404686    }
    405687    return scanNode;
     
    422704    {
    423705      hybNode = new Node("hybridization", "Hybridization: denied", scanNode, null);
     706      failures.add(new Failure(Validator.DENIED_HYBRIDIZATION, hybNode));
    424707    }
    425708    if (scan != null)
     
    429712      addLabeledExtracts(dc, hybNode);
    430713      addHardware(dc, hybNode, "Hyb. station");
    431       addProtocol(dc, hybNode);
     714      addProtocol(dc, hybNode, Project.Default.HYBRIDIZATION_PROTOCOL);
    432715      addArraySlide(dc, hybNode);
    433716    }
    434717    if (hybNode == null)
    435718    {
    436       failures.add(new Failure(Validator.MISSING_HYBRIDIZATION, scanNode));
     719      failures.add(new Failure(Validator.MISSING_HYBRIDIZATION, scanNode, null,
     720        new Fix("Add hybridization to scan", scan)));
    437721    }
    438722    return hybNode;
     
    479763    ItemQuery<LabeledExtract> leQuery =
    480764      (ItemQuery<LabeledExtract>)initQuery(hyb.getCreationEvent().getSources(), "label.name");
     765    int added = 0;
     766    int channels = experiment.getRawDataType().getChannels();
     767
     768    Map<Label, LabeledExtract> labels = new HashMap<Label, LabeledExtract>();
     769    Set<LabeledExtract> nonUnique = new HashSet<LabeledExtract>();
    481770    for (LabeledExtract le : leQuery.list(dc))
    482771    {
    483       addLabeledExtract(dc, leNode, le);
     772      Node llNode = addLabeledExtract(dc, leNode, le);
     773      ++added;
     774      try
     775      {
     776        Label l = le.getLabel();
     777        if (labels.containsKey(l))
     778        {
     779          nonUnique.add(le);
     780          nonUnique.add(labels.get(l));
     781        }
     782        else
     783        {
     784          labels.put(l, le);
     785        }
     786      }
     787      catch (PermissionDeniedException ex)
     788      {}
     789    }
     790   
     791    // Check number of labeled extracts
     792    if (added != channels)
     793    {
     794      Fix fix = added > channels ?
     795        new Fix("Remove labeled extracts from hybridization", hyb) :
     796        new Fix("Add labeled extracts to hybridization", hyb);
     797      String message = added > channels ?
     798        "Too many labeled extracts" : "Too few labeled extracts";
     799      failures.add(new Failure(Validator.INCORRECT_NUM_LABELEDEXTRACTS, hybNode, message, fix));
     800    }
     801   
     802    // Check that labeled extracts has unique labels
     803    if (nonUnique.size() > 0)
     804    {
     805      Failure failure = new Failure(Validator.NONUNIQUE_LABEL, hybNode);
     806      failure.addFix(new Fix("Change labeled extracts on hybridization", hyb));
     807      for (LabeledExtract le : nonUnique)
     808      {
     809        failure.addFix(new Fix("Change label of " + le.getName(), le));
     810      }
     811      failures.add(failure);
    484812    }
    485813    return leNode;
     
    501829    {}
    502830    Node leNode = new Node("labeledextract."+le.getId(),
    503       (label != null ? le.getName() + ": " : "") + le.getName(), parentNode, le);
     831      (label != null ? label.getName() + ": " : "") + le.getName(), parentNode, le);
     832   
     833    if (label == null)
     834    {
     835      failures.add(new Failure(Validator.DENIED_LABEL, leNode));
     836    }
    504837   
    505838    addAnnotations(dc, leNode);
    506839    if (le.isPooled())
    507840    {
    508       // addPooledLabledExtracts(dc, leNode);
     841      addPooledLabeledExtracts(dc, leNode);
    509842    }
    510843    else
     
    512845      addExtract(dc, leNode, null);
    513846    }
    514     addProtocol(dc, leNode);
     847    addProtocol(dc, leNode, Project.Default.LABELING_PROTOCOL);
    515848    return leNode;
     849  }
     850 
     851  /**
     852    Add labeled extract child nodes that are the source labeled
     853    extracts of a pooled labeled extract
     854  */
     855  @SuppressWarnings("unchecked")
     856  private void addPooledLabeledExtracts(DbControl dc, Node parentNode)
     857  {
     858    LabeledExtract product = (LabeledExtract)parentNode.getItem();
     859    Label productLabel = null;
     860    try
     861    {
     862      productLabel = product.getLabel();
     863    }
     864    catch (PermissionDeniedException ex)
     865    {}
     866   
     867    ItemQuery<LabeledExtract> sourceQuery =
     868      initQuery((ItemQuery<LabeledExtract>)product.getCreationEvent().getSources(), "name");
     869   
     870    int added = 0;
     871    for (LabeledExtract source : sourceQuery.list(dc))
     872    {
     873      ++added;
     874
     875      // Check circular reference
     876      boolean circular = false;
     877      Node tempNode = parentNode;
     878      BasicItem tempItem = tempNode.getItem();
     879      while (tempNode != null && tempItem != null && tempItem.getType() == Item.LABELEDEXTRACT)
     880      {
     881        if (source.equals(tempItem))
     882        {
     883          failures.add(new Failure(Validator.CIRCULAR_REFERENCE, parentNode,
     884            "Circular reference to " + ((LabeledExtract)tempItem).getName(),
     885            new Fix("Modify source labeled extracts", product)
     886          ));
     887          tempNode = null;
     888          tempItem = null;
     889          circular = true;
     890        }
     891        else
     892        {
     893          tempNode = tempNode.getParent();
     894          tempItem = tempNode.getItem();
     895        }
     896      }
     897     
     898      if (!circular)
     899      {
     900        Node leNode = addLabeledExtract(dc, parentNode, source);
     901       
     902        // Check that source has same label as product
     903        if (productLabel != null)
     904        {
     905          try
     906          {
     907            Label label = source.getLabel();
     908            if (!productLabel.equals(label))
     909            {
     910              failures.add(new Failure(Validator.DIFFERENT_LABEL, leNode, null,
     911                new Fix("Change label of " + source.getName(), source),
     912                new Fix("Change label of " + product.getName(), product)
     913                ));
     914            }
     915          }
     916          catch (PermissionDeniedException ex)
     917          {}
     918        }
     919      }
     920    }
     921   
     922    if (added == 0)
     923    {
     924      failures.add(new Failure(Validator.MISSING_LABELED_EXTRACT, parentNode, null,
     925        new Fix("Add sources to the labeled extract", product)
     926      ));
     927    }
     928   
    516929  }
    517930 
     
    533946      {
    534947        extractNode = new Node("extract", "Extract: denied", parentNode, null);
     948        failures.add(new Failure(Validator.DENIED_EXTRACT, extractNode));
    535949      }
    536950      if (extract != null)
     
    550964      if (extract.isPooled())
    551965      {
    552         // addPooledExtracts(dc, leNode);
     966        addPooledExtracts(dc, extractNode);
    553967      }
    554968      else
     
    556970        addSample(dc, extractNode, null);
    557971      }
    558       addProtocol(dc, extractNode);
     972      addProtocol(dc, extractNode, Project.Default.EXTRACTING_PROTOCOL);
    559973    }
    560974    if (extractNode == null)
    561975    {
    562       failures.add(new Failure(Validator.MISSING_EXTRACT, parentNode));
     976      failures.add(new Failure(Validator.MISSING_EXTRACT, parentNode, null,
     977        new Fix("Add extract to labeled extract", parentNode.getItem())));
    563978    }
    564979    return extractNode;
     980  }
     981 
     982  /**
     983    Add extract child nodes that are the source extracts of a pooled extract.
     984  */
     985  @SuppressWarnings("unchecked")
     986  private void addPooledExtracts(DbControl dc, Node parentNode)
     987  {
     988    Extract product = (Extract)parentNode.getItem();
     989   
     990    ItemQuery<Extract> sourceQuery =
     991      initQuery((ItemQuery<Extract>)product.getCreationEvent().getSources(), "name");
     992   
     993    int added = 0;
     994    for (Extract source : sourceQuery.list(dc))
     995    {
     996      ++added;
     997 
     998      // Check circular reference
     999      boolean circular = false;
     1000      Node tempNode = parentNode;
     1001      BasicItem tempItem = tempNode.getItem();
     1002      while (tempNode != null && tempItem != null && tempItem.getType() == Item.EXTRACT)
     1003      {
     1004        if (source.equals(tempItem))
     1005        {
     1006          failures.add(new Failure(Validator.CIRCULAR_REFERENCE, parentNode,
     1007            "Circular reference to " + ((Extract)tempItem).getName(),
     1008            new Fix("Modify source extracts", product)
     1009          ));
     1010          tempNode = null;
     1011          tempItem = null;
     1012          circular = true;
     1013        }
     1014        else
     1015        {
     1016          tempNode = tempNode.getParent();
     1017          tempItem = tempNode.getItem();
     1018        }
     1019      }
     1020     
     1021      if (!circular)
     1022      {
     1023        Node extractNode = addExtract(dc, parentNode, source);
     1024      }
     1025    }
     1026   
     1027    if (added == 0)
     1028    {
     1029      failures.add(new Failure(Validator.MISSING_EXTRACT, parentNode, null,
     1030        new Fix("Add sources to the extract", product)
     1031      ));
     1032    }
    5651033  }
    5661034 
     
    5821050      {
    5831051        sampleNode = new Node("sample", "Sample: denied", parentNode, null);
     1052        failures.add(new Failure(Validator.DENIED_SAMPLE, sampleNode));
    5841053      }
    5851054      if (extract != null)
     
    5991068      if (sample.isPooled())
    6001069      {
    601         // addPooledSamples(dc, leNode);
     1070        addPooledSamples(dc, sampleNode);
    6021071      }
    6031072      else
     
    6051074        addBioSource(dc, sampleNode);
    6061075      }
    607       addProtocol(dc, sampleNode);
     1076      addProtocol(dc, sampleNode, Project.Default.SAMPLING_PROTOCOL);
    6081077    }
    6091078    if (sampleNode == null)
    6101079    {
    611       failures.add(new Failure(Validator.MISSING_SAMPLE, parentNode));
     1080      failures.add(new Failure(Validator.MISSING_SAMPLE, parentNode, null,
     1081        new Fix("Add sample to extract", parentNode.getItem())));
    6121082    }
    6131083    return sampleNode;
     1084  }
     1085 
     1086  /**
     1087    Add sample child nodes that are the source samples of a pooled sample.
     1088  */
     1089  @SuppressWarnings("unchecked")
     1090  private void addPooledSamples(DbControl dc, Node parentNode)
     1091  {
     1092    Sample product = (Sample)parentNode.getItem();
     1093   
     1094    ItemQuery<Sample> sourceQuery =
     1095      initQuery((ItemQuery<Sample>)product.getCreationEvent().getSources(), "name");
     1096   
     1097    int added = 0;
     1098    for (Sample source : sourceQuery.list(dc))
     1099    {
     1100      ++added;
     1101 
     1102      // Check circular reference
     1103      boolean circular = false;
     1104      Node tempNode = parentNode;
     1105      BasicItem tempItem = tempNode.getItem();
     1106      while (tempNode != null && tempItem != null && tempItem.getType() == Item.SAMPLE)
     1107      {
     1108        if (source.equals(tempItem))
     1109        {
     1110          failures.add(new Failure(Validator.CIRCULAR_REFERENCE, parentNode,
     1111            "Circular reference to " + ((Sample)tempItem).getName(),
     1112            new Fix("Modify source samples", product)
     1113          ));
     1114          tempNode = null;
     1115          tempItem = null;
     1116          circular = true;
     1117        }
     1118        else
     1119        {
     1120          tempNode = tempNode.getParent();
     1121          tempItem = tempNode.getItem();
     1122        }
     1123      }
     1124     
     1125      if (!circular)
     1126      {
     1127        Node sampleNode = addSample(dc, parentNode, source);
     1128      }
     1129    }
     1130   
     1131    if (added == 0)
     1132    {
     1133      failures.add(new Failure(Validator.MISSING_SAMPLE, parentNode, null,
     1134        new Fix("Add sources to the sample", product)
     1135      ));
     1136    }
    6141137  }
    6151138 
     
    6301153    {
    6311154      bioSourceNode = new Node("biosource", "Biosource: denied", sampleNode, null);
     1155      failures.add(new Failure(Validator.DENIED_BIOSOURCE, bioSourceNode));
    6321156    }
    6331157    if (bioSource != null)
     
    6381162    if (bioSourceNode == null)
    6391163    {
    640       failures.add(new Failure(Validator.MISSING_BIOSOURCE, sampleNode));
     1164      failures.add(new Failure(Validator.MISSING_BIOSOURCE, sampleNode, null,
     1165        new Fix("Add biosource to sample", sampleNode.getItem())));
    6411166    }
    6421167    return bioSourceNode;
     
    6591184    {
    6601185      slideNode = new Node("slide", "Array slide: denied", hybNode, null);
     1186      failures.add(new Failure(Validator.DENIED_ARRAYSLIDE, slideNode));
    6611187    }
    6621188    if (slide != null)
     
    6681194    if (slideNode == null)
    6691195    {
    670       failures.add(new Failure(Validator.MISSING_ARRAYSLIDE, hybNode));
     1196      failures.add(new Failure(Validator.MISSING_ARRAYSLIDE, hybNode, null,
     1197        new Fix("Add array slide to hybridization", hyb)));
    6711198    }
    6721199    return slideNode;
     
    6891216    {
    6901217      batchNode = new Node("batch", "Batch: denied", slideNode, null);
     1218      failures.add(new Failure(Validator.DENIED_ARRAYBATCH, batchNode));
    6911219    }
    6921220    if (batch != null)
     
    6961224      addArrayDesign(dc, batchNode);
    6971225      addHardware(dc, batchNode, "Print robot");
    698       addProtocol(dc, batchNode);
     1226      addProtocol(dc, batchNode, Project.Default.PRINTING_PROTOCOL);
     1227    }
     1228    if (batchNode == null)
     1229    {
     1230      failures.add(new Failure(Validator.MISSING_ARRAYBATCH, slideNode));
    6991231    }
    7001232    return batchNode;
     
    7101242    Software software = null;
    7111243    Node softwareNode = null;
     1244    Project.Default projectDefault = null;
    7121245    try
    7131246    {
     
    7151248      {
    7161249        software = ((RawBioAssay)item).getSoftware();
     1250        projectDefault = Project.Default.SOFTWARE;
    7171251      }
    7181252    }
     
    7201254    {
    7211255      softwareNode = new Node("software", "Software: denied", parentNode, null);
     1256      failures.add(new Failure(Validator.DENIED_SOFTWARE, softwareNode));
    7221257    }
    7231258    if (software != null)
    7241259    {
    7251260      softwareNode = new Node("software", "Software: " + software.getName(), parentNode, software);
     1261
     1262      // Check if using project default software
     1263      if (project != null && projectDefault != null)
     1264      {
     1265        try
     1266        {
     1267          BasicItem defaultItem = project.getDefaultItem(dc, projectDefault);
     1268          if (defaultItem != null && !software.equals(defaultItem))
     1269          {
     1270            failures.add(new Failure(Validator.NONDEFAULT_SOFTWARE, parentNode, null,
     1271                new Fix("Change software of raw bioassay", item),
     1272                new Fix("Change default software of project", project)
     1273              ));
     1274          }
     1275        }
     1276        catch (BaseException ex)
     1277        {}
     1278      }
     1279     
     1280      // Check hardware type
     1281      try
     1282      {
     1283        SoftwareType st = software.getSoftwareType();
     1284        if (!st.getSystemId().equals(projectDefault.getType()))
     1285        {
     1286          failures.add(new Failure(Validator.INCORRECT_SOFTWARETYPE, parentNode, null,
     1287            new Fix("Change software of raw bioassay", item),
     1288            new Fix("Change type of software", software)
     1289          ));
     1290        }
     1291      }
     1292      catch (PermissionDeniedException ex)
     1293      {}
     1294     
    7261295    }
    7271296    if (softwareNode == null)
    7281297    {
    729       failures.add(new Failure(Validator.MISSING_SOFTWARE, parentNode));
     1298      failures.add(new Failure(Validator.MISSING_SOFTWARE, parentNode, null,
     1299        new Fix("Add software to raw bioassay", item)));
    7301300    }
    7311301    return softwareNode;
     
    7391309  {
    7401310    BasicItem item = parentNode.getItem();
     1311    String itemTypeName = item.getType().toString().toLowerCase();
    7411312    Hardware hardware = null;
    7421313    Node hardwareNode = null;
     1314    Project.Default projectDefault = null;
    7431315    try
    7441316    {
     
    7471319      {
    7481320        hardware = ((Scan)item).getScanner();
     1321        projectDefault = Project.Default.SCANNER_HARDWARE;
    7491322      }
    7501323      else if (itemType == Item.HYBRIDIZATION)
    7511324      {
    7521325        hardware = ((Hybridization)item).getCreationEvent().getHardware();
     1326        projectDefault = Project.Default.HYBRIDIZATION_HARDWARE;
    7531327      }
    7541328      else if (itemType == Item.ARRAYBATCH)
    7551329      {
    7561330        hardware = ((ArrayBatch)item).getPrintRobot();
     1331        projectDefault = Project.Default.PRINTROBOT_HARDWARE;
    7571332      }
    7581333    }
     
    7601335    {
    7611336      hardwareNode = new Node("hardware", hardwareType + ": denied", parentNode, null);
     1337      failures.add(new Failure(Validator.DENIED_HARDWARE, hardwareNode));
    7621338    }
    7631339    if (hardware != null)
    7641340    {
    7651341      hardwareNode = new Node("hardware", hardwareType + ": " + hardware.getName(), parentNode, hardware);
     1342     
     1343      // Check if using project default hardware
     1344      if (project != null && projectDefault != null)
     1345      {
     1346        try
     1347        {
     1348          BasicItem defaultItem = project.getDefaultItem(dc, projectDefault);
     1349          if (defaultItem != null && !hardware.equals(defaultItem))
     1350          {
     1351            failures.add(new Failure(Validator.NONDEFAULT_HARDWARE, parentNode, null,
     1352              new Fix("Change " + hardwareType.toLowerCase() + " of " + itemTypeName, item),
     1353              new Fix("Change default " + hardwareType.toLowerCase() + " of project", project)
     1354            ));
     1355          }
     1356        }
     1357        catch (BaseException ex)
     1358        {}
     1359      }
     1360     
     1361      // Check hardware type
     1362      try
     1363      {
     1364        HardwareType ht = hardware.getHardwareType();
     1365        if (!ht.getSystemId().equals(projectDefault.getType()))
     1366        {
     1367          failures.add(new Failure(Validator.INCORRECT_HARDWARETYPE, parentNode, null,
     1368            new Fix("Change " + hardwareType + " of " + itemTypeName, item),
     1369            new Fix("Change type of " + hardwareType, hardware)
     1370          ));
     1371        }
     1372      }
     1373      catch (PermissionDeniedException ex)
     1374      {}
     1375
    7661376    }
    7671377    if (hardwareNode == null)
    7681378    {
    769       failures.add(new Failure(Validator.MISSING_HARDWARE, parentNode));
     1379      failures.add(new Failure(Validator.MISSING_HARDWARE, parentNode, null,
     1380        new Fix("Add " + hardwareType.toLowerCase() + " to " + item.getType().toString().toLowerCase(), item)));
    7701381    }
    7711382    return hardwareNode;
     
    7761387    Creates an item-type node with the name <code>protocol</code>.
    7771388  */
    778   private Node addProtocol(DbControl dc, Node parentNode)
     1389  private Node addProtocol(DbControl dc, Node parentNode, Project.Default defaultProtocol)
    7791390  {
    7801391    BasicItem item = parentNode.getItem();
     
    7911402    {
    7921403      protocolNode = new Node("protocol", "Protocol: denied", parentNode, null);
     1404      failures.add(new Failure(Validator.DENIED_PROTOCOL, protocolNode));
    7931405    }
    7941406    if (protocol != null)
     
    7961408      protocolNode = new Node("protocol", "Protocol: " + protocol.getName(), parentNode, protocol);
    7971409      addProtocolParameters(dc, protocolNode);
     1410     
     1411      // Check if using project default protocol
     1412      if (project != null)
     1413      {
     1414        try
     1415        {
     1416          BasicItem defaultItem = project.getDefaultItem(dc, defaultProtocol);
     1417          if (defaultItem != null && !protocol.equals(defaultItem))
     1418          {
     1419            failures.add(new Failure(Validator.NONDEFAULT_PROTOCOL, parentNode, null,
     1420              new Fix("Change protocol of " + item.getType().toString().toLowerCase(), item),
     1421              new Fix("Change default " + defaultProtocol.getShortName().toLowerCase() + " for project", project)
     1422            ));
     1423          }
     1424        }
     1425        catch (BaseException ex)
     1426        {}
     1427      }
     1428     
     1429      // Check protocol type
     1430      try
     1431      {
     1432        ProtocolType pt = protocol.getProtocolType();
     1433        if (!pt.getSystemId().equals(defaultProtocol.getType()))
     1434        {
     1435          failures.add(new Failure(Validator.INCORRECT_PROTOCOLTYPE, parentNode, null,
     1436            new Fix("Change protocol of " + item.getType().toString().toLowerCase(), item),
     1437            new Fix("Change type of protocol", protocol)
     1438          ));
     1439        }
     1440      }
     1441      catch (PermissionDeniedException ex)
     1442      {}
    7981443    }
    7991444    if (protocolNode == null)
    8001445    {
    801       failures.add(new Failure(Validator.MISSING_PROTOCOL, parentNode));
     1446      failures.add(new Failure(Validator.MISSING_PROTOCOL, parentNode, null,
     1447        new Fix("Add protocol to " + item.getType().toString().toLowerCase(), item)));
    8021448    }
    8031449    return protocolNode;
     
    8141460  {
    8151461    Protocol protocol = (Protocol)protocolNode.getItem();
     1462    Node parentNode = protocolNode.getParent();
     1463    BasicItem parentItem = parentNode.getItem();
     1464    Annotatable annotatable = parentItem instanceof Annotatable ? (Annotatable)parentItem : null;
     1465    AnnotationSet as = annotatable != null && annotatable.isAnnotated() ?
     1466        annotatable.getAnnotationSet() : null;
    8161467    ItemQuery<AnnotationType> parameterQuery = initQuery(protocol.getParameters(), "name");
    8171468    List<AnnotationType> parameters = parameterQuery.list(dc);
     
    8231474      {
    8241475        new Node("parameter."+pp.getId(), pp.getName(), parameterNode, pp);
     1476       
     1477        // Check if a value for this parameter has been specified
     1478        if (as != null && !as.hasAnnotation(pp))
     1479        {
     1480          failures.add(new Failure(Validator.MISSING_PARAMETER, parentNode,
     1481            "Missing parameter value: " + pp.getName(),
     1482            new Fix("Add parameter value", parentItem, pp, false)));
     1483        }
    8251484      }
    8261485    }
     
    8411500    if (parent.isAnnotated())
    8421501    {
     1502      Protocol protocol = null;
     1503      try
     1504      {
     1505        protocol = parent.getProtocol();
     1506      }
     1507      catch (PermissionDeniedException ex)
     1508      {}
    8431509      annotationsNode = new Node("annotations", "Annotations", parentNode);
    8441510      AnnotationSet as = parent.getAnnotationSet();
    8451511      ItemQuery<Annotation> annotationQuery = initQuery(as.getAnnotations(), "annotationType.name");
     1512      Map<AnnotationType, Node> annotationTypes = new HashMap<AnnotationType, Node>();
     1513      Set<AnnotationType> duplicates = new HashSet<AnnotationType>();
     1514   
    8461515      for (Annotation a : annotationQuery.list(dc))
    8471516      {
    848         AnnotationType at = a.getAnnotationType();
    849         new Node("annotation."+at.getId(), at.getName(), annotationsNode, at);
    850       }
     1517        try
     1518        {
     1519          AnnotationType at = a.getAnnotationType();
     1520          if (protocol == null || protocol.isParameter(at))
     1521          {
     1522            Node atNode = new Node("annotationtype."+at.getId(), at.getName(), annotationsNode, at);
     1523            annotationTypes.put(at, atNode);
     1524           
     1525            // Check if annotation is a protocol parameter
     1526            if (at.isProtocolParameter())
     1527            {
     1528              failures.add(new Failure(Validator.ANNOTATION_IS_PARAMETER, parentNode,
     1529                "Annotation " + at.getName() + " is a protocol parameter",
     1530                new Fix("Remove annotation value", (BasicItem)parent, at, false),
     1531                new Fix("Change 'parameter' flag of annotation type", at)
     1532              ));
     1533            }
     1534           
     1535            // Check if annotation can be used on this item type
     1536            if (!at.isEnabledForItem(parent.getType()))
     1537            {
     1538              failures.add(new Failure(Validator.ANNOTATION_INVALID_ITEM, parentNode,
     1539                "Annotation " + at.getName() + " is invalid for item type: " + parent.getType(),
     1540                new Fix("Remove annotation value", (BasicItem)parent, at, false),
     1541                new Fix("Add '" + parent.getType().name() + "' to annotation type", at)
     1542              ));
     1543            }
     1544            try
     1545            {
     1546              List<?> values = a.getValues();
     1547              if (values != null)
     1548              {
     1549                for (Object value : values)
     1550                {
     1551                  at.validateAnnotationValue(value);
     1552                }
     1553              }
     1554            }
     1555            catch (InvalidDataException ex)
     1556            {
     1557              failures.add(new Failure(Validator.ANNOTATION_INVALID_VALUE, parentNode, ex.getMessage(),
     1558                new Fix("Change annotation value", (BasicItem)parent, at, false),
     1559                new Fix("Change annotation type restrictions", at)
     1560              ));
     1561            }
     1562          }
     1563        }
     1564        catch (PermissionDeniedException ex)
     1565        {
     1566          Node annotationNode = new Node("annotation."+a.getId(), a.getValueType().toString(), annotationsNode, a);
     1567          failures.add(new Failure(Validator.DENIED_ANNOTATIONTYPE, annotationNode));
     1568        }
     1569      }
     1570     
     1571      // Check if all MIAME annotations are specified
     1572      Set<AnnotationType> miameAnnotations = getMiameAnnotationTypes(parent.getType());
     1573      if (miameAnnotations != null)
     1574      {
     1575        for (AnnotationType at : miameAnnotations)
     1576        {
     1577          if (!annotationTypes.containsKey(at))
     1578          {
     1579            failures.add(new Failure(Validator.MISSING_MIAME_ANNOTATION, parentNode, null,
     1580                new Fix("Add value for annotation " + at.getName(), (BasicItem)parent, at, false),
     1581                new Fix("Remove 'Required for MIAME' flag on " + at.getName(), at)
     1582              ));
     1583          }
     1584        }
     1585      }
     1586      annotationTypes.clear();
    8511587     
    8521588      annotationQuery = initQuery(as.getAllInheritedAnnotations(), "annotationType.name");
    853       for (Annotation a : annotationQuery.list(dc))
    854       {
    855         AnnotationType at = a.getAnnotationType();
    856         new Node("annotation."+at.getId(), at.getName(), annotationsNode, at);
    857       }     
    858     }
     1589      List<Annotation> inherited = annotationQuery.list(dc);
     1590      if (inherited.size() > 0)
     1591      {
     1592        Set<Annotatable> parents = getAnnotatableParents(parent);
     1593
     1594        for (Annotation a : inherited)
     1595        {
     1596          Node atNode = null;
     1597          AnnotationType at = null;
     1598          try
     1599          {
     1600            at = a.getAnnotationType();
     1601            atNode = new Node("annotationtype."+at.getId(), at.getName(), annotationsNode, at);
     1602            if (annotationTypes.containsKey(at))
     1603            {
     1604              duplicates.add(at);
     1605            }
     1606            else
     1607            {
     1608              annotationTypes.put(at, atNode);
     1609            }
     1610          }
     1611          catch (PermissionDeniedException ex)
     1612          {
     1613            atNode = new Node("annotation."+a.getId(), a.getValueType().toString(), annotationsNode, a);
     1614            failures.add(new Failure(Validator.DENIED_ANNOTATIONTYPE, atNode));
     1615          }
     1616          try
     1617          {
     1618            Annotatable inheritFrom = a.getAnnotationSet().getItem();
     1619            if (!parents.contains(inheritFrom))
     1620            {
     1621              failures.add(new Failure(Validator.ANNOTATION_INHERIT_FROM_NONPARENT, parentNode,
     1622                "Inheriting annotation " + (at != null ?
     1623                  at.getName() : a.getValueType().toString()) + " from non-parent",
     1624                new Fix("Remove inherited annotation", parentNode.getItem(), at, true)
     1625              ));
     1626            }
     1627          }
     1628          catch (PermissionDeniedException ex)
     1629          {}
     1630        }
     1631      }
     1632     
     1633      // Add warnings for duplicate annotation types
     1634      if (duplicates.size() > 0)
     1635      {
     1636        for (AnnotationType dup : duplicates)
     1637        {
     1638          failures.add(new Failure(Validator.ANNOTATION_INHERIT_MULTIPLE, parentNode,
     1639            "Inherits multiple annotations of type " + dup.getName(),
     1640            new Fix("Modify inherited annotations", parentNode.getItem(), dup, true)
     1641          ));
     1642        }
     1643      }
     1644     
     1645    }
     1646
    8591647    return annotationsNode;
    8601648  }
    861 
    8621649
    8631650  /**
  • trunk/src/core/net/sf/basedb/util/overview/Failure.java

    r3033 r3045  
    2424package net.sf.basedb.util.overview;
    2525
     26import java.util.Arrays;
     27import java.util.LinkedList;
     28import java.util.List;
     29
    2630/**
    2731  Holds information about a failed validation. Note that all
     
    4347  private Validator validator;
    4448  private Node node;
     49  private String message;
     50  private List<Fix> fixes;
    4551 
    4652  /**
     
    5157  public Failure(Validator validator, Node node)
    5258  {
     59    this(validator, node, null, (Fix[])null);
     60  }
     61 
     62  public Failure(Validator validator, Node node, String message)
     63  {
     64    this(validator, node, message, (Fix[])null);
     65  }
     66 
     67  public Failure(Validator validator, Node node, String message, Fix... fixes)
     68  {
    5369    this.validator = validator;
    5470    this.node = node;
     71    this.message = message;
     72    this.fixes = new LinkedList<Fix>();
     73    if (fixes != null) this.fixes.addAll(Arrays.asList(fixes));
    5574  }
    5675 
     
    7190  }
    7291 
     92  /**
     93    Get a message explaining the failure.
     94  */
     95  public String getMessage()
     96  {
     97    return message != null ? message : validator.getFailureSummary();
     98  }
     99 
     100  public List<Fix> getFixes()
     101  {
     102    return fixes;
     103  }
     104 
     105  public void addFix(Fix fix)
     106  {
     107    fixes.add(fix);
     108  }
     109 
     110  public String toString()
     111  {
     112    return getMessage();
     113  }
    73114}
  • trunk/src/core/net/sf/basedb/util/overview/Validator.java

    r3033 r3045  
    4949
    5050  /**
     51    Validator rule that checks for denied access to protocols. Default severity level
     52    is WARNING.
     53  */
     54  public static final Validator DENIED_PROTOCOL = new Validator(
     55      "denied.protocol", "Access denied to protocol",
     56      "Checks if the user is denied access to a protocol",
     57      "Access denied to protocol", Severity.WARNING
     58    );
     59
     60  /**
    5161    Validator rule that checks for missing scan. Default severity level
    5262    is WARNING.
     
    5969 
    6070  /**
     71    Validator rule that checks for denied access to scans. Default severity level
     72    is WARNING.
     73  */
     74  public static final Validator DENIED_SCAN = new Validator(
     75      "denied.scan", "Access denied to scan",
     76      "Checks if the user is denied access to a scan",
     77      "Access denied to scan", Severity.WARNING
     78    );
     79 
     80  /**
    6181    Validator rule that checks for missing software. Default severity level
    6282    is WARNING.
     
    6686      "Checks if a software has been specified for a raw bioassay",
    6787      "Missing software", Severity.WARNING
     88    );
     89 
     90  /**
     91    Validator rule that checks for denied access to software. Default severity level
     92    is WARNING.
     93  */
     94  public static final Validator DENIED_SOFTWARE = new Validator(
     95      "denied.software", "Access denied to software",
     96      "Checks if the user is denied access to a software",
     97      "Access denied to software", Severity.WARNING
    6898    );
    6999 
     
    80110
    81111  /**
     112    Validator rule that checks for denied access to hardware. Default severity level
     113    is WARNING.
     114  */
     115  public static final Validator DENIED_HARDWARE = new Validator(
     116      "denied.hardware", "Access denied to hardware",
     117      "Checks if the user is denied access to a hardware",
     118      "Access denied to hardware", Severity.WARNING
     119    );
     120
     121  /**
    82122    Validator rule that checks for missing hybridization. Default severity level
    83123    is WARNING.
     
    90130
    91131  /**
     132    Validator rule that checks for denied access to hybridization. Default severity level
     133    is WARNING.
     134  */
     135  public static final Validator DENIED_HYBRIDIZATION = new Validator(
     136      "denied.hybridization", "Access denied to hybridization",
     137      "Checks if the user is denied access to a hybridization",
     138      "Access denied to hybridization", Severity.WARNING
     139    );
     140
     141  /**
    92142    Validator rule that checks for missing array slide. Default severity level
    93143    is WARNING.
     
    100150
    101151  /**
     152    Validator rule that checks for denied access to array slides. Default severity level
     153    is WARNING.
     154  */
     155  public static final Validator DENIED_ARRAYSLIDE = new Validator(
     156      "denied.slide", "Access denied to array slide",
     157      "Checks if the user is denied access to an array slide",
     158      "Access denied to array slide", Severity.WARNING
     159    );
     160
     161  /**
     162    Validator rule that checks for missing labeled extract. Default severity level
     163    is WARNING.
     164  */
     165  public static final Validator MISSING_LABELED_EXTRACT = new Validator(
     166      "missing.labeledextract", "Missing labeled extract",
     167      "Checks if at least one labeled extract has been specified as parent to a " +
     168      "pooled labeled extract",
     169      "Missing labeled extract", Severity.WARNING
     170    );
     171 
     172  /**
    102173    Validator rule that checks for missing extract. Default severity level
    103174    is WARNING.
     
    105176  public static final Validator MISSING_EXTRACT = new Validator(
    106177      "missing.extract", "Missing extract",
    107       "Checks if an extract has been specified for a non-pooled labled extract",
     178      "Checks if an extract has been specified for a labled extract or pooled extract",
    108179      "Missing extract", Severity.WARNING
    109180    );
    110181
     182  /**
     183    Validator rule that checks for denied access to extracts. Default severity level
     184    is WARNING.
     185  */
     186  public static final Validator DENIED_EXTRACT = new Validator(
     187      "denied.extract", "Access denied to extract",
     188      "Checks if the user is denied access to a extract",
     189      "Access denied to extract", Severity.WARNING
     190    );
     191
     192 
    111193  /**
    112194    Validator rule that checks for missing sample. Default severity level
     
    115197  public static final Validator MISSING_SAMPLE = new Validator(
    116198      "missing.sample", "Missing sample",
    117       "Checks if a sample has been specified for a non-pooled extract",
     199      "Checks if a sample has been specified for an extract or pooled sample",
    118200      "Missing sample", Severity.WARNING
    119201    );
    120202
     203  /**
     204    Validator rule that checks for denied access to samples. Default severity level
     205    is WARNING.
     206  */
     207  public static final Validator DENIED_SAMPLE = new Validator(
     208      "denied.sample", "Access denied to sample",
     209      "Checks if the user is denied access to a sample",
     210      "Access denied to sample", Severity.WARNING
     211    );
     212
     213 
    121214  /**
    122215    Validator rule that checks for missing biosource. Default severity level
     
    130223
    131224  /**
     225    Validator rule that checks for denied access to biosource. Default severity level
     226    is WARNING.
     227  */
     228  public static final Validator DENIED_BIOSOURCE = new Validator(
     229      "denied.biosource", "Access denied to biosource",
     230      "Checks if the user is denied access to a biosource",
     231      "Access denied to biosource", Severity.WARNING
     232    );
     233
     234  /**
     235    Validator rule that checks for denied access to labels. Default severity level
     236    is WARNING.
     237  */
     238  public static final Validator DENIED_LABEL = new Validator(
     239      "denied.label", "Access denied to label",
     240      "Checks if the user is denied access to a label",
     241      "Access denied to label", Severity.WARNING
     242    );
     243 
     244  /**
    132245    Validator rule that checks for missing array design. Default severity level
    133246    is WARNING.
    134247  */
    135248  public static final Validator MISSING_ARRAYDESIGN = new Validator(
    136       "missing.arraydesign", "Missing arraydesign",
     249      "missing.arraydesign", "Missing array design",
    137250      "Checks if an array design has been specified for a raw bioassay",
    138251      "Missing array design", Severity.WARNING
     
    140253
    141254  /**
     255    Validator rule that checks for denied access to an array design. Default severity level
     256    is WARNING.
     257  */
     258  public static final Validator DENIED_ARRAYDESIGN = new Validator(
     259      "denied.arraydesign", "Access denied to array design",
     260      "Checks if the user is denied access to an array design",
     261      "Access denied to array design", Severity.WARNING
     262    );
     263
     264  /**
     265    Validator rule that checks for missing array batch. Default severity level
     266    is WARNING.
     267  */
     268  public static final Validator MISSING_ARRAYBATCH = new Validator(
     269      "missing.arraybatch", "Missing array batch",
     270      "Checks if an array batch has been specified for an array slide",
     271      "Missing array batch", Severity.WARNING
     272    );
     273 
     274  /**
     275    Validator rule that checks for denied access to an array batch. Default severity level
     276    is WARNING.
     277  */
     278  public static final Validator DENIED_ARRAYBATCH = new Validator(
     279      "denied.arraybatch", "Access denied to array batch",
     280      "Checks if the user is denied access to an array batch",
     281      "Access denied to array batch", Severity.WARNING
     282    );
     283
     284 
     285  /**
    142286    Validator rule that checks for missing experimental factor value.
    143287    Default severity level is ERROR.
     
    145289  public static final Validator MISSING_FACTORVALUE = new Validator(
    146290      "missing.factorvalue", "Missing factor value",
    147       "Checks if a factorvalue has been specified for a raw bioassay",
     291      "Checks if a value has been specified for all experimental factors for a raw bioassay",
    148292      "Missing factor value", Severity.ERROR
    149293    );
     
    155299  public static final Validator MISSING_PARAMETER = new Validator(
    156300      "missing.parameter", "Missing parameter value",
    157       "Checks if a parameter has been specified for a protocol",
     301      "Checks if a parameter value has been specified for all protocol parameters",
    158302      "Missing parameter value", Severity.ERROR
    159303    );
    160304
    161305  /**
    162     Validator rule that checks for missing "Required by MIAME" annotation.
     306    Validator rule that checks for missing "Required for MIAME" annotation.
    163307    Default severity level is ERROR.
    164308  */
    165309  public static final Validator MISSING_MIAME_ANNOTATION = new Validator(
    166       "missing.miameannotation", "Missing annotation value",
    167       "Checks if an annotation value has been specified for a 'Required by MIAME' annotation type",
    168       "Missing annotation value", Severity.ERROR
    169     );
    170 
     310      "missing.miameannotation", "Missing MIAME annotation value",
     311      "Checks if an annotation value has been specified for a 'Required for MIAME' annotation type",
     312      "Missing MIAME annotation value", Severity.ERROR
     313    );
     314
     315  /**
     316    Validator rule that checks for denied access to an annotation type.
     317    Default severity level is WARNING.
     318  */
     319  public static final Validator DENIED_ANNOTATIONTYPE = new Validator(
     320      "denied.annotationtype", "Access denied to annotation type",
     321      "Checks if the user is denied access to an annotation type",
     322      "Access denied to annotation type", Severity.WARNING
     323    );
     324 
     325  /**
     326    Validator rule that checks if an item uses a different protocol than
     327    specified by the project default. Default severity level is WARNING.
     328  */
     329  public static final Validator NONDEFAULT_PROTOCOL = new Validator(
     330      "nondefault.protocol", "Use of non-default protocol",
     331      "Checks if an item uses a different protocol than the default for the current project",
     332      "Use of non-default protocol", Severity.WARNING
     333    );
     334
     335  /**
     336    Validator rule that checks if an item uses a different hardware than
     337    specified by the project default. Default severity level is WARNING.
     338  */
     339  public static final Validator NONDEFAULT_HARDWARE = new Validator(
     340      "nondefault.hardware", "Use of non-default hardware",
     341      "Checks if an item uses a different hardware (scanner, print robot, etc.) " +
     342      "than the default for the current project",
     343      "Use of non-default hardware", Severity.WARNING
     344    );
     345 
     346  /**
     347    Validator rule that checks if an item uses a different software than
     348    specified by the project default. Default severity level is WARNING.
     349  */
     350  public static final Validator NONDEFAULT_SOFTWARE = new Validator(
     351      "nondefault.software", "Use of non-default software",
     352      "Checks if an item uses a different software (feature extraction) " +
     353      "than the default for the current project",
     354      "Use of non-default software", Severity.WARNING
     355    );
     356
     357  /**
     358    Validator rule that checks if an item uses a different array design than
     359    specified by the project default. Default severity level is WARNING.
     360  */
     361  public static final Validator NONDEFAULT_ARRAYDESIGN = new Validator(
     362      "nondefault.arraydesign", "Use of non-default array design",
     363      "Checks if an item uses a different array design " +
     364      "than the default for the current project",
     365      "Use of non-default array design", Severity.WARNING
     366    );
     367 
     368  /**
     369    Validator rule that checks if an item uses a different raw data type than
     370    specified by the project default. Default severity level is WARNING.
     371  */
     372  public static final Validator NONDEFAULT_RAWDATATYPE = new Validator(
     373      "nondefault.rawdatatype", "Use of non-default raw data type",
     374      "Checks if an experiment uses the same raw data type as specified by the " +
     375      "default for the current project",
     376      "Use of non-default raw data type", Severity.WARNING
     377    );
     378 
     379  /**
     380    Validator rule that checks if all raw bioassays in an experiment
     381    uses the same array design. Default severity level is WARNING.
     382  */
     383  public static final Validator MULTIPLE_ARRAYDESIGNS = new Validator(
     384      "misc.multiplearraydesigns", "Multiple array designs",
     385      "Checks if all raw bioassays in an experiment uses the same " +
     386      "array design.",
     387      "Multiple array designs", Severity.WARNING
     388    );
     389
     390  /**
     391    Validator rule that checks if the array design for a raw bioassay
     392    matches the array design of the associated hybridization.
     393    Default severity level is WARNING.
     394  */
     395  public static final Validator NONMATHCING_ARRAYDESIGN = new Validator(
     396      "misc.nonmatchingarraydesigns", "Array design mismatch",
     397      "Checks if the array design for a raw bioassay is the same " +
     398      "array design as of the associated hybridization.",
     399      "Array design mismatch", Severity.WARNING
     400    );
     401
     402  /**
     403    Validator rule that checks if the protocol attached to an item
     404    has a correct protocol type. Default severity level is WARNING.
     405  */
     406  public static final Validator INCORRECT_PROTOCOLTYPE = new Validator(
     407      "misc.incorrectprotocoltype", "Incorrect protocol type",
     408      "Checks if the protocol attached to an item has a correct protocol type.",
     409      "Incorrect protocol type", Severity.WARNING
     410    );
     411
     412  /**
     413    Validator rule that checks if the software attached to an item
     414    has a correct software type. Default severity level is WARNING.
     415  */
     416  public static final Validator INCORRECT_SOFTWARETYPE = new Validator(
     417      "misc.incorrectsoftwaretype", "Incorrect software type",
     418      "Checks if the software attached to an item has a correct software type.",
     419      "Incorrect software type", Severity.WARNING
     420    );
     421
     422  /**
     423    Validator rule that checks if the hardware attached to an item
     424    has a correct hardware type. Default severity level is WARNING.
     425  */
     426  public static final Validator INCORRECT_HARDWARETYPE = new Validator(
     427      "misc.incorrecthardwaretype", "Incorrect hardware type",
     428      "Checks if the hardware attached to an item has a correct hardware type.",
     429      "Incorrect hardware type", Severity.WARNING
     430    );
     431 
     432  /**
     433    Validator rule that checks if the number of labeled extracts
     434    attached to a hybridization matches the number of channels in the
     435    experiment. Default severity level is ERROR.
     436  */
     437  public static final Validator INCORRECT_NUM_LABELEDEXTRACTS = new Validator(
     438      "misc.incorrectnumlabeledextracts", "Incorrect number of labeled extracts",
     439      "Checks if the the number of labeled extracts attached to a hybridzation matches " +
     440      "the number of channels in the experiment.",
     441      "Incorrect number of labeled extracts", Severity.ERROR
     442    );
     443 
     444  /**
     445    Validator rule that checks if a hybridization has more than one
     446    labeled extract with the same label. Default severity level is WARNING.
     447  */
     448  public static final Validator NONUNIQUE_LABEL = new Validator(
     449      "misc.nonuniquelabel", "Multiple labeled extracts with same label",
     450      "Checks if a hybridization has more than one labeled extract with the same label",
     451      "Multiple labeled extracts with same label", Severity.WARNING
     452    );
     453
     454  /**
     455    Validator rule that checks if a parent to a pooled labeled extract has the
     456    same lebel. Default severity level is WARNING.
     457  */
     458  public static final Validator DIFFERENT_LABEL = new Validator(
     459      "misc.differentlabel", "Labeled extract with different label",
     460      "Checks if the sources to a pooled labeled extract has the same " +
     461      "label as the product",
     462      "Labeled extract with different label", Severity.WARNING
     463    );
     464 
     465  /**
     466    Validator rule that checks if two items of the same type has the same
     467    name. Default severity level is ERROR.
     468  */
     469  public static final Validator NONUNIQUE_NAME_FOR_TYPE = new Validator(
     470      "misc.nonuniquenamefortype", "Non-unique name",
     471      "Checks if more than one item of the same type has the same name.",
     472      "Non-unique name", Severity.ERROR
     473    );
     474
     475  /**
     476    Validator rule that checks if two items of different type has the same
     477    name. Default severity level is IGNORE.
     478  */
     479  public static final Validator NONUNIQUE_NAME_GLOBAL = new Validator(
     480      "misc.nonuniquenameglobal", "Global non-unique name",
     481      "Checks if more than one item (of any type) has the same name.",
     482      "Global non-unique name", Severity.IGNORE
     483    );
     484
     485  /**
     486    Validator rule that checks for circular references among pooled items.
     487    Default severity level is ERROR.
     488  */
     489  public static final Validator CIRCULAR_REFERENCE = new Validator(
     490      "misc.circular", "Circular reference to pooled item",
     491      "Checks if there are circular references among pooled items.",
     492      "Circular reference to pooled item", Severity.ERROR
     493    );
     494
     495 
     496  /**
     497    Validator rule that checks if an annotation is a protocol parameter.
     498    Default severity level is WARNING.
     499  */
     500  public static final Validator ANNOTATION_IS_PARAMETER = new Validator(
     501      "annotation.isparameter", "Annotation is protocol parameter",
     502      "Checks if an item has annotations that are protocol parameters.",
     503      "Annotation is protocol parameter", Severity.WARNING
     504    );
     505
     506  /**
     507    Validator rule that checks if an annotation is not valid for the
     508    current item type. Default severity level is WARNING.
     509  */
     510  public static final Validator ANNOTATION_INVALID_ITEM = new Validator(
     511      "annotation.invaliditem", "Annotation invalid for item",
     512      "Checks if an annotation is invalid for the type of item.",
     513      "Annotation is invalid for item", Severity.WARNING
     514    );
     515
     516  /**
     517    Validator rule that checks if an annotation value is invalid
     518    according to annotation type specification. Default severity level is ERROR.
     519  */
     520  public static final Validator ANNOTATION_INVALID_VALUE = new Validator(
     521      "annotation.invalidvalue", "Annotation has invalid value",
     522      "Checks if an annotation has an invalid value.",
     523      "Annotation has invalid value", Severity.ERROR
     524    );
     525 
     526  /**
     527    Validator rule that checks if an inherited annotation value is inherited
     528    from a parent item. Default severity level is ERROR.
     529  */
     530  public static final Validator ANNOTATION_INHERIT_FROM_NONPARENT = new Validator(
     531      "annotation.inhertitfromnonparent", "Inheriting annotation from non-parent",
     532      "Checks if an item inherits an annotation that is is not from a parent item.",
     533      "Inherting annotation from non-parent", Severity.ERROR
     534    );
     535 
     536  /**
     537    Validator rule that checks if two or more inherited annotations have the
     538    same annotation type. Default severity level is ERROR.
     539  */
     540  public static final Validator ANNOTATION_INHERIT_MULTIPLE = new Validator(
     541      "annotation.inhertitmultiple", "Inheriting multiple annotation of same type",
     542      "Checks if an item inherits more than one annotation of the same annotation type.",
     543      "Inheriting multiple annotation of same type", Severity.ERROR
     544    );
    171545 
    172546  private String id;
  • trunk/www/common/annotations/inherit.jsp

    r2978 r3045  
    155155final Item itemType = Item.valueOf(request.getParameter("item_type"));
    156156final int itemId = Values.getInt(request.getParameter("item_id"));
     157final boolean standalone = Values.getBoolean(request.getParameter("standalone"));
    157158
    158159final DbControl dc = sc.newDbControl();
     
    169170    loadParents(parentAnnotations, parentItems, item);
    170171  }
    171  
     172  if (standalone)
     173  {
     174    sc.getCurrentContext(itemType).setObject("item", item);
     175  }
     176  String title = "Inherit annotations to " +
     177    HTML.encodeTags((item instanceof Nameable ? ((Nameable)item).getName() :
     178    (item == null ? " new item" : item.toString())));
     179
    172180  // Parent items may have been submitted by caller
    173181  String[] parents = request.getParameterValues("parents");
     
    317325    event.cancelBubble = true;
    318326  }
     327 
     328  function saveAnnotations()
     329  {
     330    var frm = document.forms['modified'];
     331    Annotations.addInheritedAnnotationsToForm(window, frm);
     332    frm.submit();
     333  }
    319334
    320335  </script>
    321336  </base:head>
    322   <base:body onload="init()" style="background: #E0E0E0;">
     337  <base:body onload="init()" style="<%=standalone ? "" : "background: #E0E0E0;"%>">
     338    <%
     339    if (standalone)
     340    {
     341      %>
     342      <h3 class="docked"><%=title%> <base:help helpid="annotations.inherit" /></h3>
     343      <div class="boxed" style="background: #E0E0E0">
     344      <%
     345    }
     346    %>
    323347
    324348  <form name="annotations">
     
    347371  </tr>
    348372  </table>
    349      
    350373  </form>
     374
     375    <%
     376    if (standalone)
     377    {
     378      %>
     379      </div>
     380      <table align="center">
     381      <tr>
     382        <td width="50%"><base:button onclick="saveAnnotations()" title="Save" /></td>
     383        <td width="50%"><base:button onclick="window.close()" title="Cancel" /></td>
     384      </tr>
     385      </table>
     386      <form name="modified" method="post" action="index.jsp?ID=<%=ID%>">
     387        <input type="hidden" name="cmd" value="SaveAnnotations">
     388        <input type="hidden" name="item_type" value="<%=itemType.name()%>">
     389        <input type="hidden" name="item_id" value="<%=itemId%>">
     390      </form>
     391      <%
     392    }
     393    %>
    351394  </base:body>
    352395  </base:page>
  • trunk/www/filemanager/directories/list_directories.jsp

    r2978 r3045  
    226226    %>
    227227    <base:body onload="initialise()"
    228       style="background: #E0E0E0; border: 1px solid #666666; border-bottom: 0px; padding-left: 0px; padding-right: 0px;" >
     228      style="border: 1px solid #999999; border-bottom: 0px; border-right: 0px; padding-left: 0px; padding-right: 0px;" >
    229229    <div id="main" class="joust" style="width:100%;">
    230230      <div id="joust" style="overflow: auto;">
  • trunk/www/filemanager/files/list_files.jsp

    r2978 r3045  
    286286  </base:head>
    287287 
    288   <base:body style="border-left: 1px solid #666666; padding-left: 0px; padding-right: 0px;">
     288  <base:body style="padding-left: 0px; padding-right: 0px;">
    289289  <m:menu
    290290    id="move"
  • trunk/www/filemanager/frameset.jsp

    r2978 r3045  
    6565<base:page type="frameset" title="">
    6666  <base:head />
    67   <frameset cols="170,*" frameborder="yes" border="3" >
     67  <frameset cols="170,*" frameborder="yes" border="5" >
    6868      <frame name="directories"
    6969        src="directories/list_directories.jsp?ID=<%=ID%>&mode=<%=mode%>"
    70         scrolling="auto" marginwidth="0" marginheight="0" frameborder="0">
     70        scrolling="auto" marginwidth="0" marginheight="0" frameborder="1">
    7171    <frame name="files"
    7272      src="<%=fileSrc%>"
    73       scrolling="auto" marginwidth="0" marginheight="0" frameborder="0">
     73      scrolling="auto" marginwidth="0" marginheight="0" frameborder="1">
    7474  </frameset>
    7575</base:page>
  • trunk/www/filemanager/manager.jsp

    r2978 r3045  
    8383  <iframe name="manager" id="idManager" src="frameset.jsp?ID=<%=ID%>&file_id=<%=fileId%>" width="100%"
    8484    frameborder="0" vspace="0" hspace="0"
    85     marginwidth="0" marginheight="0" scrolling="no" style="overflow: visible"></iframe>
     85    marginwidth="0" marginheight="0" scrolling="no"
     86    style="overflow: visible"></iframe>
    8687</base:body>
    8788</base:page>
  • trunk/www/include/scripts/newjoust.js

    r3033 r3045  
    194194    @param menuItemIndex The index of the menu item to open
    195195  */
    196   this.open = function(menuItemIndex)
     196  this.open = function(menuItemIndex, noParents)
    197197  {
    198198    var menuItem = this.menuItems[menuItemIndex];
    199     if (!menuItem || menuItem.isOpen) return;
     199    if (!menuItem || (menuItem.isOpen && noParents)) return;
    200200    menuItem.isOpen = true;
    201201    Main.show('children'+menuItem.index);
    202202    this.updateIconsAndText(menuItemIndex);
    203     if (menuItem.parentItemIndex != -1) this.open(menuItem.parentItemIndex);
     203    if (!noParents && menuItem.parentItemIndex != -1) this.open(menuItem.parentItemIndex, false);
    204204  }
    205205 
     
    211211    for (var i = 0; i < this.menuItems.length; i++)
    212212    {
    213       this.open(i);
     213      this.open(i, true);
    214214    }
    215215  }
     
    249249    var menuItem = this.menuItems[menuItemIndex];
    250250    if (!menuItem) return;
    251    
     251
    252252    if (menuItem.parentItemIndex != -1) this.open(menuItem.parentItemIndex);
    253253    if (menuItemIndex != this.selectedItemIndex)
  • trunk/www/include/styles/main.css

    r3033 r3045  
    332332  border: 0px;
    333333}
     334
     335.postit {
     336  position: absolute;
     337  width: 200px;
     338  background: #ffffd8;
     339  border: 1px solid #999999;
     340  padding: 2px;
     341}
  • trunk/www/include/styles/newjoust.css

    r2306 r3045  
    3333
    3434.joust .menuitem.hover {
    35   background: #F0F0F0;
     35  background: #E0E0E0;
    3636  cursor: pointer;
    3737}
  • trunk/www/views/experiments/overview/failures.jsp

    r3033 r3045  
    9595    else
    9696    {
    97       var joust = window.parent.frames['tree'].JoustMenu;
    98       var node = joust.menuItems[nodeId];
    99       joust.select(node.index);
     97      window.parent.frames['tree'].selectNode(nodeId);
    10098      if (selectedFailure) Main.removeClass(selectedFailure, 'selected');
    10199      selectedFailure = document.getElementById(failureId);
    102100      Main.addClass(selectedFailure, 'selected');
    103101    }
    104   }
    105   function validationOptionsOnClick()
    106   {
    107     Main.openPopup('options.jsp?ID=<%=ID%>', 'ValidationOptions', 700, 500);
    108   }
    109   function refreshTree()
    110   {
    111     window.parent.frames['tree'].refreshIfOutdated();
    112102  }
    113103  function itemOnClick(evt, itemType, itemId)
     
    118108  </base:head>
    119109
    120     <base:body
    121       style="background: #E0E0E0;" onload="refreshTree()">
    122       <div style="border-bottom: 1px solid #ffffff">
    123       <div style="border-bottom: 1px solid #999999">
    124         <table>
    125         <tr>
    126         <td>
    127           <b>
    128           <%=errors.size() %> error(s);
    129           <%=warnings.size()%> warning(s)
    130           </b>
    131         </td>
    132         <td>
    133           <base:button onclick="validationOptionsOnClick()"
    134             title="Validation options&hellip;"></base:button>
    135         </td>
    136         </tr>
    137         </table>
    138       </div>
     110    <base:body>
     111      <div style="border-bottom: 1px solid #999999; padding-bottom: 2px;">
     112        <b>
     113        <%=errors.size() %> error(s),
     114        <%=warnings.size()%> warning(s)
     115        </b>
    139116      </div>
    140117     
     
    177154            "error.gif" : "warning.gif"%>" /></td>
    178155            <td class="text" style="border-bottom: 1px dotted #999999; padding: 2px;"
    179               ><%=HTML.encodeTags(validator.getFailureSummary() + ": " + node.getTitle()) %>
     156              ><%=HTML.encodeTags(failure.getMessage()) %>
     157            </td>
     158            <td class="text" style="border-bottom: 1px dotted #999999; padding: 2px;"
     159              ><%=HTML.encodeTags(node.getTitle()) %>
    180160            </td>
    181161          </tr>
  • trunk/www/views/experiments/overview/frameset.jsp

    r3033 r3045  
    4747    <frame name="tree"
    4848      src="tree.jsp?ID=<%=ID%>"
    49       scrolling="auto" marginwidth="0" marginheight="0" frameborder="1"
     49      scrolling="auto" marginwidth="0" marginheight="4" frameborder="1"
    5050    >
    5151    <frameset rows="*,200" framborder="yes" border="5">
    5252      <frame name="info"
    53         src=""
    54         scrolling="auto" marginwidth="0" marginheight="0" frameborder="1"
     53        src="info.jsp?ID=<%=ID%>"
     54        scrolling="auto" marginwidth="0" marginheight="4" frameborder="1"
    5555      >
    5656      <frame name="failures"
    5757        src="failures.jsp?ID=<%=ID%>"
    58         scrolling="auto" marginwidth="0" marginheight="0" frameborder="1"
     58        scrolling="auto" marginwidth="0" marginheight="4" frameborder="1"
    5959      >
    6060    </frameset>
  • trunk/www/views/experiments/overview/index.jsp

    r3033 r3045  
    6262  {
    6363    // Display the overview page
    64 //    Base.getAndSetCurrentContext(sc, itemType, null, defaultContext, true);
    6564    dc = sc.newDbControl();
    6665    Experiment experiment = Experiment.getById(dc, itemId);
    6766    Project project = sc.getActiveProjectId() == 0 ? null : Project.getById(dc, sc.getActiveProjectId());
    6867    ExperimentOverview overview = ExperimentOverview.getOverview(experiment, project);
     68    if (Values.getBoolean(request.getParameter("revalidate")))
     69    {
     70      overview.reset(dc);
     71    }
    6972    dc.close();
    7073    forward = "overview.jsp";
  • trunk/www/views/experiments/overview/options.jsp

    r3033 r3045  
    9090    }
    9191  }
     92  function setAllInGroup(grpId, severity)
     93  {
     94    var vldId = 1;
     95    var vld = document.getElementById('select.'+grpId+'.'+vldId);
     96    while (vld)
     97    {
     98      for (var i = 0; i < vld.length; i++)
     99      {
     100        if (vld[i].value == severity)
     101        {
     102          vld.selectedIndex = i;
     103          i = vld.length;
     104        }
     105      }
     106      vldId++;
     107      vld = document.getElementById('select.'+grpId+'.'+vldId);
     108    }
     109  }
     110  function setAllOnChange(grpId, selectList)
     111  {
     112    var severity = selectList[selectList.selectedIndex].value;
     113    selectList.selectedIndex = 0;
     114    setAllInGroup(grpId, severity);
     115  }
     116 
     117  function showDescription(evt, validatorId)
     118  {
     119    var description = 'description.'+validatorId;
     120    Main.show(description);
     121    var el = document.getElementById(description);
     122    el.style.left = (evt.clientX + 10) + 'px';
     123    el.style.top = (evt.clientY - 10) + 'px';
     124  }
     125  function hideDescription(validatorId)
     126  {
     127    var description = 'description.'+validatorId;
     128    Main.hide(description);
     129  }
    92130  </script>
    93131  </base:head>
     
    101139    <t:tabcontrol id="settings" contentstyle="<%="height: "+(int)(scale*370)+"px;"%>"
    102140      position="bottom">
    103     <t:tab id="options" title="Validation options" helpid="overview.validationoptions">
     141    <t:tab id="options" title="Validation options" helpid="experiment.overview.validationoptions">
    104142   
    105143      <table border="0" cellspacing="0" cellpadding="0">
    106144      <%
    107145      int grp = 0;
     146      StringBuilder descriptions = new StringBuilder();
    108147      for (Map.Entry<String, List<Validator>> entry : validators.entrySet())
    109148      {
     
    113152        %>
    114153        <tr id="grp.<%=grp%>">
    115           <td colspan="2"><a href="javascript:toggle(<%=grp%>)"
     154          <td style="padding-top: 6px;"><a href="javascript:toggle(<%=grp%>)"
    116155            ><base:icon id="<%="grp."+grp+".icon"%>"
    117156              image="<%=grp > 1 ? "joust/plusonly.gif" : "joust/minustop.gif"%>"
    118             />&nbsp;<b><%=HTML.encodeTags(title)%></b></a>
     157            />&nbsp;<b><%=HTML.encodeTags(title)%></b></a>&nbsp;&nbsp;
     158          </td>
     159          <td style="padding-top: 6px;">
     160            <select name="setall.<%=grp%>" onchange="setAllOnChange(<%=grp%>, this)">
     161            <option value="">- set all in this group -
     162            <%
     163            for (Severity s : Severity.values())
     164            {
     165              %>
     166              <option value="<%=s.name()%>"><%=s%>
     167              <%
     168            }
     169            %>
    119170          </td>
    120171        </tr>
     
    128179          String validatorId = validator.getId();
    129180          boolean hasNext = vi.hasNext();
     181          descriptions.append("<div id=\"description.").append(validatorId).append("\"");
     182          descriptions.append(" class=\"postit\" style=\"display:none;\">");
     183          descriptions.append(HTML.encodeTags(validator.getDescription()));
     184          descriptions.append("</div>\n");
    130185          %>
    131           <tr id="vld.<%=grp%>.<%=vld%>" style="<%=grp > 1 ? "display: none;" : ""%>">
    132             <td
    133               title="<%=HTML.encodeTags(validator.getDescription())%>"
    134               ><base:icon image="<%=hasNext ? "joust/big/join.gif" : "joust/big/joinbottom.gif"%>"
    135             /><%=HTML.encodeTags(validator.getTitle())%>&nbsp;&nbsp;</td>
     186          <tr id="vld.<%=grp%>.<%=vld%>" style="<%=grp > 1 ? "display: none;" : ""%>"
     187            onmouseover="showDescription(event, '<%=validatorId%>')"
     188            onmouseout="hideDescription('<%=validatorId%>')"
     189            >
     190            <td><base:icon
     191              image="<%=hasNext ? "joust/big/join.gif" : "joust/big/joinbottom.gif"%>"
     192              /><%=HTML.encodeTags(validator.getTitle())%>&nbsp;&nbsp;</td>
    136193            <td>
    137             <select name="<%=validatorId%>">
     194            <select id="select.<%=grp%>.<%=vld%>" name="<%=validatorId%>">
    138195              <%
    139196              for (Severity s : Severity.values())
     
    152209      %>
    153210      </table>
     211      <%=descriptions.toString()%> 
    154212    </t:tab>
    155213    </t:tabcontrol>
  • trunk/www/views/experiments/overview/overview.jsp

    r3033 r3045  
    3939<%@ taglib prefix="p" uri="/WEB-INF/path.tld" %>
    4040<%@ taglib prefix="t" uri="/WEB-INF/tab.tld" %>
     41<%@ taglib prefix="tbl" uri="/WEB-INF/table.tld" %>
    4142<%!
    4243  private static final Item itemType = Item.EXPERIMENT;
     
    5354  %>
    5455  <base:page title="">
    55   <base:head scripts="tabcontrol.js" styles="headertabcontrol.css,path.css">
     56  <base:head scripts="tabcontrol.js" styles="toolbar.css,headertabcontrol.css,path.css">
    5657    <script language="JavaScript">
    5758    var timer = 0;
     
    7879      var iframe = window.frames['overview'];
    7980      var tree = iframe.frames['tree'].document.getElementById('main');
    80       if (tree) tree.style.height = (iframeElement.height-1)+'px';
     81      if (tree) tree.style.height = (iframeElement.height-8)+'px';
    8182      var joust = iframe.frames['tree'].document.getElementById('joust');
    82       if (joust) joust.style.height = (iframeElement.height-1-30)+'px';
     83      if (joust) joust.style.height = (iframeElement.height-8)+'px';
    8384      var info = iframe.frames['info'].document.getElementById('main');
    8485      if (info) info.style.height = iframeElement.height+'px';
     
    114115      }
    115116    }
     117   
     118    function expandAll()
     119    {
     120      frames['overview']['tree'].openAll();
     121    }
     122    function collapseAll()
     123    {
     124      frames['overview']['tree'].closeAll();
     125    }
     126    function revalidate()
     127    {
     128      location.href = 'index.jsp?ID=<%=ID%>&cmd=Overview&revalidate=1';
     129    }
     130    function validationOptions()
     131    {
     132      Main.openPopup('options.jsp?ID=<%=ID%>', 'ValidationOptions', 700, 500);
     133    }
    116134    </script>
    117135  </base:head>
     
    127145    <t:tab id="bioassaysets" title="Bioassay sets" />
    128146    <t:tab id="overview" title="Overview">
     147   
     148      <tbl:toolbar>
     149        <tbl:button image="joust/plusonly.gif" title="Expand all"
     150          onclick="expandAll()" tooltip="Expand entire tree"/>
     151        <tbl:button image="joust/minusonly.gif" title="Collapse all"
     152          onclick="collapseAll()" tooltip="Collapse entire tree" />
     153        <tbl:button image="refresh.gif" title="Revalidate"
     154          onclick="revalidate()" tooltip="Revalidate the experiment" />
     155        <tbl:button image="configure.png" title="Validation options&hellip;"
     156          onclick="validationOptions()" tooltip="Change validation options" />
     157        <tbl:button image="help.gif" title="Help&hellip;"
     158          onclick="<%="Main.openHelp('" + ID +"', 'experiment.overview')"%>"
     159          tooltip="Get help about this page"
     160        /> 
     161      </tbl:toolbar>
    129162      <iframe name="overview" id="idOverview" src="frameset.jsp?ID=<%=ID%>" width="100%"
    130163        frameborder="0" vspace="0" hspace="0"
    131         marginwidth="0" marginheight="0" scrolling="no" style="overflow: visible"></iframe>
     164        marginwidth="0" marginheight="0" scrolling="no"
     165        style="border: 1px solid #999999; border-top: 0px; overflow: visible"></iframe>
    132166    </t:tab>
    133167    </t:tabcontrol>
  • trunk/www/views/experiments/overview/tree.jsp

    r3033 r3045  
    7171      folderIcon += "ChildWarning";
    7272    }
    73     if (child.getNodeType() == Node.Type.ITEM && child.getItem() == null)
    74     {
    75       folderIcon = "ItemDenied";
    76     }
    7773    String tooltip = "";
    7874    if (warnings > 0 && errors > 0)
     
    109105    sb.append(",'").append(HTML.javaScriptEncode(child.getTitle()));
    110106    sb.append(child.getNodeType() == Node.Type.FOLDER ? " (" + numChildren + ")" : "").append("',");
    111     sb.append("'','" + HTML.javaScriptEncode(tooltip) + "', '").append(child.getId()).append("')\n");
     107    sb.append("'showInfo(\"").append(child.getId()).append("\")','").append(HTML.javaScriptEncode(tooltip)).append("', '").append(child.getId()).append("')\n");
    112108    sb.append(generateSubTree(child, ID));
    113109  }
     
    168164    IconStore.addIcon('ItemChildError', path + 'itemchilderror.gif', 18, 16);
    169165    IconStore.addIcon('ItemChildErrorSelected', path + 'itemchilderrorselected.gif', 18, 16);
    170     IconStore.addIcon('ItemDenied', path + 'itemdenied.gif', 18, 16);
    171     IconStore.addIcon('ItemDeniedSelected', path + 'itemdeniedselected.gif', 18, 16);
    172     var node<%=rootNode.hashCode()%> = JoustMenu.addMenuItem(-1, '<%=rootIcon%>', '<%=HTML.javaScriptEncode(experiment.getName())%>', '', '', '<%=rootNode.getId()%>');
     166    var node<%=rootNode.hashCode()%> = JoustMenu.addMenuItem(-1, '<%=rootIcon%>', '<%=HTML.javaScriptEncode(experiment.getName())%>', 'showInfo("<%=rootNode.getId()%>")', '', '<%=rootNode.getId()%>');
    173167    <%=generateSubTree(rootNode, ID)%>
     168    JoustMenu.menuItems[node<%=rootNode.hashCode()%>].isOpen = true;
    174169    JoustMenu.draw('joust');
    175170    isInitialised = true;
     
    185180    JoustMenu.closeAll();
    186181  }
     182 
     183  function showInfo(nodeId)
     184  {
     185    parent.frames['info'].location.href = 'info.jsp?ID=<%=ID%>&nodeId='+nodeId;
     186  }
     187 
     188  function selectNode(nodeId)
     189  {
     190    var node = JoustMenu.menuItems[nodeId];
     191    JoustMenu.select(node.index);
     192  }
     193 
    187194  var loadedTime = new Date().getTime();
    188195  function refreshIfOutdated()
     
    196203  </script>
    197204  </base:head>
    198     <base:body onload="initialise()"
    199       style="background: #E0E0E0; xborder-right: 1px solid #666666; padding-left: 0px; padding-right: 0px;" >
     205    <base:body onload="initialise()">
    200206    <div id="main" class="joust" style="width:100%;">
    201207      <div id="joust" style="overflow: auto;">
    202208      </div>
    203       <div style="width:99%;">
    204       <table align="center">
    205       <tr>
    206         <td><base:button onclick="openAll()" title="Expand all" image="joust/plus.gif" /></td>
    207         <td><base:button onclick="closeAll()" title="Collapse all" image="joust/minus.gif" /></td>
    208       </tr>
    209       </table>
    210       </div>
    211209    </div>
    212210    </base:body>
    213 
    214211  </base:page>
    215212  <%
Note: See TracChangeset for help on using the changeset viewer.