Changeset 8094


Ignore:
Timestamp:
Nov 4, 2022, 9:05:30 AM (3 months ago)
Author:
Nicklas Nordborg
Message:

Merge BASE 3.19.5 to the trunk

Location:
trunk
Files:
38 edited
3 copied

Legend:

Unmodified
Added
Removed
  • trunk

  • trunk/.classpath

    r7994 r8094  
    3535  <classpathentry kind="lib" path="lib/dist/poi-ooxml-5.0.0.jar"/>
    3636  <classpathentry kind="lib" path="lib/dist/hibernate-core-5.5.6.Final.jar"/>
     37  <classpathentry kind="lib" path="lib/dist/zip4j-2.11.2.jar"/>
    3738  <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11">
    3839    <attributes>
  • trunk/doc/3rd-party-components.txt

    r7994 r8094  
    303303Files    : AffxFusion.jar
    304304
     305ZIP file support
     306----------------
     307A library for reading and writing ZIP files.
     308
     309More info: https://github.com/srikanth-lingala/zip4j
     310Version  : 2.11.2
     311License  : zip4j-license.txt
     312Files    : zip4j-2.11.2.jar
     313
     314
    305315TAR file support
    306316----------------
     
    382392            commons-compress-1.20.jar, commons-math3-3.6.1.jar, xmlbeans-4.0.0.jar
    383393
     394
  • trunk/doc/src/docbook/user/webclient.xml

    r8083 r8094  
    24102410          </listitem>
    24112411        </varlistentry>
     2412       
     2413        <varlistentry>
     2414          <term><guilabel>Allow doubling back</guilabel></term>
     2415          <listitem>
     2416            <para>       
     2417              The normal operation when both a parent and child selection
     2418              has been made is that the path used when going up to the parent
     2419              is ignored when going down to the child. If this option is checked
     2420              then it is allowed to "double back" the same path also when going
     2421              down to the child item.
     2422            </para>
     2423          </listitem>
     2424        </varlistentry>
    24122425
    24132426        <varlistentry>
  • trunk/src/clients/web/net/sf/basedb/clients/web/extensions/list/RelatedItemColumn.java

    r8083 r8094  
    146146    if (dc != null)
    147147    {
    148       SourceItemTransformerFactory transformerFactory = ListableUtil.getTransformerFactory(spec.targetType);
     148      boolean includeChildrenThatPushToParents =  !spec.multiHop &&
     149          (spec.getTargetType() == Item.EXTRACT || spec.getTargetType() == Item.SAMPLE) &&
     150          spec.getItemSubtype(dc).getPushAnnotations();
     151      SourceItemTransformerFactory transformerFactory = ListableUtil.getTransformerFactory(spec.targetType, includeChildrenThatPushToParents);
    149152      SourceItemTransformer tmp = transformerFactory.create(spec.sourceType, spec.direction);
    150153      Restriction targetRestriction = spec.createTargetTypeRestriction(dc);
     
    186189 
    187190  /**
     191    Get the specification for this column.
     192    @since 3.19.5
     193  */
     194  protected Specification getSpecification()
     195  {
     196    return spec;
     197  }
     198 
     199  /**
    188200    We finalize this implementation to make sure that the helper
    189201    implementation always get a chance to re-cycle transactions.
     
    258270  {
    259271    Set<Integer> sourceIds = Collections.singleton(item.getId());
     272    helper.transformContext.resetCollected();
    260273    if (preTransform != null)
    261274    {
     275      if (!spec.allowDoublingBack) helper.transformContext.setCollecting();
    262276      sourceIds = preTransform.transform(helper.transformContext, sourceIds);
     277      if (!spec.allowDoublingBack) helper.transformContext.setAvoiding();
    263278    }
    264279    Set<Integer> relatedIds = transformer.transform(helper.transformContext, sourceIds);
     
    306321        baseIndex = 2;
    307322        spec.directionRaw = tmp[1];
    308         if ("CHILD".equals(spec.directionRaw)) spec.direction = SourceItemTransform.PARENT_TO_CHILD;
     323        if (spec.directionRaw.endsWith("+")) spec.allowDoublingBack = true;
     324        if (spec.directionRaw.startsWith("CHILD")) spec.direction = SourceItemTransform.PARENT_TO_CHILD;
    309325      }
    310326      spec.targetType = Item.valueOf(tmp[baseIndex]);
     
    350366    String directionRaw;
    351367    SourceItemTransform direction;
     368    boolean allowDoublingBack;
    352369    Item sourceType;
    353370    Item targetType;
     
    385402
    386403    /**
     404      Enabled on a multi-hop path if the path down to the related child from the
     405      parent item is allowed to traverse the same items as the path up from
     406      the source child item to the parent.
     407    */
     408    public boolean isDoublingBackAllowed()
     409    {
     410      return allowDoublingBack;
     411    }
     412   
     413    /**
    387414      Get the source item type. This is not part of the expression, but
    388415      is taken from the current list.
     
    471498      result += direction == SourceItemTransform.CHILD_TO_PARENT ? "parentitem" : "childitem";
    472499      if (multiHop) result += " multihop";
     500      if (allowDoublingBack) result += " doublingback";
    473501      result += "\">";
    474502      result += StringUtil.coalesce(subtypeName, targetType.name());
  • trunk/src/clients/web/net/sf/basedb/clients/web/extensions/list/RelatedItemMultiHopColumn.java

    r8083 r8094  
    1818
    1919  private final RelatedItemColumn nextHop;
     20  private final Specification nextSpec;
     21 
    2022  RelatedItemMultiHopColumn(DbControl dc, int index, Specification spec, RelatedItemHelper helper, RelatedItemColumn nextHop)
    2123  {
    2224    super(dc, index, spec, helper);
    2325    this.nextHop = nextHop;
     26    this.nextSpec = nextHop.getSpecification();
    2427   
    2528    setValueType(nextHop.getValueType());
     
    4346    setTitle(spec.generateTitle(nextHop.getTitle()));
    4447    setSubtitle(nextHop.getSubtitle());
    45     setTooltip(spec.generateTooltip(StringUtil.coalesce(nextHop.getTooltip(), nextHop.getTitle())));
     48    setTooltip(spec.generateTooltip(StringUtil.coalesce(nextHop.getTooltip(), nextHop.getTitle())+
     49      (nextSpec.allowDoublingBack ? " (doubling back allowed)" : " (no doubling back)")));
    4650  }
    4751
  • trunk/src/core/net/sf/basedb/core/PropertyFilter.java

    r8083 r8094  
    120120  private Unit unit;
    121121  private boolean temporary;
     122  private TransformContext transformContext;
    122123 
    123124  /**
     
    866867      String[] parts = property.split("/", 5);
    867868      SourceItemTransform direction = SourceItemTransform.PARENT_TO_CHILD;
     869      boolean allowDoublingBack = false;
    868870      int baseIndex = 1;
    869871      if (parts.length == 5) // The /DIRECTION is optional
    870872      {
    871873        baseIndex = 2;
    872         direction = "CHILD".equals(parts[1]) ? SourceItemTransform.CHILD_TO_PARENT : SourceItemTransform.PARENT_TO_CHILD;
     874        if (parts[1].startsWith("CHILD")) direction = SourceItemTransform.CHILD_TO_PARENT;
     875        allowDoublingBack = parts[1].endsWith("+");
    873876      }
    874877      Item targetType = Item.valueOf(parts[baseIndex]);
     
    896899      }
    897900      PropertyFilter pp = new PropertyFilter(targetProperty, operator, getValue(), getValueType());
     901      // Create a TransformContext unless we already have one
     902      // The subquery must use the same TransformContext in case we need the "doubling back" feature
     903      TransformContext tCtx = transformContext == null ? new TransformContext(dc) : transformContext;
     904      pp.transformContext = tCtx;
    898905      ClientContext subContext = new ClientContext(dc);
    899906      if (context != null) subContext.linkAttributes(context);
     
    907914        cc.setException(targetItemContext.getException());
    908915      }
    909 
     916     
    910917      // We then transform the list if ID:s to a list of child item ID:s using ItemList functionality
    911918      SortedSet<Integer> parentIds = new TreeSet<>(subquery.idList(dc));
    912       TransformContext tCtx = new TransformContext(dc);
    913919
    914920      SourceItemTransformerFactory factory = ListableUtil.getTransformerFactory(query.getItemType());
    915       factory = new SourceItemTransformerWithCache(factory);
     921      factory = new SourceItemTransformerWithCache(factory, tCtx.isAvoiding() ? property+operator+value : null);
     922      // If we are in a subquery the main query may need this for the "doubling back" feature
     923      if (transformContext != null && !allowDoublingBack) transformContext.setCollecting();
    916924      Set<Integer> myIds = factory.create(targetType, direction).transform(tCtx, parentIds);
     925      // If we are in a subquery the main query may need this for the "doubling back" feature
     926      if (transformContext != null && !allowDoublingBack) transformContext.setAvoiding();
    917927     
    918928      // The final ID list is returned as a restriction
  • trunk/src/core/net/sf/basedb/util/listable/BioSourceToSampleTransformer.java

    r6848 r8094  
    5656  public Set<Integer> transform(TransformContext context, Set<Integer> source)
    5757  {
     58    context.collect(getSourceItemType(), source);
    5859    ItemQuery<Sample> query = Sample.getQuery();
    5960    query.setIncludes(context.getInclude());
     
    6566        Expressions.parameter("biosources")
    6667      ));
    67     return safeIdList(context.getDbControl(), query, "biosources", source);
     68    return context.avoid(getTargetItemType(), safeIdList(context.getDbControl(), query, "biosources", source));
    6869  }
    6970
  • trunk/src/core/net/sf/basedb/util/listable/DerivedBioAssayToChildDerivedBioAssayTransformer.java

    r6848 r8094  
    7979    while (parents.size() > 0)
    8080    {
    81       Set<Integer> children = safeIdList(dc, query, "parents", parents);
     81      context.collect(getSourceItemType(), parents);
     82      Set<Integer> children = context.avoid(getTargetItemType(), safeIdList(dc, query, "parents", parents));
    8283     
    8384      // Store new children and "used" parents
  • trunk/src/core/net/sf/basedb/util/listable/DerivedBioAssayToParentDerivedBioAssayTransformer.java

    r6848 r8094  
    7979    while (children.size() > 0)
    8080    {
    81       Set<Integer> parents = safeIdList(dc, query, "children", children);
     81      context.collect(getSourceItemType(), children);
     82      Set<Integer> parents = context.avoid(getTargetItemType(), safeIdList(dc, query, "children", children));
    8283     
    8384      // Store new parents and "used" children
  • trunk/src/core/net/sf/basedb/util/listable/DerivedBioAssayToPhysicalBioAssayTransformer.java

    r6848 r8094  
    2424import java.util.Set;
    2525
    26 import net.sf.basedb.core.DbControl;
    2726import net.sf.basedb.core.Item;
    2827import net.sf.basedb.core.ItemQuery;
     
    5453  public Set<Integer> transform(TransformContext context, Set<Integer> source)
    5554  {
    56     DbControl dc = context.getDbControl();
    57    
     55    context.collect(getSourceItemType(), source);
    5856    ItemQuery<PhysicalBioAssay> query = PhysicalBioAssay.getQuery();
    5957    query.setIncludes(context.getInclude());
     
    6664    );
    6765   
    68     return safeIdList(context.getDbControl(), query, "bioAssays", source);
     66    return context.avoid(getTargetItemType(), safeIdList(context.getDbControl(), query, "bioAssays", source));
    6967  }
    7068
  • trunk/src/core/net/sf/basedb/util/listable/DerivedBioAssayToRawBioAssayTransformer.java

    r6848 r8094  
    6767  public Set<Integer> transform(TransformContext context, Set<Integer> source)
    6868  {
     69    context.collect(getSourceItemType(), source);
    6970    DbControl dc = context.getDbControl();
    7071   
     
    7879      )
    7980    );
    80     Set<Integer> all = safeIdList(dc, query, "bioAssays", source);
     81    Set<Integer> all = context.avoid(getTargetItemType(), safeIdList(dc, query, "bioAssays", source));
    8182   
    8283    if (collectedExtracts != null)
  • trunk/src/core/net/sf/basedb/util/listable/ExtractToChildExtractTransformer.java

    r6848 r8094  
    4747
    4848  private final boolean includeSourcesInTarget;
     49  private final boolean pushOnly;
    4950 
    5051  /**
     
    5455  public ExtractToChildExtractTransformer(boolean includeSourcesInTarget)
    5556  {
     57    this(includeSourcesInTarget, false);
     58  }
     59  /**
     60    Create a new extract to child extract transformer that only load children
     61    has a subtype with "push annotations" set.
     62    @since 3.19.5
     63  */
     64  public ExtractToChildExtractTransformer(boolean includeSourcesInTarget, boolean childrensThatPushOnly)
     65  {
    5666    super(Item.EXTRACT, Item.EXTRACT);
    5767    this.includeSourcesInTarget = includeSourcesInTarget;
     68    this.pushOnly = childrensThatPushOnly;
    5869  }
    59  
     70
    6071  @Override
    6172  public Set<Integer> transform(TransformContext context, Set<Integer> source)
     
    7586        Expressions.parameter("parents")
    7687      ));
     88    if (pushOnly)
     89    {
     90      query.join(Hql.innerJoin("itemSubtype", "st"));
     91      query.restrict(Restrictions.eq(Hql.property("st", "pushAnnotations"), Expressions.bool(true)));
     92    }
    7793
    7894    // Keep track of all seen children and parents
     
    85101    while (parents.size() > 0)
    86102    {
    87       Set<Integer> children = safeIdList(dc, query, "parents", parents);
     103      context.collect(getSourceItemType(), parents);
     104      Set<Integer> children = context.avoid(getTargetItemType(), safeIdList(dc, query, "parents", parents));
    88105     
    89106      // Store new children and "used" parents
  • trunk/src/core/net/sf/basedb/util/listable/ExtractToParentExtractTransformer.java

    r7836 r8094  
    136136    while (children.size() > 0)
    137137    {
    138       Set<Integer> parents = safeIdList(dc, query, "children", children);
     138      context.collect(getSourceItemType(), children);
     139      Set<Integer> parents = context.avoid(getTargetItemType(), safeIdList(dc, query, "children", children));
    139140      if (upstream != null) parents.removeAll(upstream);
    140141      if (downstream != null) parents.retainAll(downstream);
  • trunk/src/core/net/sf/basedb/util/listable/ExtractToPhysicalBioAssayTransformer.java

    r6848 r8094  
    2424import java.util.Set;
    2525
    26 import net.sf.basedb.core.DbControl;
    2726import net.sf.basedb.core.Item;
    2827import net.sf.basedb.core.ItemQuery;
     
    5352  public Set<Integer> transform(TransformContext context, Set<Integer> source)
    5453  {
    55     DbControl dc = context.getDbControl();
    56    
     54    context.collect(getSourceItemType(), source);
    5755    ItemQuery<PhysicalBioAssay> query = PhysicalBioAssay.getQuery();
    5856    query.setIncludes(context.getInclude());
     
    6563        Expressions.parameter("parents")
    6664      ));
    67     return safeIdList(context.getDbControl(), query, "parents", source);
     65    return context.avoid(getTargetItemType(), safeIdList(context.getDbControl(), query, "parents", source));
    6866  }
    6967
  • trunk/src/core/net/sf/basedb/util/listable/ExtractToSampleTransformer.java

    r7772 r8094  
    7474  public Set<Integer> transform(TransformContext context, Set<Integer> source)
    7575  {
     76    context.collect(getSourceItemType(), source);
    7677    ItemQuery<Sample> query = Sample.getQuery();
    7778    query.setIncludes(context.getInclude());
     
    8889      query.restrict(Restrictions.eq(Hql.property("st", "pushAnnotations"), Expressions.bool(true)));
    8990    }
    90     return safeIdList(context.getDbControl(), query, "extracts", source);
     91    return context.avoid(getTargetItemType(), safeIdList(context.getDbControl(), query, "extracts", source));
    9192  }
    9293
  • trunk/src/core/net/sf/basedb/util/listable/ListableUtil.java

    r6787 r8094  
    2727
    2828import net.sf.basedb.core.Item;
     29import net.sf.basedb.core.ItemSubtype;
    2930import net.sf.basedb.core.Listable;
    3031import net.sf.basedb.core.SyncFilter.SourceItemTransform;
     
    6667  public static SourceItemTransformerFactory getTransformerFactory(Item targetItemType)
    6768  {
     69    return getTransformerFactory(targetItemType, false);
     70  }
     71 
     72  /**
     73    Create a source item transformer factory that can transform items to the given
     74    target item type. If no transformer factory exists, null is returned.
     75    The 'includeChildrenThatPushToParent' parameter can be used for transforms
     76    that go from child to parent items, when the target is a SAMPLE or EXTRACT.
     77    When this flag is set, transformer will also include child items that have
     78    a subtype that have the {@link ItemSubtype#getPushAnnotations()} flag enabled
     79    in the final result.
     80   
     81    @since 3.19.5
     82  */
     83  public static SourceItemTransformerFactory getTransformerFactory(Item targetItemType, boolean includeChildrenThatPushToParent)
     84  {
    6885    SourceItemTransformerFactory factory = null;
    6986    if (targetItemType == Item.BIOSOURCE)
     
    7390    else if (targetItemType == Item.SAMPLE)
    7491    {
    75       factory = new ToSampleSourceItemTransformerFactory();
     92      factory = new ToSampleSourceItemTransformerFactory(includeChildrenThatPushToParent);
    7693    }
    7794    else if (targetItemType == Item.EXTRACT)
    7895    {
    79       factory = new ToExtractSourceItemTransformerFactory();
     96      factory = new ToExtractSourceItemTransformerFactory(includeChildrenThatPushToParent);
    8097    }
    8198    else if (targetItemType == Item.PHYSICALBIOASSAY)
  • trunk/src/core/net/sf/basedb/util/listable/PhysicalBioAssayToDerivedBioAssayTransformer.java

    r6848 r8094  
    8080      )
    8181    );
    82     Set<Integer> all = safeIdList(dc, query, "bioAssays", source);
     82    context.collect(getSourceItemType(), source);
     83    Set<Integer> all = context.avoid(getTargetItemType(), safeIdList(dc, query, "bioAssays", source));
    8384   
    8485    if (collectedExtracts != null)
  • trunk/src/core/net/sf/basedb/util/listable/PhysicalBioAssayToExtractTransformer.java

    r6848 r8094  
    5555  public Set<Integer> transform(TransformContext context, Set<Integer> source)
    5656  {
     57    context.collect(getSourceItemType(), source);
    5758    ItemQuery<Extract> query = Extract.getQuery();
    5859    query.setIncludes(context.getInclude());
     
    6667      )
    6768    );
    68     return safeIdList(context.getDbControl(), query, "bioAssays", source);
     69    return context.avoid(getTargetItemType(), safeIdList(context.getDbControl(), query, "bioAssays", source));
    6970  }
    7071
  • trunk/src/core/net/sf/basedb/util/listable/RawBioAssayToDerivedBioAssayTransformer.java

    r6848 r8094  
    2424import java.util.Set;
    2525
    26 import net.sf.basedb.core.DbControl;
    2726import net.sf.basedb.core.DerivedBioAssay;
    2827import net.sf.basedb.core.Item;
     
    5554  public Set<Integer> transform(TransformContext context, Set<Integer> source)
    5655  {
    57     DbControl dc = context.getDbControl();
    58    
     56    context.collect(getSourceItemType(), source);
    5957    ItemQuery<DerivedBioAssay> query = DerivedBioAssay.getQuery();
    6058    query.setIncludes(context.getInclude());
     
    6664      )
    6765    );
    68     return safeIdList(context.getDbControl(), query, "rawBioAssays", source);
     66    return context.avoid(getTargetItemType(), safeIdList(context.getDbControl(), query, "rawBioAssays", source));
    6967  }
    7068
  • trunk/src/core/net/sf/basedb/util/listable/SampleToBioSourceTransformer.java

    r7772 r8094  
    7171  public Set<Integer> transform(TransformContext context, Set<Integer> source)
    7272  {
     73    context.collect(getSourceItemType(), source);
    7374    ItemQuery<BioSource> query = BioSource.getQuery();
    7475    query.setIncludes(context.getInclude());
     
    8586      query.restrict(Restrictions.eq(Hql.property("st", "pushAnnotations"), Expressions.bool(true)));
    8687    }
    87     return safeIdList(context.getDbControl(), query, "samples", source);
     88    return context.avoid(getTargetItemType(), safeIdList(context.getDbControl(), query, "samples", source));
    8889  }
    8990
  • trunk/src/core/net/sf/basedb/util/listable/SampleToChildSampleTransformer.java

    r6848 r8094  
    2929import net.sf.basedb.core.ItemQuery;
    3030import net.sf.basedb.core.Sample;
    31 import net.sf.basedb.core.Type;
    3231import net.sf.basedb.core.query.Expressions;
    3332import net.sf.basedb.core.query.Hql;
     
    4847
    4948  private final boolean includeSourcesInTarget;
     49  private final boolean pushOnly;
    5050 
    5151  /**
     
    5555  public SampleToChildSampleTransformer(boolean includeSourcesInTarget)
    5656  {
     57    this(includeSourcesInTarget, false);
     58  }
     59  /**
     60    Create a new sample to child sample transformer that only load children that
     61    has a subtype with "push annotations" set.
     62    @since 3.19.5
     63  */
     64  public SampleToChildSampleTransformer(boolean includeSourcesInTarget, boolean childrensThatPushOnly)
     65  {
    5766    super(Item.SAMPLE, Item.SAMPLE);
    5867    this.includeSourcesInTarget = includeSourcesInTarget;
     68    this.pushOnly = childrensThatPushOnly;
    5969  }
    60  
     70
    6171  @Override
    6272  public Set<Integer> transform(TransformContext context, Set<Integer> source)
     
    7686        Expressions.parameter("parents")
    7787      ));
     88    if (pushOnly)
     89    {
     90      query.join(Hql.innerJoin("itemSubtype", "st"));
     91      query.restrict(Restrictions.eq(Hql.property("st", "pushAnnotations"), Expressions.bool(true)));
     92    }
    7893
    7994    // Keep track of all seen children and parents
     
    86101    while (parents.size() > 0)
    87102    {
    88       query.setParameter("parents", parents, Type.INT);
    89       Set<Integer> children = safeIdList(dc, query, "parents", parents);
     103      context.collect(getSourceItemType(), parents);
     104      Set<Integer> children = context.avoid(getTargetItemType(), safeIdList(dc, query, "parents", parents));
    90105     
    91106      // Store new children and "used" parents
  • trunk/src/core/net/sf/basedb/util/listable/SampleToExtractTransformer.java

    r6848 r8094  
    5757  public Set<Integer> transform(TransformContext context, Set<Integer> source)
    5858  {
     59    context.collect(getSourceItemType(), source);
    5960    ItemQuery<Extract> query = Extract.getQuery();
    6061    query.setIncludes(context.getInclude());
     
    6667        Expressions.parameter("samples")
    6768      ));
    68     return safeIdList(context.getDbControl(), query, "samples", source);
     69    return context.avoid(getTargetItemType(), safeIdList(context.getDbControl(), query, "samples", source));
    6970  }
    7071
  • trunk/src/core/net/sf/basedb/util/listable/SampleToParentSampleTransformer.java

    r7772 r8094  
    103103    while (children.size() > 0)
    104104    {
    105       Set<Integer> parents = safeIdList(dc, query, "children", children);
     105      context.collect(getSourceItemType(), children);
     106      Set<Integer> parents = context.avoid(getTargetItemType(), safeIdList(dc, query, "children", children));
    106107     
    107108      // Store new parents and "used" children
  • trunk/src/core/net/sf/basedb/util/listable/SourceItemTransformerChain.java

    r6801 r8094  
    102102    for (SourceItemTransformer sit : chain)
    103103    {
    104       //System.out.println(sit + " before: " + sit.getSourceItemType() + "=" + source.size() +":" + source);
    105104      source = sit.transform(context, source);
    106       //System.out.println("After: " + sit.getTargetItemType() + "=" + source.size());
    107105    }
    108106    return source;
  • trunk/src/core/net/sf/basedb/util/listable/SourceItemTransformerWithCache.java

    r7772 r8094  
    4747
    4848  private final SourceItemTransformerFactory factory;
     49  private final String cacheRegion;
    4950 
    5051  /**
     
    5758  public SourceItemTransformerWithCache(SourceItemTransformerFactory factory)
    5859  {
    59     this.factory = factory;
     60    this(factory, null);
    6061  }
    6162
     63  public SourceItemTransformerWithCache(SourceItemTransformerFactory factory, String cacheRegion)
     64  {
     65    this.factory = factory;
     66    this.cacheRegion = cacheRegion;
     67  }
     68 
     69 
    6270  @Override
    6371  public Item getTargetItem()
     
    7583  public SourceItemTransformer create(Item sourceItemType, SourceItemTransform transform)
    7684  {
    77     return new TransformerWithCache(factory.create(sourceItemType, transform), transform);
     85    return new TransformerWithCache(factory.create(sourceItemType, transform), transform, cacheRegion);
    7886  }
    7987 
     
    8593    private final SourceItemTransformer transformer;
    8694    private final SourceItemTransform transform;
     95    private final String cacheRegion;
    8796   
    88     TransformerWithCache(SourceItemTransformer transformer, SourceItemTransform transform)
     97    TransformerWithCache(SourceItemTransformer transformer, SourceItemTransform transform, String cacheRegion)
    8998    {
    9099      this.transformer = transformer;
    91100      this.transform = transform;
     101      this.cacheRegion = cacheRegion;
    92102    }
    93103   
     
    117127      if (cache != null)
    118128      {
    119         key = TransformCache.getKey(getSourceItemType(), getTargetItemType(), transform, source);
     129        key = TransformCache.getKey(cacheRegion, getSourceItemType(), getTargetItemType(), transform, source);
    120130        target = cache.get(key);
    121131      }
  • trunk/src/core/net/sf/basedb/util/listable/ToBioSourceSourceItemTransformerFactory.java

    r6791 r8094  
    6868
    6969      // Use utility function to add transformation up to the extract level
    70       ToExtractSourceItemTransformerFactory.childToParentChain(chain, sourceItemType, Item.BIOSOURCE);
     70      ToExtractSourceItemTransformerFactory.childToParentChain(chain, sourceItemType, Item.BIOSOURCE, false);
    7171      if (chain.size() > 0)
    7272      {
  • trunk/src/core/net/sf/basedb/util/listable/ToExtractSourceItemTransformerFactory.java

    r7772 r8094  
    5050    { Item.EXTRACT, Item.PHYSICALBIOASSAY, Item.DERIVEDBIOASSAY, Item.RAWBIOASSAY };
    5151 
     52  private final boolean includeChildrenThatPushToParent;
    5253 
    5354  public ToExtractSourceItemTransformerFactory()
    5455  {
     56    this(false);
     57  }
     58 
     59  public ToExtractSourceItemTransformerFactory(boolean includeChildrenThatPushToParent)
     60  {
    5561    super(Item.EXTRACT, PARENT_TO_CHILD, CHILD_TO_PARENT);
     62    this.includeChildrenThatPushToParent = includeChildrenThatPushToParent;
    5663  }
    5764 
     
    93100    else if (transform == SourceItemTransform.CHILD_TO_PARENT)
    94101    {
    95       childToParentChain(chain, sourceItemType, Item.EXTRACT);
     102      childToParentChain(chain, sourceItemType, Item.EXTRACT, includeChildrenThatPushToParent);
    96103    }
    97104
     
    105112    DERIVEDBIOASSAY, PHYSICALBIOASSAY and EXTRACT
    106113  */
    107   static void childToParentChain(List<SourceItemTransformer> chain, Item sourceItemType, Item targetItemType)
     114  static void childToParentChain(List<SourceItemTransformer> chain, Item sourceItemType, Item targetItemType, boolean includeChildrenThatPushToParent)
    108115  {
    109116    Item stepBySource = null;
     
    146153      // Load parent extracts, maybe including the source extracts
    147154      chain.add(new ExtractToParentExtractTransformer(sourceItemType != targetItemType, collectedExtracts));
     155      // Also include child extracts that have push-to-parent flag set
     156      if (includeChildrenThatPushToParent && targetItemType == Item.EXTRACT)
     157      {
     158        chain.add(new ExtractToChildExtractTransformer(true, true));
     159      }
    148160    }
    149161   
  • trunk/src/core/net/sf/basedb/util/listable/ToSampleSourceItemTransformerFactory.java

    r7772 r8094  
    5151 
    5252 
     53  private final boolean includeChildrenThatPushToParent;
     54 
    5355  public ToSampleSourceItemTransformerFactory()
    5456  {
    55     super(Item.SAMPLE, PARENT_TO_CHILD, CHILD_TO_PARENT);
     57    this(false);
    5658  }
    5759 
    58  
     60  public ToSampleSourceItemTransformerFactory(boolean includeChildrenThatPushToParent)
     61  {
     62    super(Item.SAMPLE, PARENT_TO_CHILD, CHILD_TO_PARENT);
     63    this.includeChildrenThatPushToParent = includeChildrenThatPushToParent;
     64  }
     65
    5966  @Override
    6067  public SourceItemTransformer create(final Item sourceItemType, final SourceItemTransform transform)
     
    8794     
    8895      // Use utility function to add transformation up to the extract level
    89       ToExtractSourceItemTransformerFactory.childToParentChain(chain, sourceItemType, Item.SAMPLE);
     96      ToExtractSourceItemTransformerFactory.childToParentChain(chain, sourceItemType, Item.SAMPLE, false);
    9097      if (chain.size() > 0)
    9198      {
     
    99106        // Load parent samples and maybe include source samples
    100107        chain.add(new SampleToParentSampleTransformer(sourceItemType != Item.SAMPLE));
     108        // Also include child samples that have push-to-parent flag set
     109        if (includeChildrenThatPushToParent)
     110        {
     111          chain.add(new SampleToChildSampleTransformer(true, true));
     112        }
    101113      }
    102114    }
  • trunk/src/core/net/sf/basedb/util/listable/TransformCache.java

    r7770 r8094  
    3030  public static CacheKey getKey(Item sourceType, Item targetType, SyncFilter.SourceItemTransform transform, Set<Integer> sourceIds)
    3131  {
     32    return getKey(null, sourceType, targetType, transform, sourceIds);
     33  }
     34 
     35  public static CacheKey getKey(String cacheRegion, Item sourceType, Item targetType, SyncFilter.SourceItemTransform transform, Set<Integer> sourceIds)
     36  {
    3237    SortedSet<Integer> sortedSrc = sourceIds instanceof SortedSet ? (SortedSet<Integer>)sourceIds : new TreeSet<>(sourceIds);
    33     return new CacheKey(sourceType, targetType, transform, sortedSrc);
     38    return new CacheKey(cacheRegion, sourceType, targetType, transform, sortedSrc);
    3439  }
    3540 
     
    96101  public static class CacheKey
    97102  {
     103    private final String cacheRegion;
    98104    private final Item sourceType;
    99105    private final Item targetType;
     
    101107    private final String sourceIdHash;
    102108   
    103     CacheKey(Item sourceType, Item targetType, SyncFilter.SourceItemTransform transform, SortedSet<Integer> sourceIds)
     109    CacheKey(String cacheRegion, Item sourceType, Item targetType, SyncFilter.SourceItemTransform transform, SortedSet<Integer> sourceIds)
    104110    {
     111      this.cacheRegion = cacheRegion==null?"":cacheRegion;
    105112      this.sourceType = sourceType;
    106113      this.targetType = targetType;
     
    112119    public int hashCode()
    113120    {
    114       return sourceType.hashCode() + 3 * targetType.hashCode() + 7 * transform.hashCode() + 11 * sourceIdHash.hashCode();
     121      return cacheRegion.hashCode()+sourceType.hashCode() + 3 * targetType.hashCode() + 7 * transform.hashCode() + 11 * sourceIdHash.hashCode();
    115122    }
    116123
     
    120127      if (!(obj instanceof CacheKey)) return false;
    121128      CacheKey other = (CacheKey)obj;
    122       return sourceType == other.sourceType && targetType == other.targetType &&
     129      return cacheRegion.equals(other.cacheRegion) &&
     130        sourceType == other.sourceType && targetType == other.targetType &&
    123131        transform == other.transform && sourceIdHash.equals(other.sourceIdHash);
    124132    }
     
    127135    public String toString()
    128136    {
    129       return "CacheKey[" + sourceType.name() + "->" + targetType.name() + "; " + transform.name() + "; " + sourceIdHash + "]";
    130     }   
     137      return "CacheKey["+cacheRegion + ";" + sourceType.name() + "->" + targetType.name() + "; " + transform.name() + "; " + sourceIdHash + "]";
     138    }
    131139  }
    132140 
  • trunk/src/core/net/sf/basedb/util/listable/TransformContext.java

    r7770 r8094  
    2323
    2424import java.util.Collection;
     25import java.util.HashMap;
     26import java.util.HashSet;
     27import java.util.Map;
     28import java.util.Set;
    2529
    2630import net.sf.basedb.core.DbControl;
    2731import net.sf.basedb.core.Include;
     32import net.sf.basedb.core.Item;
    2833
    2934/**
     
    8994  }
    9095
     96  private boolean collecting;
     97  private boolean avoiding;
     98  private Map<Item, Set<Integer>> collectedByItemType;
     99
     100 
     101  /**
     102    Enable/disable collecting of all source items that the transformers in
     103    this context are using.
     104    @since 3.19.5
     105  */
     106  public void setCollecting(boolean collecting)
     107  {
     108    this.collecting = collecting;
     109  }
     110 
     111  /**
     112    Shortcut for enabling 'collecting' and disabling 'avoiding'.
     113    @since 3.19.5
     114  */
     115  public void setCollecting()
     116  {
     117    this.collecting = true;
     118    this.avoiding = false;
     119  }
     120 
     121  public boolean isCollecting()
     122  {
     123    return collecting;
     124  }
     125 
     126  /**
     127    Enable/disable avoiding of returning any source items that has
     128    been previously collected.
     129    @since 3.19.5
     130  */
     131  public void setAvoiding(boolean avoiding)
     132  {
     133    this.avoiding = avoiding;
     134  }
     135  /**
     136    Shortcut for enabling 'avoiding' and disabling 'collecting'.
     137    @since 3.19.5
     138  */
     139  public void setAvoiding()
     140  {
     141    this.collecting = false;
     142    this.avoiding = true;
     143  }
     144
     145  public boolean isAvoiding()
     146  {
     147    return avoiding;
     148  }
     149 
     150  /**
     151    Clear all collected items and disable both 'collecting' and
     152    'avoiding'.
     153    @since 3.19.5
     154  */
     155  public void resetCollected()
     156  {
     157    this.collecting = false;
     158    this.avoiding = false;
     159    if (collectedByItemType != null) collectedByItemType.clear();
     160  }
     161 
     162  /**
     163    Store collected items for later use if collecting has been enabled.
     164    @return The source items
     165  */
     166  public Set<Integer> collect(Item itemType, Set<Integer> source)
     167  {
     168    if (collecting && source.size() > 0)
     169    {
     170      if (collectedByItemType == null) collectedByItemType = new HashMap<>();
     171      Set<Integer> collected = collectedByItemType.get(itemType);
     172      if (collected == null)
     173      {
     174        collected = new HashSet<>();
     175        collectedByItemType.put(itemType, collected);
     176      }
     177      collected.addAll(source);
     178    }
     179    return source;
     180  }
     181 
     182  /**
     183    Avoid collected items by removing them from the source set.
     184    Note that this method modified the source set directly.
     185    @return The source set
     186  */
     187  public Set<Integer> avoid(Item itemType, Set<Integer> source)
     188  {
     189    if (avoiding && source.size() > 0)
     190    {
     191      if (collectedByItemType != null && collectedByItemType.containsKey(itemType))
     192      {
     193        Set<Integer> collected = collectedByItemType.get(itemType);
     194        source.removeAll(collected);
     195      }
     196    }
     197    return source;
     198  }
     199
    91200}
  • trunk/src/core/net/sf/basedb/util/zip/FilePacker.java

    r7551 r8094  
    2727import java.io.InputStream;
    2828import java.io.OutputStream;
     29
     30import net.sf.basedb.core.PluginParameter;
     31import net.sf.basedb.core.StringParameterType;
    2932
    3033/**
     
    6568 
    6669  /**
     70    Does the packer support encryption or not?
     71    The default implementation return false.
     72    @since 3.19.5
     73  */
     74  public default boolean supportsEncryption()
     75  {
     76    return false;
     77  }
     78 
     79  /**
     80    The default implementation return a parameter asking for a password.
     81    The implementing class may create another parameter as long as it is
     82    named "password". This method is only called if the implementation
     83    supports encryption.
     84    @since 3.19.5
     85  */
     86  public default PluginParameter<String> getPasswordParameter()
     87  {
     88    PluginParameter<String> passwordParameter = new PluginParameter<String>
     89    (
     90      "password", "Password", "Enter a password to encrypt the archive." , new StringParameterType()
     91    );
     92    return passwordParameter;
     93  }
     94 
     95  /**
     96    Set the password to use for encrypting the archive. This method
     97    is only called if the implementation supports encryption and the
     98    user has entered a password.
     99    @since 3.19.5
     100  */
     101  public default void setPassword(String password)
     102  {}
     103 
     104  /**
    67105    The output stream that the compressed files should be written to.
    68106    @param out The output stream to write to
  • trunk/src/core/net/sf/basedb/util/zip/ZipFilePacker.java

    r6127 r8094  
    2323package net.sf.basedb.util.zip;
    2424
     25import net.lingala.zip4j.io.outputstream.ZipOutputStream;
     26import net.lingala.zip4j.model.ZipParameters;
     27import net.lingala.zip4j.model.enums.AesKeyStrength;
     28import net.lingala.zip4j.model.enums.CompressionLevel;
     29import net.lingala.zip4j.model.enums.CompressionMethod;
     30import net.lingala.zip4j.model.enums.EncryptionMethod;
     31import net.sf.basedb.core.BaseException;
     32import net.sf.basedb.core.PluginParameter;
     33import net.sf.basedb.core.StringParameterType;
    2534import net.sf.basedb.util.FileUtil;
    2635
     
    2837import java.io.InputStream;
    2938import java.io.OutputStream;
    30 import java.util.zip.ZipEntry;
    31 import java.util.zip.ZipOutputStream;
    3239
    3340/**
     
    4249{
    4350  private ZipOutputStream zip;
     51  private String password;
    4452 
    4553  /**
     
    7886  }
    7987  /**
    80    * Wrap the output stream in a {@link ZipOutputStream}.
    81    */
     88    Wrap the output stream in a {@link ZipOutputStream}.
     89  */
    8290  @Override
    8391  public void setOutputStream(OutputStream out)
    8492  {
    85     this.zip = new ZipOutputStream(out);
    86     zip.setMethod(ZipOutputStream.DEFLATED);
     93    try
     94    {
     95      this.zip = password == null ? new ZipOutputStream(out) : new ZipOutputStream(out, password.toCharArray());
     96    }
     97    catch (IOException ex)
     98    {
     99      throw new BaseException(ex);
     100    }
    87101  }
     102 
    88103  /**
    89     Create a new {@link ZipEntry} and write the compressed
    90     data to it.
     104    Encryption is supported.
     105    @since 3.19.5
     106  */
     107  @Override
     108  public boolean supportsEncryption()
     109  {
     110    return true;
     111  }
     112
     113  /**
     114    Get the encyption password parameter.
     115    @since 3.19.5
     116  */
     117  @Override
     118  public PluginParameter<String> getPasswordParameter()
     119  {
     120    PluginParameter<String> passwordParameter = new PluginParameter<String>
     121    (
     122      "password", "Password", "Enter a password to encrypt the archive with strong AES256 encryption. "
     123        + "If empty, the ZIP archive will not be encrypted." , new StringParameterType()
     124    );
     125    return passwordParameter;
     126  }
     127
     128  /**
     129    @since 3.19.5
     130  */
     131  @Override
     132  public void setPassword(String password)
     133  {
     134    this.password = password;
     135  }
     136
     137  /**
     138    Create a new entry and write the compressed data to it.
    91139  */
    92140  @Override
     
    96144    boolean isDirectory = in == null;
    97145    if (isDirectory && !entryName.endsWith("/")) entryName += "/";
    98     ZipEntry entry = new ZipEntry(entryName);
    99     if (lastModified > 0) entry.setTime(lastModified);
    100     if (isDirectory)
     146   
     147    ZipParameters zipParameters = new ZipParameters();
     148    zipParameters.setFileNameInZip(entryName);
     149    if (lastModified > 0)
    101150    {
    102       entry.setMethod(ZipOutputStream.STORED);
    103       entry.setSize(0);
    104       entry.setCrc(0);
     151      zipParameters.setLastModifiedFileTime(lastModified);
     152    }
     153    if (isDirectory)
     154    {
     155      zipParameters.setCompressionMethod(CompressionMethod.STORE);
     156      zipParameters.setEntrySize(0);
     157      zipParameters.setEntryCRC(0);
    105158    }
    106159    else
    107160    {
    108       entry.setSize(size);
     161      zipParameters.setCompressionMethod(CompressionMethod.DEFLATE);
     162      zipParameters.setCompressionLevel(CompressionLevel.NORMAL);
     163      zipParameters.setEntrySize(size);
     164      if (password != null)
     165      {
     166        zipParameters.setEncryptFiles(true);
     167        zipParameters.setEncryptionMethod(EncryptionMethod.AES);
     168        zipParameters.setAesKeyStrength(AesKeyStrength.KEY_STRENGTH_256);
     169      }
    109170    }
    110     zip.putNextEntry(entry);
     171    zip.putNextEntry(zipParameters);
    111172    if (!isDirectory) FileUtil.copy(in, zip);
    112173    zip.flush();
  • trunk/src/plugins/core/net/sf/basedb/plugins/PackedFileExporter.java

    r7605 r8094  
    308308       
    309309        // Other options
     310        if (packer.supportsEncryption())
     311        {
     312          storeValue(job, request, ri.getParameter("password"));
     313        }
    310314        storeValue(job, request, ri.getParameter("removeItems"));
    311315        if (saveAs != null)
     
    358362    List<Integer> directories = job.getValues("directories");
    359363    boolean removeItems = Boolean.TRUE.equals(job.getValue("removeItems"));
     364    String password = job.getValue("password");
    360365    FilePacker packer = getPacker();
     366    if (packer.supportsEncryption() && password != null)
     367    {
     368      packer.setPassword(password);
     369    }
    361370
    362371    ChainedProgressReporter chained = null;
     
    528537        parameters.add(getSaveAsParameter(null, null, defaultPath, requireFile));
    529538        parameters.add(getOverwriteParameter(null, null));
     539        // Encryption
     540        if (packer.supportsEncryption())
     541        {
     542          parameters.add(packer.getPasswordParameter());
     543        }
    530544
    531545        // Remove parameter
  • trunk/www/common/columns/add_relateditem_column.js

    r8083 r8094  
    109109    configure.clearList('childItemType');
    110110    configure.clearList('childSubtype');
     111    Doc.element('allowDoublingBack').disabled = true;
    111112   
    112113    var frm = document.forms['relatedItems'];
     
    200201    configure.clearColumns();
    201202    configure.clearList('childSubtype');
     203    Doc.element('allowDoublingBack').disabled = true;
    202204   
    203205    var frm = document.forms['relatedItems'];
     
    267269      frm.childSubtype.selectedIndex = 0;
    268270      frm.childSubtype.disabled = currentChildSubtypes.length == 0;
     271      frm.allowDoublingBack.disabled = currentChildSubtypes.length == 0;
    269272    }
    270273   
     
    371374    data.childItemType = frm.childItemType.value;
    372375    data.childSubtype = frm.childSubtype.value;
     376    data.allowDoublingBack = frm.allowDoublingBack.checked?1:0;
    373377
    374378    if (!data.targetItemType)
     
    396400    {
    397401      data.childSubtypeName = frm.childSubtype[frm.childSubtype.selectedIndex].text;
    398       propertyPrefix += '/CHILD/'+data.childItemType+'/'+data.childSubtype+'/';
     402      propertyPrefix += (data.allowDoublingBack?'/CHILD+/':'/CHILD/')+data.childItemType+'/'+data.childSubtype+'/';
    399403      titlePrefix += '.'+data.childSubtypeName;
    400404    }
  • trunk/www/common/columns/add_relateditem_column.jsp

    r8083 r8094  
    5858{
    5959  width: 100%;
     60  position: absolute;
     61  border-collapse: separate;
     62}
     63
     64.columnstable thead
     65{
     66  position: sticky;
     67  top: 0;
    6068}
    6169
     
    6371{
    6472  vertical-align: top;
     73}
     74
     75.columnstable tr.bottomborder th
     76{
     77  border-bottom-width: 1px;
     78}
     79
     80.columnstable tr.topborder th
     81{
     82  border-top-width: 1px;
    6583}
    6684
     
    170188      </td>
    171189    </tr>
     190    <tr>
     191      <th class="subprompt"></th>
     192      <td>
     193        <label><input type="checkbox" id="showAllAnnotationTypes"
     194          name="showAllAnnotationTypes">Show annotations for all subtypes</label>
     195      </td>
     196      <td></td>
     197      <td>
     198        <label title="Normally, child items that was passed when going up to the parent are ignored when going down. Enable this option to include all child items."
     199          ><input type="checkbox" id="allowDoublingBack" name="allowDoublingBack" disabled
     200          >Allow doubling back</label>
     201      </td>
     202    </tr>
    172203    <tr class="dynamic">
    173204      <th></th>
    174       <td></td>
    175       <td></td>
    176       <td></td>
     205      <td colspan="3" class="columnsFrom" style="padding-top: 2px;">
     206        <span id="targetPath"></span><span id="childPath" class="childitem" style="display: none;"></span>
     207      </td>
    177208    </tr>
    178209    </table>
    179210    </div>
    180211   
    181     <div class="absolutefull" style="top: 4em; left: 10em;">
    182       <div class="columnsFrom" style="height: 1.5em; white-space: nowrap; overflow: hidden;">
    183         <span id="targetPath"></span><span id="childPath" class="childitem" style="display: none;"></span>
    184         <label style="font-weight: normal;"><input type="checkbox" id="showAllAnnotationTypes"
    185           name="showAllAnnotationTypes">Show annotations for all subtypes</label>
    186       </div>
     212    <div class="absolutefull" style="top: 6.75em; left: 10em;">   
    187213      <table id="columnstable" class="columnstable" style="width: 100%;">
    188       <thead class="bg-filled-100 topborder bottomborder">
    189         <tr>
     214      <thead class="">
     215        <tr class="bg-filled-100 topborder bottomborder">
    190216          <th style="width: 33%;">Columns</th>
    191217          <th style="width: 33%;">Annotations</th>
  • trunk/www/include/styles/table.css

    r8083 r8094  
    253253}
    254254
    255 /* A column header defining a parent/child item value */
    256 .itemlist div.data th.relateditemcol::before
    257 {
    258   margin-right: 2px;
    259   float: left;
    260 }
    261 
    262255.itemlist div.data th.relateditemcol span.parentitem::before
    263256{
     
    274267}
    275268
    276 
    277 /* This will make room for the '›' without causing the header to wrap */
    278 .itemlist div.data th.relateditemcol > span
    279 {
    280   display: inline-block;
    281   max-width: calc(100% - 16px);
    282   overflow: hidden;
    283 }
     269.itemlist div.data th.relateditemcol span.childitem.doublingback::before
     270{
     271  content: url('../../images/child-item-doubleback.png');
     272}
     273
    284274
    285275/* A column header defining a linked item value */
Note: See TracChangeset for help on using the changeset viewer.