diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/TrackingServer.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/TrackingServer.java index 8c45863eda1b97922c92464c637cfcb18c57cc4d..c6a9146e7bf9b081871891d029900ff7231b220e 100644 --- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/TrackingServer.java +++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/TrackingServer.java @@ -79,6 +79,8 @@ public final class TrackingServer extends AbstractServer<ITrackingServer> implem final Session session = getSession(sessionToken); final ISampleLister sampleLister = businessObjectFactory.createSampleLister(session); - return sampleLister.list(new ListOrSearchSampleCriteria(criteria)); + final ListOrSearchSampleCriteria listerCriteria = new ListOrSearchSampleCriteria(criteria); + listerCriteria.setEnrichDependentSamplesWithProperties(true); + return sampleLister.list(listerCriteria); } } diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/samplelister/ISampleListingQuery.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/samplelister/ISampleListingQuery.java index c203a16118f59be84ed281abf620c1065127bf1e..e59fab453de06c14da207e4ea45f5d414b8f7e13 100644 --- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/samplelister/ISampleListingQuery.java +++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/samplelister/ISampleListingQuery.java @@ -169,7 +169,7 @@ public interface ISampleListingQuery extends TransactionQuery, IPropertyListingQ @Select(sql = "select s.id, s.perm_id, s.code, s.expe_id, s.grou_id, s.dbin_id, " + " s.registration_timestamp, s.pers_id_registerer, " + " s.samp_id_generated_from, s.samp_id_part_of, s.saty_id, s.inva_id " - + " from samples s where s.saty_id=?{1} and s.id > ?{2} order by s.code", fetchSize = FETCH_SIZE) + + " from samples s where s.saty_id=?{1} and s.id > ?{2}", fetchSize = FETCH_SIZE) public DataIterator<SampleRecord> getNewSamplesForSampleType(long sampleTypeId, int lastSeenSampleId); diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/samplelister/SampleListingWorker.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/samplelister/SampleListingWorker.java index f164ae69487ee3465eb827d54ae8ff4f451e3c56..4b01e61ff21634c47c79d2a9d01c6e469f75edf8 100644 --- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/samplelister/SampleListingWorker.java +++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/samplelister/SampleListingWorker.java @@ -217,8 +217,35 @@ final class SampleListingWorker watch.start(); } - // Only enrich the "primary" samples (matching the criteria) with properties, not - // dependent samples. + if (criteria.isEnrichDependentSamplesWithProperties() == false) + { + // only 'primary' samples were retrieved up to this point + enrichRetrievedSamplesWithProperties(watch); + } + retrieveDependentSamplesRecursively(); + resolveParents(); + resolveContainers(); + if (criteria.isEnrichDependentSamplesWithProperties()) + { + // dependent samples will also be enriched + enrichRetrievedSamplesWithProperties(watch); + } + + return sampleList; + } + + // + // Private worker methods + // + + private void enrichRetrievedSamplesWithProperties(StopWatch watch) + { + // Initialize property collections of all samples retrieved up to this point + // (without this enricher will not work properly). + for (Sample sample : sampleMap.values()) + { + sample.setProperties(new ArrayList<IEntityProperty>()); + } if (samplePropertiesEnricherOrNull != null) { samplePropertiesEnricherOrNull.enrich(sampleMap.keySet(), @@ -236,18 +263,8 @@ final class SampleListingWorker .toString())); } } - - retrieveDependentSamplesRecursively(); - resolveParents(); - resolveContainers(); - - return sampleList; } - // - // Private worker methods - // - private void loadGroups() { // all groups are needed for parent samples identifiers @@ -394,6 +411,9 @@ final class SampleListingWorker { return null; } + // uncomment if we want all dependent samples to be loaded + // maxSampleContainerResolutionDepth = Integer.MAX_VALUE; + // maxSampleParentResolutionDepth = Integer.MAX_VALUE; Long sampleTypeId = referencedEntityDAO.getSampleTypeIdForSampleTypeCode(criteria.getSampleTypeCode()); return query.getNewSamplesForSampleType(sampleTypeId, criteria.getLastSeenSampleId()); @@ -471,7 +491,6 @@ final class SampleListingWorker sample.setPermlink(PermlinkUtilities.createPermlinkURL(baseIndexURLOrNull, EntityKind.SAMPLE, row.perm_id)); sample.setRegistrationDate(row.registration_timestamp); - sample.setProperties(new ArrayList<IEntityProperty>()); if (row.inva_id != null) { final Invalidation invalidation = new Invalidation(); diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/ListOrSearchSampleCriteria.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/ListOrSearchSampleCriteria.java index bd3914502a0c4e00fecbfc705d23d6e9b789249b..a393847cde2b65ef318f18263464ee8b14f07220 100644 --- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/ListOrSearchSampleCriteria.java +++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/ListOrSearchSampleCriteria.java @@ -21,10 +21,15 @@ import java.util.Collection; import ch.systemsx.cisd.openbis.generic.shared.basic.TechId; /** - * Extended {@link ListSampleCriteria} with 4th filter option for detailed sample search and 5th - * option for tracking samples.<br> + * Extended {@link ListSampleCriteria} with 2 new filter options: + * <ul> + * <li>detailed sample search + * <li>tracking new samples of particular type + * </ul> + * Additionally one can decide if dependent samples that are loaded (parents and containers) should + * be enriched with properties. By default only 'primary' samples are enriched.<br> * <br> - * NOTE: not serializable + * NOTE: This bean is not serializable. * * @author Piotr Buczek */ @@ -38,6 +43,8 @@ public final class ListOrSearchSampleCriteria extends ListSampleCriteria private Collection<Long> sampleIds; + private boolean enrichDependentSamplesWithProperties = false; + /** Creates criteria that delegates to given {@link ListSampleCriteria}. */ public ListOrSearchSampleCriteria(ListSampleCriteria listCriteria) { @@ -122,4 +129,14 @@ public final class ListOrSearchSampleCriteria extends ListSampleCriteria return listCriteria == null ? false : listCriteria.isIncludeInstance(); } + public boolean isEnrichDependentSamplesWithProperties() + { + return enrichDependentSamplesWithProperties; + } + + public void setEnrichDependentSamplesWithProperties(boolean enrichDependentSamplesWithProperties) + { + this.enrichDependentSamplesWithProperties = enrichDependentSamplesWithProperties; + } + } diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/ListSampleCriteria.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/ListSampleCriteria.java index ad42bf82a270b35700337c4d56e096c0a83aa769..fceb15046954207cc0d87a1267334ccf44067a74 100644 --- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/ListSampleCriteria.java +++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/ListSampleCriteria.java @@ -24,10 +24,12 @@ import ch.systemsx.cisd.openbis.generic.shared.basic.TechId; /** * Criteria for listing <i>samples</i>. This class offers 3 kinds of filters, but only one can be - * used at the same time: <br> - * filter 1: samples of particular type in a specified group and/or shared <br> - * filter 2: samples belonging to a container sample<br> - * filter 3: samples from the experiment<br> + * used at the same time: + * <ol> + * <li>samples of particular type in a specified group and/or shared + * <li>samples belonging to a container sample + * <li>samples from the experiment + * </ol> * * @author Izabela Adamczyk * @author Tomasz Pylak @@ -36,7 +38,7 @@ import ch.systemsx.cisd.openbis.generic.shared.basic.TechId; public class ListSampleCriteria implements IsSerializable, Serializable { private static final long serialVersionUID = ServiceVersionHolder.VERSION; - + // --------- filter 1 fields private SampleType sampleType; diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/OpenbisClientTest.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/OpenbisClientTest.java index 4cd7442c7abe52191ccc4301818eefd036b7fc7b..42c3b79fae09ec2cb63697b5b70e7ee17d3e89dc 100644 --- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/OpenbisClientTest.java +++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/OpenbisClientTest.java @@ -4,6 +4,8 @@ import java.util.ArrayList; import java.util.List; import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang.builder.ToStringBuilder; +import org.apache.commons.lang.builder.ToStringStyle; import ch.systemsx.cisd.common.spring.HttpInvokerUtils; import ch.systemsx.cisd.openbis.generic.shared.ICommonServer; @@ -12,6 +14,7 @@ import ch.systemsx.cisd.openbis.generic.shared.basic.IEntityInformationHolder; import ch.systemsx.cisd.openbis.generic.shared.basic.TechId; import ch.systemsx.cisd.openbis.generic.shared.basic.dto.EntityKind; import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ExternalData; +import ch.systemsx.cisd.openbis.generic.shared.basic.dto.IEntityProperty; import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Person; import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Sample; import ch.systemsx.cisd.openbis.generic.shared.basic.dto.SampleParentWithDerived; @@ -107,30 +110,110 @@ public class OpenbisClientTest new TrackingSampleCriteria(sampleTypeCode, lastSeenSampleId); final List<Sample> samples = trackingServer.listSamples(session.getSessionToken(), sampleCriteria); - outputFoundEntities(samples, EntityKind.SAMPLE); + System.out.println(TrackingHelper.trackedEntitiesInformation(samples, EntityKind.SAMPLE)); final TrackingDataSetCriteria dataSetCriteria = new TrackingDataSetCriteria(sampleTypeCode, lastSeenDataSetId); final List<ExternalData> dataSets = trackingServer.listDataSets(session.getSessionToken(), dataSetCriteria); - outputFoundEntities(dataSets, EntityKind.DATA_SET); + System.out + .println(TrackingHelper.trackedEntitiesInformation(dataSets, EntityKind.DATA_SET)); } - private static void outputFoundEntities(List<? extends IEntityInformationHolder> entities, - EntityKind entityKind) + /** + * Helper class encapsulating methods used for producing readable information about entities + * returned by {@link ITrackingServer} methods. + * + * @author Piotr Buczek + */ + private static class TrackingHelper { - if (entities == null || entities.size() == 0) + + private static final String INDENT = " "; + + private static String trackedEntitiesInformation( + List<? extends IEntityInformationHolder> entities, EntityKind entityKind) { - System.out.println(String.format("No %ss found.", entityKind.getDescription())); - } else + if (entities == null || entities.size() == 0) + { + return String.format("\nNo %ss tracked.", entityKind.getDescription()); + } else + { + List<String> entityInfo = new ArrayList<String>(entities.size()); + for (IEntityInformationHolder entity : entities) + { + entityInfo.add(toString(entity)); + } + return String.format("\nTracked %d %s(s): \n%s", entityInfo.size(), entityKind + .getDescription(), StringUtils.join(entityInfo, "\n")); + } + } + + private static String toString(IEntityInformationHolder entity) { - List<String> codes = new ArrayList<String>(entities.size()); - for (IEntityInformationHolder entity : entities) + switch (entity.getEntityKind()) { - codes.add(entity.getCode()); + case SAMPLE: + return toString((Sample) entity); + case DATA_SET: + return toString((ExternalData) entity); + default: + throw new IllegalArgumentException(entity.getEntityKind() + + " is not supported "); } - System.out.println(String.format("Found %d %ss: %s", codes.size(), entityKind - .getDescription(), StringUtils.join(codes, ", "))); + } + + private static String toString(Sample sample) + { + return toString(sample, INDENT); + } + + private static String toString(Sample sample, String indent) + { + final StringBuilder sb = new StringBuilder(); + ToStringBuilder builder = new ToStringBuilder(sample, ToStringStyle.SHORT_PREFIX_STYLE); + builder.append("id", sample.getId()); + builder.append(" code", sample.getCode()); + builder.append(" identifier", sample.getIdentifier()); + builder.append(" type", sample.getSampleType()); + builder.append(" properties", toString(sample.getProperties())); + sb.append(builder.toString()); + final String newIndent = indent + INDENT; + if (sample.getContainer() != null) + { + sb.append("\n" + indent + "container"); + sb.append(toString(sample.getContainer(), newIndent)); + } + if (sample.getGeneratedFrom() != null) + { + sb.append("\n" + indent + "parent"); + sb.append(toString(sample.getGeneratedFrom(), newIndent)); + } + return sb.toString(); + } + + private static String toString(ExternalData dataSet) + { + final StringBuilder sb = new StringBuilder(); + ToStringBuilder builder = + new ToStringBuilder(dataSet, ToStringStyle.SHORT_PREFIX_STYLE); + builder.append("id", dataSet.getId()); + builder.append(" code", dataSet.getCode()); + builder.append(" type", dataSet.getDataSetType()); + builder.append(" properties", toString(dataSet.getProperties())); + sb.append(builder.toString()); + final String indent = INDENT; + if (dataSet.getSample() != null) + { + sb.append("\n" + indent + toString(dataSet.getSample())); + } + return sb.toString(); + } + + private static String toString(List<IEntityProperty> properties) + { + // output just collection size or null if initialized + return properties == null ? null : new Integer(properties.size()).toString(); } } }