All Downloads are FREE. Search and download functionalities are using the official Maven repository.

step.core.controller.settings.AbstractScopedObjectAccessor Maven / Gradle / Ivy

The newest version!
/*******************************************************************************
 * Copyright (C) 2020, exense GmbH
 *
 * This file is part of STEP
 *
 * STEP is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * STEP is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with STEP.  If not, see .
 ******************************************************************************/
package step.core.controller.settings;

import org.bson.types.ObjectId;
import step.core.access.User;
import step.core.accessors.AbstractAccessor;
import step.core.accessors.AbstractIdentifiableObject;
import step.core.collections.Collection;
import step.core.collections.Filter;
import step.core.collections.Filters;
import step.framework.server.Session;

import java.util.*;
import java.util.function.Predicate;
import java.util.stream.Collectors;

import static step.core.controller.settings.AbstractScopedObject.SCOPE_FIELD;

public class AbstractScopedObjectAccessor extends AbstractAccessor {

    private final ObjectScopeRegistry objectScopeRegistry;

    public AbstractScopedObjectAccessor(Collection collectionDriver, ObjectScopeRegistry objectScopeRegistry) {
        super(collectionDriver);
        this.objectScopeRegistry = objectScopeRegistry;
    }

    /**
     * Save object applying selected scope
     * @param baseScope the map of base scope info to be saved
     * @param scopedObject the scoped object to be saved
     * @param scopes the scope to be applied from the session context
     * @param session the related session (used to retrieve scope values)
     */
    public T saveScopedObject(Map baseScope, T scopedObject, List scopes, Session session) {
        //Override previous scope and id in case of update, i.e. if scope is changed we create a new entry
        AbstractIdentifiableObject previousScopedObject = get(scopedObject.getId());
        if (previousScopedObject != null) {
            scopedObject.setId(new ObjectId());
        }
        scopedObject.setScope(Objects.requireNonNullElse(new HashMap<>(baseScope), new HashMap<>()));
        //Enrich with requested scope based on session context
        objectScopeRegistry.addScopesToObject(scopedObject, scopes, session);
        // Cleaning up any existing objects with narrower scope. Example: an admin change the table settings for the
        // whole system, this will delete the settings saved with more specific  scope (user and/or project)
        cleanupObjectsWithNarrowerScopes(scopedObject, session);
        //Check if an entry exists for this exact combination of scope, and set for update in this case
        Optional byScope = (Optional) getByScope(scopedObject.getScope());
        byScope.ifPresent(s -> scopedObject.setId(s.getId()));
        //Finally save or update
        return save(scopedObject);
    }

    private void cleanupObjectsWithNarrowerScopes(T scopedObject, Session session) {
        //any entry saved with the same scope info + additional scope info are cleaned up
        List baseScopedObjects = this.collectionDriver.find(getBaseFilters(scopedObject.getScope()), null, null, null, 0).collect(Collectors.toList());
        baseScopedObjects.stream().filter(o -> o.getScope().size() > scopedObject.getScope().size()).forEach(o->this.remove(o.getId()));
    }

    /**
     * Retrieve the object having the requested base scope and with the highest priority given the current session context.
     * Example: one object with base scope settingId=A is stored for scope project=projectA and user=userA and another one only with scope user=userA.
     * If the session is for userA in project A, the first setting will be returned, if the session is for userA in projectB,
     * the 2nd setting will be returned, otherwise no setting will be returned
     * @param baseScope the map of static scope information (i.e. defined not the caller and not based on session context
     * @param session the session used to match stored objects by scope
     * @return optional scoped object
     */
    public Optional getScopedObject(Map baseScope, Session session) {
        Optional first = Optional.empty();
        Filter baseFilters = getBaseFilters(baseScope);
        List scopedObjects = this.collectionDriver.find(baseFilters, null, null, null, 0).collect(Collectors.toList());
        List>> predicateListsInPriorityOrder = objectScopeRegistry.getPredicateListsInPriorityOrder(session);
        for (List> predicateList : predicateListsInPriorityOrder) {
            first = scopedObjects.stream().filter(predicateList.stream().reduce(Predicate::and).orElse(x -> false)).findFirst();
            if (first.isPresent()) {
                break;
            }
        }
        return first;
    }

    private Filter getBaseFilters(Map baseScope) {
        return Filters.and(baseScope.entrySet().stream().map(e -> Filters.equals(SCOPE_FIELD + "." + e.getKey(), e.getValue())).collect(Collectors.toList()));
    }

    protected Optional getByScope(Map scopeMap) {
        //Return element which has the exact same scope, all element of the map matches and not other scope is defined
        Filter baseFilters = getBaseFilters(scopeMap);
        return this.collectionDriver.find(baseFilters, null, null, null, 0).filter(o -> o.getScope().size() == scopeMap.size()).findFirst();
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy