001/*
002 * PermissionsEx
003 * Copyright (C) zml and PermissionsEx contributors
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 *    http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package ca.stellardrift.permissionsex.datastore.sql;
018
019import ca.stellardrift.permissionsex.context.ContextValue;
020import ca.stellardrift.permissionsex.context.ContextInheritance;
021import ca.stellardrift.permissionsex.impl.util.PCollections;
022import org.checkerframework.checker.nullness.qual.Nullable;
023import org.pcollections.PMap;
024import org.pcollections.PVector;
025import org.pcollections.TreePVector;
026
027import java.sql.SQLException;
028import java.util.List;
029import java.util.Map;
030import java.util.concurrent.atomic.AtomicReference;
031
032public class SqlContextInheritance implements ContextInheritance {
033    private final PMap<ContextValue<?>, PVector<ContextValue<?>>> inheritance;
034    private final AtomicReference<PVector<CheckedBiConsumer<SqlDao, SqlContextInheritance, SQLException>>> updatesToPerform = new AtomicReference<>();
035
036    SqlContextInheritance(final PMap<ContextValue<?>, PVector<ContextValue<?>>> inheritance) {
037        this(inheritance, TreePVector.empty());
038    }
039
040    SqlContextInheritance(final PMap<ContextValue<?>, PVector<ContextValue<?>>> inheritance, final PVector<CheckedBiConsumer<SqlDao, SqlContextInheritance, SQLException>> updates) {
041        this.inheritance = inheritance;
042        this.updatesToPerform.set(updates);
043    }
044
045    @Override
046    public PVector<ContextValue<?>> parents(ContextValue<?> context) {
047        PVector<ContextValue<?>> ret = this.inheritance.get(context);
048        return ret == null ? PCollections.vector() : ret;
049    }
050
051    @Override
052    public SqlContextInheritance parents(final ContextValue<?> context, final @Nullable List<ContextValue<?>> parents) {
053        if (parents == null) {
054            return new SqlContextInheritance(this.inheritance.minus(context), this.updatesToPerform.get().plus((dao, inherit) -> {
055                dao.setContextInheritance(context, null);
056            }));
057        } else {
058            final PVector<ContextValue<?>> pParent = PCollections.asVector(parents);
059            return new SqlContextInheritance(this.inheritance.plus(context, pParent), this.updatesToPerform.get().plus((dao, inherit) -> {
060                final PVector<ContextValue<?>> newParents = inherit.parents(context);
061                if (!newParents.isEmpty()) {
062                    dao.setContextInheritance(context, newParents);
063                }
064            }));
065        }
066    }
067
068    @Override
069    public Map<ContextValue<?>, List<ContextValue<?>>> allParents() {
070        return PCollections.narrow(this.inheritance);
071    }
072
073    void doUpdate(SqlDao dao) throws SQLException {
074        List<CheckedBiConsumer<SqlDao, SqlContextInheritance, SQLException>> updates = updatesToPerform.getAndSet(TreePVector.empty());
075        for (CheckedBiConsumer<SqlDao, SqlContextInheritance, SQLException> action : updates) {
076            action.accept(dao, this);
077        }
078    }
079}