package com.constellio.model.services.users; import static com.constellio.data.dao.dto.records.OptimisticLockingResolution.EXCEPTION; import static com.constellio.data.utils.LangUtils.valueOrDefault; import static com.constellio.model.services.search.query.logical.LogicalSearchQueryOperators.from; import java.util.ArrayList; import java.util.Collections; import java.util.List; import com.constellio.data.dao.dto.records.OptimisticLockingResolution; import com.constellio.model.entities.records.ActionExecutorInBatch; import com.constellio.model.entities.records.Record; import com.constellio.model.entities.records.RecordUpdateOptions; import com.constellio.model.entities.records.Transaction; import com.constellio.model.entities.records.wrappers.Collection; import com.constellio.model.entities.schemas.Schemas; import com.constellio.model.entities.security.global.GlobalGroup; import com.constellio.model.entities.security.global.GlobalGroupStatus; import com.constellio.model.entities.security.global.SolrGlobalGroup; import com.constellio.model.services.factories.ModelLayerFactory; import com.constellio.model.services.factories.SystemCollectionListener; import com.constellio.model.services.records.RecordServicesException; import com.constellio.model.services.records.SchemasRecordsServices; import com.constellio.model.services.search.SearchServices; import com.constellio.model.services.search.query.logical.LogicalSearchQuery; import com.constellio.model.services.search.query.logical.condition.LogicalSearchCondition; import com.constellio.model.services.users.GlobalGroupsManagerRuntimeException.GlobalGroupsManagerRuntimeException_InvalidParent; import com.constellio.model.services.users.GlobalGroupsManagerRuntimeException.GlobalGroupsManagerRuntimeException_ParentNotFound; import com.constellio.model.services.users.GlobalGroupsManagerRuntimeException.GlobalGroupsManagerRuntimeException_RecordException; public class SolrGlobalGroupsManager implements GlobalGroupsManager, SystemCollectionListener { private final ModelLayerFactory modelLayerFactory; private final SearchServices searchServices; private final SchemasRecordsServices schemas; public SolrGlobalGroupsManager(ModelLayerFactory modelLayerFactory) { this.modelLayerFactory = modelLayerFactory; modelLayerFactory.addSystemCollectionListener(this); searchServices = modelLayerFactory.newSearchServices(); schemas = new SchemasRecordsServices(Collection.SYSTEM_COLLECTION, modelLayerFactory); } @Override public GlobalGroup create(String code, String name, List<String> collections, String parent, GlobalGroupStatus status, boolean locallyCreated) { return ((SolrGlobalGroup) valueOrDefault(getGlobalGroupWithCode(code), schemas.newGlobalGroup())) .setCode(code) .setName(name) .setUsersAutomaticallyAddedToCollections(collections) .setParent(parent) .setStatus(status) .withLocallyCreated(locallyCreated); } @Override public GlobalGroup create(String code, String parent, GlobalGroupStatus status, boolean locallyCreated) { return create(code, code, Collections.<String>emptyList(), parent, status, locallyCreated); } @Override public void addUpdate(GlobalGroup group) { SolrGlobalGroup groupRecord = (SolrGlobalGroup) group; validateHierarchy(groupRecord); try { modelLayerFactory.newRecordServices().add(groupRecord); } catch (RecordServicesException e) { // TODO: Exception e.printStackTrace(); } } @Override public void logicallyRemoveGroup(GlobalGroup group) { Transaction transaction = new Transaction(); for (GlobalGroup each : getGroupHierarchy((SolrGlobalGroup) group)) { transaction.add(((SolrGlobalGroup) each).setStatus(GlobalGroupStatus.INACTIVE).set(Schemas.LOGICALLY_DELETED_STATUS, true)); } try { modelLayerFactory.newRecordServices().execute(transaction); } catch (RecordServicesException e) { // TODO: Exception e.printStackTrace(); } } @Override public void activateGlobalGroupHierarchy(GlobalGroup group) { Transaction transaction = new Transaction(); for (GlobalGroup each : getGroupHierarchy((SolrGlobalGroup) group)) { transaction.add(((SolrGlobalGroup) each).setStatus(GlobalGroupStatus.ACTIVE)); } try { modelLayerFactory.newRecordServices().execute(transaction); } catch (RecordServicesException e) { // TODO: Exception e.printStackTrace(); } } @Override public GlobalGroup getGlobalGroupWithCode(String code) { Record group = searchServices.searchSingleResult( from(schemas.globalGroupSchemaType()).where(schemas.globalGroupCode()).isEqualTo(code)); return group != null ? schemas.wrapGlobalGroup(group) : null; } @Override public GlobalGroup getActiveGlobalGroupWithCode(String code) { GlobalGroup group = getGlobalGroupWithCode(code); return group != null && group.getStatus() == GlobalGroupStatus.ACTIVE ? group : null; } public LogicalSearchQuery getAllGroupsQuery() { return new LogicalSearchQuery(from(schemas.globalGroupSchemaType()).returnAll()).sortAsc(schemas.globalGroupCode()); } @Override public List<GlobalGroup> getAllGroups() { return schemas.wrapGlobalGroups(searchServices.search(getAllGroupsQuery())); } @Override public List<GlobalGroup> getHierarchy(String code) { SolrGlobalGroup group = (SolrGlobalGroup) getGlobalGroupWithCode(code); return group != null ? getGroupHierarchy(group) : Collections.<GlobalGroup>emptyList(); } public LogicalSearchQuery getActiveGroupsQuery() { return new LogicalSearchQuery( from(schemas.globalGroupSchemaType()).where(schemas.globalGroupStatus()).isEqualTo(GlobalGroupStatus.ACTIVE)) .sortAsc(schemas.globalGroupCode()); } @Override public List<GlobalGroup> getActiveGroups() { return schemas.wrapGlobalGroups(searchServices.search(getActiveGroupsQuery())); } public LogicalSearchQuery getGroupsInCollectionQuery(String collection) { return new LogicalSearchQuery( from(schemas.globalGroupSchemaType()).where(schemas.globalGroupCollections()).isEqualTo(collection)) .sortAsc(schemas.globalGroupCode()); } @Override public void removeCollection(final String collection) { try { new ActionExecutorInBatch(searchServices, "Remove collection in global groups", 100) { @Override public void doActionOnBatch(List<Record> records) throws Exception { Transaction transaction = new Transaction(); transaction.getRecordUpdateOptions().setOptimisticLockingResolution(EXCEPTION); for (Record record : records) { transaction.add((SolrGlobalGroup) schemas.wrapGlobalGroup(record)).withRemovedCollection(collection); } modelLayerFactory.newRecordServices().execute(transaction); } }.execute(getGroupsInCollectionQuery(collection)); } catch (Exception e) { throw new GlobalGroupsManagerRuntimeException_RecordException(e); } } @Override public void initialize() { // Nothing to be done } @Override public void close() { // Nothing to be done } @Override public void systemCollectionCreated() { } private List<GlobalGroup> getGroupHierarchy(SolrGlobalGroup group) { List<GlobalGroup> result = new ArrayList<>(); for (Record record : searchServices.search(getGroupHierarchyQuery(group))) { result.add(schemas.wrapGlobalGroup(record)); } return result; } private LogicalSearchQuery getGroupHierarchyQuery(SolrGlobalGroup group) { LogicalSearchCondition condition = from(schemas.globalGroupSchemaType()) .where(schemas.globalGroupCode()).isEqualTo(group.getCode()) .orWhere(schemas.globalGroupHierarchy()).isStartingWithText(group.getHierarchy() + "/"); return new LogicalSearchQuery(condition).sortAsc(schemas.globalGroupHierarchy()); } private void validateHierarchy(SolrGlobalGroup group) { if (group.getParent() == null) { group.setHierarchy(group.getCode()); return; } SolrGlobalGroup parent = (SolrGlobalGroup) getGlobalGroupWithCode(group.getParent()); if (parent == null) { throw new GlobalGroupsManagerRuntimeException_ParentNotFound(); } if (parent.getCode().equals(group.getCode()) || parent.getHierarchy().startsWith(group.getHierarchy() + "/")) { throw new GlobalGroupsManagerRuntimeException_InvalidParent(group.getParent()); } group.setHierarchy(parent.getHierarchy() + "/" + group.getCode()); } }