Skip to content

Commit 6fc0c4e

Browse files
authored
feat: add SyncedCachedEnforcer class (#438)
1 parent 9b60f70 commit 6fc0c4e

File tree

2 files changed

+419
-0
lines changed

2 files changed

+419
-0
lines changed
Lines changed: 334 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,334 @@
1+
// Copyright 2024 The casbin Authors. All Rights Reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package org.casbin.jcasbin.main;
16+
17+
import org.casbin.jcasbin.model.Model;
18+
import org.casbin.jcasbin.persist.Adapter;
19+
import org.casbin.jcasbin.persist.cache.Cache;
20+
import org.casbin.jcasbin.persist.cache.CacheableParam;
21+
import org.casbin.jcasbin.persist.cache.DefaultCache;
22+
23+
import java.time.Duration;
24+
import java.util.List;
25+
import java.util.concurrent.atomic.AtomicBoolean;
26+
import java.util.concurrent.locks.ReadWriteLock;
27+
import java.util.concurrent.locks.ReentrantReadWriteLock;
28+
29+
public class SyncedCachedEnforcer extends SyncedEnforcer{
30+
private Duration expireTime;
31+
private Cache cache;
32+
private final AtomicBoolean enableCache = new AtomicBoolean(true);
33+
private final static ReadWriteLock READ_WRITE_LOCK = new ReentrantReadWriteLock();
34+
35+
/**
36+
* Default constructor. Initializes a new SyncedCachedEnforcer with a default cache.
37+
*/
38+
public SyncedCachedEnforcer(){
39+
super();
40+
this.cache = new DefaultCache();
41+
}
42+
43+
/**
44+
* Initializes an enforcer with a model file and a policy file.
45+
*
46+
* @param modelPath The path of the model file.
47+
* @param policyFile The path of the policy file.
48+
*/
49+
public SyncedCachedEnforcer(String modelPath, String policyFile){
50+
super(modelPath, policyFile);
51+
this.cache = new DefaultCache();
52+
}
53+
54+
/**
55+
* Initializes an enforcer with a model file and a database adapter.
56+
*
57+
* @param modelPath The path of the model file.
58+
* @param adapter The adapter for the database.
59+
*/
60+
public SyncedCachedEnforcer(String modelPath, Adapter adapter) {
61+
super(modelPath, adapter);
62+
this.cache = new DefaultCache();
63+
}
64+
65+
/**
66+
* Initializes an enforcer with a model and a database adapter.
67+
*
68+
* @param m The model.
69+
* @param adapter The adapter for the database.
70+
*/
71+
public SyncedCachedEnforcer(Model m, Adapter adapter) {
72+
super(m, adapter);
73+
this.cache = new DefaultCache();
74+
}
75+
76+
/**
77+
* Initializes an enforcer with a model.
78+
*
79+
* @param m The model.
80+
*/
81+
public SyncedCachedEnforcer(Model m) {
82+
super(m);
83+
this.cache = new DefaultCache();
84+
}
85+
86+
/**
87+
* Initializes an enforcer with a model file.
88+
*
89+
* @param modelPath The path of the model file.
90+
*/
91+
public SyncedCachedEnforcer(String modelPath) {
92+
super(modelPath);
93+
this.cache = new DefaultCache();
94+
}
95+
96+
/**
97+
* Initializes an enforcer with a model file, a policy file, and a logging flag.
98+
*
99+
* @param modelPath The path of the model file.
100+
* @param policyFile The path of the policy file.
101+
* @param enableLog Whether to enable logging for Casbin.
102+
*/
103+
public SyncedCachedEnforcer(String modelPath, String policyFile, boolean enableLog) {
104+
super(modelPath, policyFile, enableLog);
105+
this.cache = new DefaultCache();
106+
}
107+
108+
/**
109+
* Enables or disables caching.
110+
*
111+
* @param enable Whether to enable caching.
112+
*/
113+
public void enableCache(boolean enable) {
114+
enableCache.set(enable);
115+
}
116+
117+
/**
118+
* Performs an enforcement check based on given parameters, using the cache.
119+
*
120+
* @param rvals Parameters for the enforcement check.
121+
* @return The result of the enforcement check.
122+
*/
123+
public boolean enforce(Object... rvals) {
124+
if (enableCache.get()) {
125+
return super.enforce(rvals);
126+
}
127+
128+
String key = getKey(rvals);
129+
if (key == null) {
130+
return super.enforce(rvals);
131+
}
132+
133+
Boolean cachedResult = getCachedResult(key);
134+
if (cachedResult) {
135+
return cachedResult;
136+
}
137+
138+
boolean result = super.enforce(rvals);
139+
setCachedResult(key, result, expireTime);
140+
return result;
141+
}
142+
143+
/**
144+
* Loads the policy, clearing the cache if enabled.
145+
*/
146+
public void loadPolicy() {
147+
if(enableCache == null || !enableCache.get()){
148+
super.loadPolicy();
149+
} else {
150+
if (enableCache.get()) {
151+
cache.clear();
152+
}
153+
super.loadPolicy();
154+
}
155+
}
156+
157+
/**
158+
* Adds a single policy while checking and removing the cache.
159+
*
160+
* @param params Policy parameters.
161+
* @return Whether the addition was successful.
162+
*/
163+
public boolean addPolicy(String... params) {
164+
if (!checkOneAndRemoveCache(params)) {
165+
return false;
166+
}
167+
return super.addPolicy(params);
168+
}
169+
170+
/**
171+
* Adds multiple policies while checking and removing the cache.
172+
*
173+
* @param rules Policy rules.
174+
* @return Whether the addition was successful.
175+
*/
176+
public boolean addPolicies(List<List<String>> rules) {
177+
if (!checkManyAndRemoveCache(rules)) {
178+
return false;
179+
}
180+
return super.addPolicies(rules);
181+
}
182+
183+
/**
184+
* Removes a single policy while checking and removing the cache.
185+
*
186+
* @param params Policy parameters.
187+
* @return Whether the removal was successful.
188+
*/
189+
public boolean removePolicy(String... params) {
190+
if (!checkOneAndRemoveCache(params)) {
191+
return false;
192+
}
193+
return super.removePolicy(params);
194+
}
195+
196+
/**
197+
* Removes multiple policies while checking and removing the cache.
198+
*
199+
* @param rules Policy rules.
200+
* @return Whether the removal was successful.
201+
*/
202+
public boolean removePolicies(List<List<String>>rules) {
203+
if (!checkManyAndRemoveCache(rules)) {
204+
return false;
205+
}
206+
return super.removePolicies(rules);
207+
}
208+
209+
/**
210+
* Retrieves a cached result based on the given key.
211+
*
212+
* @param key The cache key.
213+
* @return The cached result.
214+
*/
215+
private Boolean getCachedResult(String key) {
216+
try {
217+
READ_WRITE_LOCK.readLock().lock();
218+
return cache.get(key);
219+
} finally {
220+
READ_WRITE_LOCK.readLock().unlock();
221+
}
222+
}
223+
224+
/**
225+
* Sets the cache expiration time.
226+
*
227+
* @param expireTime The expiration time.
228+
*/
229+
public void setExpireTime(Duration expireTime) {
230+
READ_WRITE_LOCK.writeLock().lock();
231+
try {
232+
this.expireTime = expireTime;
233+
} finally {
234+
READ_WRITE_LOCK.writeLock().unlock();
235+
}
236+
}
237+
238+
/**
239+
* Sets a custom cache.
240+
*
241+
* @param cache The custom cache.
242+
*/
243+
public void setCache(Cache cache) {
244+
READ_WRITE_LOCK.writeLock().lock();
245+
try {
246+
this.cache = cache;
247+
} finally {
248+
READ_WRITE_LOCK.writeLock().unlock();
249+
}
250+
}
251+
252+
/**
253+
* Sets the cached result.
254+
*
255+
* @param key The cache key.
256+
* @param result The enforcement check result.
257+
* @param extra Additional parameters.
258+
*/
259+
private void setCachedResult(String key, boolean result, Object... extra) {
260+
cache.set(key, result, extra);
261+
}
262+
263+
/**
264+
* Retrieves a cache key from the given parameters.
265+
*
266+
* @param params The parameters for generating the key.
267+
* @return The generated cache key as a string.
268+
*/
269+
public String getCacheKey(Object... params) {
270+
StringBuilder key = new StringBuilder();
271+
for (Object param : params) {
272+
if (param instanceof String) {
273+
key.append((String) param);
274+
} else if (param instanceof CacheableParam) {
275+
key.append(((CacheableParam) param).getCacheKey());
276+
} else {
277+
return "";
278+
}
279+
key.append("$$");
280+
}
281+
return key.toString();
282+
}
283+
284+
/**
285+
* Generates a key based on the given parameters.
286+
*
287+
* @param params Parameters.
288+
* @return The generated key.
289+
*/
290+
private String getKey(Object... params) {
291+
return getCacheKey(params);
292+
}
293+
294+
/**
295+
* Invalidates the cache by clearing it.
296+
*/
297+
public void invalidateCache() {
298+
cache.clear();
299+
}
300+
301+
/**
302+
* Checks and removes cache for a single policy.
303+
*
304+
* @param params Policy parameters.
305+
* @return Whether the check was successful.
306+
*/
307+
private boolean checkOneAndRemoveCache(String... params) {
308+
if (enableCache.get()) {
309+
String key = getKey((Object) params);
310+
if (key != null) {
311+
cache.delete(key);
312+
}
313+
}
314+
return true;
315+
}
316+
317+
/**
318+
* Checks and removes cache for multiple policies.
319+
*
320+
* @param rules Policy rules.
321+
* @return Whether the check was successful.
322+
*/
323+
private boolean checkManyAndRemoveCache(List<List<String>> rules) {
324+
if (!rules.isEmpty() && enableCache.get()) {
325+
for (List<String> rule : rules) {
326+
String key = getKey(rule);
327+
if (key != null) {
328+
cache.delete(key);
329+
}
330+
}
331+
}
332+
return true;
333+
}
334+
}

0 commit comments

Comments
 (0)