diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/authorization/PredicateExecutor.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/authorization/PredicateExecutor.java index e14b13d96a0d9781512a2b5415a9e9bf8e4aade5..f53ebde58f6ae7e9a6228ae3c6f262a559dfba82 100644 --- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/authorization/PredicateExecutor.java +++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/authorization/PredicateExecutor.java @@ -16,10 +16,12 @@ package ch.systemsx.cisd.openbis.generic.server.authorization; -import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; import org.hibernate.Query; import org.hibernate.Session; @@ -47,7 +49,10 @@ import ch.systemsx.cisd.openbis.generic.shared.dto.GroupPE; import ch.systemsx.cisd.openbis.generic.shared.dto.PersonPE; import ch.systemsx.cisd.openbis.generic.shared.dto.ProjectPE; import ch.systemsx.cisd.openbis.generic.shared.dto.QueryPE; +import ch.systemsx.cisd.openbis.generic.shared.dto.SampleAccessPE; import ch.systemsx.cisd.openbis.generic.shared.dto.SamplePE; +import ch.systemsx.cisd.openbis.plugin.generic.server.batch.BatchOperationExecutor; +import ch.systemsx.cisd.openbis.plugin.generic.server.batch.IBatchOperation; /** * A static class to execute {@link IPredicate}. @@ -255,54 +260,99 @@ public final class PredicateExecutor } } - @SuppressWarnings("unchecked") public DataSetAccessPE tryGetDatasetAccessData(String dataSetCode) { - Session sess = daoFactory.getSessionFactory().getCurrentSession(); - Query query = sess.getNamedQuery(DataSetAccessPE.DATASET_ACCESS_QUERY_NAME); - query = query.setReadOnly(true); - String[] codes = - { dataSetCode }; - List<DataSetAccessPE> results = - query.setParameterList(DataSetAccessPE.DATA_SET_CODES_PARAMETER_NAME, codes) - .list(); + Set<DataSetAccessPE> results = + getDatasetCollectionAccessData(Arrays.asList(dataSetCode)); if (results.size() < 1) return null; - return results.get(0); + return results.iterator().next(); } - @SuppressWarnings("unchecked") - public List<DataSetAccessPE> tryGetDatasetCollectionAccessData(List<String> dataSetCodes) + public Set<DataSetAccessPE> getDatasetCollectionAccessData(final List<String> dataSetCodes) { Session sess = daoFactory.getSessionFactory().getCurrentSession(); - Query query = sess.getNamedQuery(DataSetAccessPE.DATASET_ACCESS_QUERY_NAME); - query = query.setReadOnly(true); + final Query query = sess.getNamedQuery(DataSetAccessPE.DATASET_ACCESS_QUERY_NAME); + query.setReadOnly(true); // WORKAROUND Problem in Hibernate when the number of data set codes > 1000 // Though this query runs quickly within the pgadmin tool, even for large numbers of // data set codes, Hibernate becomes *very* slow when the size of the data set codes // exceeds 1000. For that reason, break down the query into smaller sections and // reassemble the results. - ArrayList<DataSetAccessPE> fullResults = new ArrayList<DataSetAccessPE>(); + final Set<DataSetAccessPE> fullResults = new HashSet<DataSetAccessPE>(); - int size = dataSetCodes.size(); - // blockSize is a magic number -- I don't know what the optimal value is, but execution - // speed slows down if the blockSize > 1999 - int blockSize = 999; - int start, end; - - // Loop over the codes, one block at a time - for (start = 0, end = Math.min(start + blockSize, size); start < size; start = end, end = - Math.min(start + blockSize, size)) - { - List<String> sublist = dataSetCodes.subList(start, end); - query = + BatchOperationExecutor.executeInBatches(new IBatchOperation<String>() + { + public void execute(List<String> entities) + { query.setParameterList(DataSetAccessPE.DATA_SET_CODES_PARAMETER_NAME, - sublist); - List<DataSetAccessPE> results = query.list(); - fullResults.addAll(results); - } + entities); + List<DataSetAccessPE> results = cast(query.list()); + fullResults.addAll(results); + } + + public List<String> getAllEntities() + { + return dataSetCodes; + } + + public String getEntityName() + { + return "dataset"; + } + + public String getOperationName() + { + return "authorization"; + } + }); + + return fullResults; + } + + public Set<SampleAccessPE> getSampleCollectionAccessData(final List<TechId> sampleTechIds) + { + Session sess = daoFactory.getSessionFactory().getCurrentSession(); + final Query querySpaceSamples = + sess.getNamedQuery(SampleAccessPE.SPACE_SAMPLE_ACCESS_QUERY_NAME); + querySpaceSamples.setReadOnly(true); + final Query querySharedSamples = + sess.getNamedQuery(SampleAccessPE.SHARED_SAMPLE_ACCESS_QUERY_NAME); + querySharedSamples.setReadOnly(true); + + final Set<SampleAccessPE> fullResults = new HashSet<SampleAccessPE>(); + + BatchOperationExecutor.executeInBatches(new IBatchOperation<TechId>() + { + public void execute(List<TechId> entities) + { + querySpaceSamples.setParameterList( + SampleAccessPE.SAMPLE_IDS_PARAMETER_NAME, TechId.asLongs(entities)); + querySharedSamples.setParameterList( + SampleAccessPE.SAMPLE_IDS_PARAMETER_NAME, TechId.asLongs(entities)); + List<SampleAccessPE> spaceSamples = cast(querySpaceSamples.list()); + List<SampleAccessPE> sharedSamples = cast(querySharedSamples.list()); + fullResults.addAll(spaceSamples); + fullResults.addAll(sharedSamples); + } + + public List<TechId> getAllEntities() + { + return sampleTechIds; + } + + public String getEntityName() + { + return "sample"; + } + + public String getOperationName() + { + return "authorization"; + } + }); return fullResults; } @@ -352,5 +402,18 @@ public final class PredicateExecutor return daoFactory.getQueryDAO().getByTechId(techId); } + /** + * Casts given <var>list</var> to specified type. + * <p> + * The purpose of this method is to avoid <code>SuppressWarnings("unchecked")</code> in + * calling methods. + * </p> + */ + @SuppressWarnings("unchecked") + private static final <T> List<T> cast(final List list) + { + return list; + } + } } diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/ICommonServer.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/ICommonServer.java index 3689e98855bf8d7ecddf30d0dd14b22d65a6efec..14b23da2346cdc8e7fe3ac85b6c3b8fecdfe027a 100644 --- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/ICommonServer.java +++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/ICommonServer.java @@ -31,6 +31,7 @@ import ch.systemsx.cisd.openbis.generic.shared.authorization.predicate.DataSetCo import ch.systemsx.cisd.openbis.generic.shared.authorization.predicate.DataSetCodePredicate; import ch.systemsx.cisd.openbis.generic.shared.authorization.predicate.ListSampleCriteriaPredicate; import ch.systemsx.cisd.openbis.generic.shared.authorization.predicate.ProjectUpdatesPredicate; +import ch.systemsx.cisd.openbis.generic.shared.authorization.predicate.SampleTechIdCollectionPredicate; import ch.systemsx.cisd.openbis.generic.shared.authorization.predicate.SampleTechIdPredicate; import ch.systemsx.cisd.openbis.generic.shared.authorization.predicate.SpaceIdentifierPredicate; import ch.systemsx.cisd.openbis.generic.shared.authorization.predicate.AbstractExpressionPredicate.DeleteGridCustomColumnPredicate; @@ -643,8 +644,9 @@ public interface ICommonServer extends IServer @Transactional @RolesAllowed(RoleSet.POWER_USER) @DatabaseCreateOrDeleteModification(value = ObjectKind.SAMPLE) - public void deleteSamples(String sessionToken, - @AuthorizationGuard(guardClass = SampleTechIdPredicate.class) List<TechId> sampleIds, + public void deleteSamples( + String sessionToken, + @AuthorizationGuard(guardClass = SampleTechIdCollectionPredicate.class) List<TechId> sampleIds, String reason); /** diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/authorization/IAuthorizationDataProvider.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/authorization/IAuthorizationDataProvider.java index 66de4b37e1b45ce331e97317a4d794227addb66b..f0ca31bd9b4deb2b5d6a47a58ed1bd92aa402669 100644 --- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/authorization/IAuthorizationDataProvider.java +++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/authorization/IAuthorizationDataProvider.java @@ -17,6 +17,7 @@ package ch.systemsx.cisd.openbis.generic.shared.authorization; import java.util.List; +import java.util.Set; import ch.systemsx.cisd.openbis.generic.shared.IDatabaseInstanceFinder; import ch.systemsx.cisd.openbis.generic.shared.basic.PermId; @@ -27,6 +28,7 @@ import ch.systemsx.cisd.openbis.generic.shared.dto.GridCustomFilterPE; import ch.systemsx.cisd.openbis.generic.shared.dto.GroupPE; import ch.systemsx.cisd.openbis.generic.shared.dto.ProjectPE; import ch.systemsx.cisd.openbis.generic.shared.dto.QueryPE; +import ch.systemsx.cisd.openbis.generic.shared.dto.SampleAccessPE; import ch.systemsx.cisd.openbis.generic.shared.dto.SamplePE; /** @@ -56,7 +58,12 @@ public interface IAuthorizationDataProvider extends IDatabaseInstanceFinder /** * Returns the information necessary to determine if a user is allowed to access the data sets. */ - public List<DataSetAccessPE> tryGetDatasetCollectionAccessData(List<String> dataSetCodes); + public Set<DataSetAccessPE> getDatasetCollectionAccessData(List<String> dataSetCodes); + + /** + * Returns the information necessary to determine if a user is allowed to access the samples. + */ + public Set<SampleAccessPE> getSampleCollectionAccessData(List<TechId> sampleIds); /** * Returns the group of an entity with given <var>entityKind</var> and <var>techId</var> diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/authorization/predicate/DataSetCodeCollectionPredicate.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/authorization/predicate/DataSetCodeCollectionPredicate.java index a171ef03edbcde5c4305b11b944c443a363e8f6a..28e193c23e5c60f42eaef286b7bf9e9cbe424a45 100644 --- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/authorization/predicate/DataSetCodeCollectionPredicate.java +++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/authorization/predicate/DataSetCodeCollectionPredicate.java @@ -17,6 +17,7 @@ package ch.systemsx.cisd.openbis.generic.shared.authorization.predicate; import java.util.List; +import java.util.Set; import ch.systemsx.cisd.common.exceptions.Status; import ch.systemsx.cisd.openbis.generic.shared.authorization.RoleWithIdentifier; @@ -44,13 +45,8 @@ public class DataSetCodeCollectionPredicate extends AbstractGroupPredicate<List< { assert initialized : "Predicate has not been initialized"; - List<DataSetAccessPE> accessData = - authorizationDataProvider.tryGetDatasetCollectionAccessData(dataSetCodes); - - if (accessData == null) - { - return Status.OK; - } + Set<DataSetAccessPE> accessData = + authorizationDataProvider.getDatasetCollectionAccessData(dataSetCodes); for (DataSetAccessPE accessDatum : accessData) { diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/authorization/predicate/DelegatedPredicate.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/authorization/predicate/DelegatedPredicate.java index 5cb8e4f230add9acfde9417ac101b5b3ab4aee4e..61181f2605084763493daa2be3c9a7cfaef9f8b2 100644 --- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/authorization/predicate/DelegatedPredicate.java +++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/authorization/predicate/DelegatedPredicate.java @@ -39,6 +39,8 @@ public abstract class DelegatedPredicate<P, T> extends AbstractPredicate<T> { private final IPredicate<P> delegate; + protected IAuthorizationDataProvider authorizationDataProvider; + public DelegatedPredicate(final IPredicate<P> delegate) { this.delegate = delegate; @@ -55,6 +57,7 @@ public abstract class DelegatedPredicate<P, T> extends AbstractPredicate<T> public final void init(IAuthorizationDataProvider provider) { + this.authorizationDataProvider = provider; delegate.init(provider); } diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/authorization/predicate/SampleTechIdCollectionPredicate.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/authorization/predicate/SampleTechIdCollectionPredicate.java new file mode 100644 index 0000000000000000000000000000000000000000..3852ff440af04f6d875ba9420e1c48b322d2e2a6 --- /dev/null +++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/authorization/predicate/SampleTechIdCollectionPredicate.java @@ -0,0 +1,77 @@ +/* + * Copyright 2009 ETH Zuerich, CISD + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ch.systemsx.cisd.openbis.generic.shared.authorization.predicate; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +import ch.systemsx.cisd.openbis.generic.shared.authorization.annotation.ShouldFlattenCollections; +import ch.systemsx.cisd.openbis.generic.shared.basic.TechId; +import ch.systemsx.cisd.openbis.generic.shared.dto.SampleAccessPE; +import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.DatabaseInstanceIdentifier; +import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleOwnerIdentifier; +import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SpaceIdentifier; + +/** + * An <code>IPredicate</code> implementation based on a list of sample {@link TechId}s. + * + * @author Piotr Buczek + */ +@ShouldFlattenCollections(value = false) +public class SampleTechIdCollectionPredicate extends + DelegatedPredicate<List<SampleOwnerIdentifier>, List<TechId>> +{ + + public SampleTechIdCollectionPredicate() + { + super(new SampleOwnerIdentifierCollectionPredicate(true)); + } + + @Override + public List<SampleOwnerIdentifier> convert(List<TechId> techIds) + { + ArrayList<SampleOwnerIdentifier> ownerIds = new ArrayList<SampleOwnerIdentifier>(); + + Set<SampleAccessPE> accessData = + authorizationDataProvider.getSampleCollectionAccessData(techIds); + + for (SampleAccessPE accessDatum : accessData) + { + String groupCode = accessDatum.getGroupCode(); + String dbInstanceCode = accessDatum.getDatabaseInstanceCode(); + if (groupCode != null) + { + ownerIds.add(new SampleOwnerIdentifier(new SpaceIdentifier( + DatabaseInstanceIdentifier.createHome(), groupCode))); + } else + { + ownerIds.add(new SampleOwnerIdentifier(new DatabaseInstanceIdentifier( + dbInstanceCode))); + } + } + + return ownerIds; + } + + @Override + public final String getCandidateDescription() + { + return "sample technical ids"; + } + +} diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/TechId.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/TechId.java index a0a130b4d1e81f3933c57085cdc366abda6f2038..2e174712b2e495f2b66e1828634714205b62a61e 100644 --- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/TechId.java +++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/TechId.java @@ -88,6 +88,21 @@ public class TechId implements IIdHolder, IsSerializable, Serializable return results; } + /** + * Convenience method for getting a list of long ids from given list of {@link TechId}s. + * + * @see #create(IIdHolder) + */ + public static List<Long> asLongs(List<TechId> techIds) + { + List<Long> results = new ArrayList<Long>(); + for (TechId techId : techIds) + { + results.add(techId.getId()); + } + return results; + } + public Long getId() { return id; diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/DataSetAccessPE.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/DataSetAccessPE.java index 479ca131da1f4ba45c874de2adfc0b7ea6f58444..9b00a972cd40110adf3a1ed0471427af9b7d8694 100644 --- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/DataSetAccessPE.java +++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/DataSetAccessPE.java @@ -22,6 +22,9 @@ import javax.persistence.Id; import javax.persistence.NamedNativeQuery; import javax.persistence.SqlResultSetMapping; +import org.apache.commons.lang.builder.EqualsBuilder; +import org.apache.commons.lang.builder.HashCodeBuilder; + /** * A PE for retrieving only the information necessary to determine if a user/person can access a * data set. @@ -94,4 +97,37 @@ public class DataSetAccessPE { return databaseInstanceCode; } + + // + // Object + // + + @Override + public boolean equals(Object obj) + { + if (obj == this) + { + return true; + } + if (obj instanceof DataSetAccessPE == false) + { + return false; + } + final DataSetAccessPE that = (DataSetAccessPE) obj; + final EqualsBuilder builder = new EqualsBuilder(); + builder.append(getGroupCode(), that.getGroupCode()); + builder.append(getDatabaseInstanceCode(), that.getDatabaseInstanceCode()); + builder.append(getDatabaseInstanceUuid(), that.getDatabaseInstanceUuid()); + return builder.isEquals(); + } + + @Override + public int hashCode() + { + final HashCodeBuilder builder = new HashCodeBuilder(); + builder.append(getGroupCode()); + builder.append(getDatabaseInstanceCode()); + builder.append(getDatabaseInstanceUuid()); + return builder.toHashCode(); + } } diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/SampleAccessPE.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/SampleAccessPE.java new file mode 100644 index 0000000000000000000000000000000000000000..cde0b2e324c72d973ce75989921ea15406eb71f0 --- /dev/null +++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/SampleAccessPE.java @@ -0,0 +1,136 @@ +/* + * Copyright 2010 ETH Zuerich, CISD + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ch.systemsx.cisd.openbis.generic.shared.dto; + +import javax.persistence.Entity; +import javax.persistence.EntityResult; +import javax.persistence.Id; +import javax.persistence.NamedNativeQueries; +import javax.persistence.NamedNativeQuery; +import javax.persistence.SqlResultSetMapping; +import javax.persistence.SqlResultSetMappings; + +import org.apache.commons.lang.builder.EqualsBuilder; +import org.apache.commons.lang.builder.HashCodeBuilder; + +/** + * A PE for retrieving only the information necessary to determine if a user/person can access a + * sample. + * + * @author Piotr Buczek + */ +@Entity +@SqlResultSetMappings(value = + { + @SqlResultSetMapping(name = "implicit1", entities = @EntityResult(entityClass = SampleAccessPE.class)), + @SqlResultSetMapping(name = "implicit2", entities = @EntityResult(entityClass = SampleAccessPE.class)) + + }) +@NamedNativeQueries(value = + { + @NamedNativeQuery(name = "space_sample_access", query = "SELECT DISTINCT g.code as groupCode, null as databaseInstanceCode " + + "FROM " + + TableNames.SAMPLES_TABLE + + " s, " + + TableNames.GROUPS_TABLE + + " g " + + "WHERE s.id in (:ids) and s.grou_id = g.id", resultSetMapping = "implicit1"), + @NamedNativeQuery(name = "shared_sample_access", query = "SELECT DISTINCT dbi.code as databaseInstanceCode, null as groupCode " + + "FROM " + + TableNames.SAMPLES_TABLE + + " s, " + + TableNames.DATABASE_INSTANCES_TABLE + + " dbi " + + "WHERE s.id in (:ids) and s.dbin_id = dbi.id", resultSetMapping = "implicit2") + + }) +public class SampleAccessPE +{ + private String groupCode; + + private String databaseInstanceCode; + + public final static String SPACE_SAMPLE_ACCESS_QUERY_NAME = "space_sample_access"; + + public final static String SHARED_SAMPLE_ACCESS_QUERY_NAME = "shared_sample_access"; + + public final static String SAMPLE_IDS_PARAMETER_NAME = "ids"; + + /** + * A factory method that should only be used for testing. + */ + public static SampleAccessPE createSampleAccessPEForTest(String dataSetId, String dataSetCode, + String groupCode, String databaseInstanceCode) + { + SampleAccessPE newMe = new SampleAccessPE(); + newMe.setGroupCode(groupCode); + newMe.setDatabaseInstanceCode(databaseInstanceCode); + return newMe; + } + + void setGroupCode(String groupCode) + { + this.groupCode = groupCode; + } + + void setDatabaseInstanceCode(String databaseInstanceCode) + { + this.databaseInstanceCode = databaseInstanceCode; + } + + @Id + public String getGroupCode() + { + return groupCode; + } + + public String getDatabaseInstanceCode() + { + return databaseInstanceCode; + } + + // + // Object + // + + @Override + public boolean equals(Object obj) + { + if (obj == this) + { + return true; + } + if (obj instanceof SampleAccessPE == false) + { + return false; + } + final SampleAccessPE that = (SampleAccessPE) obj; + final EqualsBuilder builder = new EqualsBuilder(); + builder.append(getGroupCode(), that.getGroupCode()); + builder.append(getDatabaseInstanceCode(), that.getDatabaseInstanceCode()); + return builder.isEquals(); + } + + @Override + public int hashCode() + { + final HashCodeBuilder builder = new HashCodeBuilder(); + builder.append(getGroupCode()); + builder.append(getDatabaseInstanceCode()); + return builder.toHashCode(); + } +} diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/server/GenericDataSetTypeSlaveServerPlugin.java b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/server/GenericDataSetTypeSlaveServerPlugin.java index 97df9049ff7a94f893c63ef0b5fcb5b81693845d..198be640dc51ab38c7a9ca8e43c5d265f6080d7c 100644 --- a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/server/GenericDataSetTypeSlaveServerPlugin.java +++ b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/server/GenericDataSetTypeSlaveServerPlugin.java @@ -59,8 +59,8 @@ public class GenericDataSetTypeSlaveServerPlugin implements IDataSetTypeSlaveSer assert session != null : "Unspecified session."; assert newDataSets != null && newDataSets.size() > 0 : "Unspecified data set or empty data sets."; - new BatchOperationExecutor<NewDataSet>().executeInBatches(new DataSetBatchUpdate( - businessObjectFactory.createExternalDataTable(session), newDataSets)); + BatchOperationExecutor.executeInBatches(new DataSetBatchUpdate(businessObjectFactory + .createExternalDataTable(session), newDataSets)); } } diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/server/GenericSampleTypeSlaveServerPlugin.java b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/server/GenericSampleTypeSlaveServerPlugin.java index ccd7eb52b9df7adb14f76e7bdd27e9f981584a9f..c4967d6d1c9c8ba3f198cd0877c1ef293e081980 100644 --- a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/server/GenericSampleTypeSlaveServerPlugin.java +++ b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/server/GenericSampleTypeSlaveServerPlugin.java @@ -79,8 +79,8 @@ public final class GenericSampleTypeSlaveServerPlugin implements ISampleTypeSlav assert session != null : "Unspecified session."; assert newSamples != null && newSamples.size() > 0 : "Unspecified sample or empty samples."; - new BatchOperationExecutor<NewSample>().executeInBatches(new SampleBatchRegistration( - businessObjectFactory.createSampleTable(session), newSamples)); + BatchOperationExecutor.executeInBatches(new SampleBatchRegistration(businessObjectFactory + .createSampleTable(session), newSamples)); } public void updateSamples(Session session, List<SampleBatchUpdatesDTO> updateSamples) @@ -88,7 +88,7 @@ public final class GenericSampleTypeSlaveServerPlugin implements ISampleTypeSlav assert session != null : "Unspecified session."; assert updateSamples != null && updateSamples.size() > 0 : "Unspecified sample or empty samples."; - new BatchOperationExecutor<SampleBatchUpdatesDTO>().executeInBatches(new SampleBatchUpdate( - businessObjectFactory.createSampleTable(session), updateSamples)); + BatchOperationExecutor.executeInBatches(new SampleBatchUpdate(businessObjectFactory + .createSampleTable(session), updateSamples)); } } diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/server/GenericServer.java b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/server/GenericServer.java index c20671abbbf0e67ffd1dc22b032c4772fdfa535e..6e6084bc7f6bbde252771305d4e1eaa922c389e1 100644 --- a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/server/GenericServer.java +++ b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/server/GenericServer.java @@ -274,10 +274,9 @@ public final class GenericServer extends AbstractServer<IGenericServer> implemen registerSamples(session, samples); } else { - new BatchOperationExecutor<NewSample>() - .executeInBatches(new SampleBatchRegisterOrUpdate(businessObjectFactory - .createSampleLister(session), samples.getNewSamples(), samples - .getSampleType(), session)); + BatchOperationExecutor.executeInBatches(new SampleBatchRegisterOrUpdate( + businessObjectFactory.createSampleLister(session), samples.getNewSamples(), + samples.getSampleType(), session)); } } } diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/server/batch/BatchOperationExecutor.java b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/server/batch/BatchOperationExecutor.java index dee516faddee20382b59f5944ab041cbad0de8fa..3d50e443f041f84d864c2d0aeadfddc00a203554 100644 --- a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/server/batch/BatchOperationExecutor.java +++ b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/server/batch/BatchOperationExecutor.java @@ -12,33 +12,34 @@ import ch.systemsx.cisd.common.logging.LogFactory; * * @author Izabela Adamczyk */ -public class BatchOperationExecutor<S> +public class BatchOperationExecutor { private static final Logger operationLog = LogFactory.getLogger(LogCategory.OPERATION, BatchOperationExecutor.class); private static final int DEFAULT_BATCH_SIZE = 1000; - public void executeInBatches(IBatchOperation<S> strategy) + public static <S> void executeInBatches(IBatchOperation<S> strategy) { executeInBatches(strategy, DEFAULT_BATCH_SIZE); } - public void executeInBatches(IBatchOperation<S> strategy, int batchSize) + public static <S> void executeInBatches(IBatchOperation<S> strategy, int batchSize) { assert strategy != null : "Unspecified operation."; final List<S> allEntities = strategy.getAllEntities(); - int startIndex = 0; int maxIndex = allEntities.size(); - while (startIndex < maxIndex) + + // Loop over the list, one block at a time + for (int startIndex = 0, endIndex = Math.min(startIndex + batchSize, maxIndex); startIndex < maxIndex; startIndex = + endIndex, endIndex = Math.min(startIndex + batchSize, maxIndex)) { - final int endIndex = Math.min(startIndex + batchSize, maxIndex); final List<S> batch = allEntities.subList(startIndex, endIndex); strategy.execute(batch); operationLog.info(String.format("%s %s progress: %d/%d", strategy.getEntityName(), strategy.getOperationName(), endIndex, maxIndex)); - startIndex += batchSize; } } + } \ No newline at end of file