/** * PermissionsEx * Copyright (C) zml and PermissionsEx contributors * * 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 ninja.leaping.permissionsex.subject; import com.github.benmanes.caffeine.cache.AsyncLoadingCache; import com.github.benmanes.caffeine.cache.Caffeine; import com.google.common.collect.Maps; import ninja.leaping.permissionsex.PermissionsEx; import ninja.leaping.permissionsex.backend.DataStore; import ninja.leaping.permissionsex.data.SubjectCache; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; /** * Collection holding data defining a type of subject. */ public class SubjectType { private final PermissionsEx pex; private SubjectTypeDefinition type; private SubjectCache persistentData, transientData; private final AsyncLoadingCache<String, CalculatedSubject> cache = Caffeine.newBuilder().buildAsync(((key, executor) -> { CalculatedSubject subj = new CalculatedSubject(SubjectDataBaker.inheritance(), Maps.immutableEntry(type.getTypeName(), key), SubjectType.this); return persistentData.getReference(key).thenCombine(transientData.getReference(key), (persistentRef, transientRef) -> { subj.initialize(persistentRef, transientRef); return subj; }); })); public SubjectType(PermissionsEx pex, String type, SubjectCache persistentData, SubjectCache transientData) { this.pex = pex; this.type = SubjectTypeDefinition.defaultFor(type); this.persistentData = persistentData; this.transientData = transientData; } public void setTypeInfo(SubjectTypeDefinition def) { this.type = def; } public SubjectTypeDefinition getTypeInfo() { return this.type; } public void cacheAll() { this.persistentData.cacheAll(); this.transientData.cacheAll(); } public Collection<CalculatedSubject> getActiveSubjects() { return Collections.unmodifiableCollection(this.cache.synchronous().asMap().values()); } public void uncache(String identifier) { if (!getTypeInfo().isNameValid(identifier)) { throw new IllegalArgumentException("Provided name " + identifier + " is not valid for subjects of type " + type.getTypeName()); } persistentData.invalidate(identifier); transientData.invalidate(identifier); cache.synchronous().invalidate(identifier); } public CompletableFuture<CalculatedSubject> get(String identifier) { if (!getTypeInfo().isNameValid(identifier)) { throw new IllegalArgumentException("Provided name " + identifier + " is not valid for subjects of type " + type.getTypeName()); } return cache.get(identifier); } public SubjectCache transientData() { return transientData; } public SubjectCache persistentData() { return persistentData; } PermissionsEx getManager() { return pex; } public void update(DataStore newDataStore) { this.persistentData.update(newDataStore); } public void load(String identifier) throws ExecutionException { this.persistentData.load(identifier); this.transientData.load(identifier); } public CompletableFuture<Boolean> isRegistered(String identifier) { return this.persistentData.isRegistered(identifier); } public Set<String> getAllIdentifiers() { Set<String> ret = new HashSet<>(); ret.addAll(this.persistentData.getAllIdentifiers()); ret.addAll(this.transientData.getAllIdentifiers()); return ret; } }