Skip to content

Commit 3e7cacd

Browse files
committed
new MaxSizeMap for caching stuff, ThreadManager for easy run
1 parent 3f8f664 commit 3e7cacd

File tree

4 files changed

+191
-0
lines changed

4 files changed

+191
-0
lines changed

src/main/java/net/b07z/sepia/server/core/data/CmdMap.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,21 @@ public class CmdMap {
2525
private List<String> permissions;
2626

2727
@SuppressWarnings("unchecked")
28+
/**
29+
* Import command map from JSON.
30+
* @param entry
31+
*/
2832
public CmdMap(JSONObject entry){
2933
this.command = JSON.getString(entry, "command");
3034
this.services = new ArrayList<>((JSONArray)entry.get("services"));
3135
this.permissions = new ArrayList<>((JSONArray)entry.get("permissions"));
3236
}
37+
/**
38+
* Create a new command map.
39+
* @param command
40+
* @param services
41+
* @param permissions
42+
*/
3343
public CmdMap(String command, List<String> services, List<String> permissions){
3444
this.command = command;
3545
this.services = services;
@@ -52,6 +62,10 @@ public boolean equals(Object map){
5262
return false;
5363
}
5464
}
65+
@Override
66+
public String toString(){
67+
return (this.command + " - services: " + this.services.size());
68+
}
5569

5670
public String getCommand(){
5771
return command;
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package net.b07z.sepia.server.core.java;
2+
3+
import java.util.Collections;
4+
import java.util.LinkedHashMap;
5+
import java.util.Map;
6+
7+
/**
8+
* A Map implementation that uses {@LinkedHashMap} to features to keep the size limited to a maximum and drop the oldest entry on overflow.<br>
9+
* NOTE: Check the constructor on notes about concurrency.
10+
*
11+
* @author Florian Quirin
12+
*
13+
* @param <K>
14+
* @param <V>
15+
*/
16+
public class MaxSizeMap<K, V> extends LinkedHashMap<K, V> {
17+
18+
private static final long serialVersionUID = 1L;
19+
20+
private int maxKeysSize;
21+
22+
/**
23+
* Create a {@LinkedHashMap} that automatically removes the oldest entry when size is exceeded.<br>
24+
* <br>
25+
* IMPORTANT: This map (as is it basically a linked hash map) can run into concurrency problems, use {@link #getSynchronizedMap(int)}
26+
* or build your own Collections.synchronizedMap(...) if you access the list from multiple threads.
27+
* @param maxSize
28+
*/
29+
public MaxSizeMap(int maxSize){
30+
super(maxSize + 1);
31+
this.maxKeysSize = maxSize;
32+
}
33+
/**
34+
* Create a synchronized version of this map.
35+
* @param maxSize
36+
* @return
37+
*/
38+
public static <T> Map<String, T> getSynchronizedMap(int maxSize){
39+
return Collections.synchronizedMap(new MaxSizeMap<String, T>(maxSize));
40+
}
41+
42+
@Override
43+
protected boolean removeEldestEntry(final Map.Entry<K, V> eldest) {
44+
return size() > maxKeysSize;
45+
}
46+
47+
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
package net.b07z.sepia.server.core.tools;
2+
3+
import java.util.List;
4+
import java.util.concurrent.ExecutorService;
5+
import java.util.concurrent.Executors;
6+
import java.util.concurrent.TimeUnit;
7+
8+
/**
9+
* A class to easily run threaded tasks.
10+
*
11+
* @author Florian Quirin
12+
*
13+
*/
14+
public class ThreadManager {
15+
16+
/**
17+
* Interface to define a task. Has one method 'run(Object o)' that should make appropriate type casting of the object.
18+
* Usually used via lambda expression, e.g.:<br>
19+
* <br>
20+
* (Object o) -> { System.out.println(o.toString()); }
21+
*/
22+
public static interface ThreadManagerTask {
23+
public void run(Object o);
24+
}
25+
26+
/**
27+
* Run a given task ({@link ThreadManagerTask}) with parameters in a certain number of threads
28+
* and wait for completion or timeout.
29+
* @param numOfThreads - number of threads to use
30+
* @param myTask - {@link ThreadManagerTask} implementation (has to overwrite run(Object o) method).
31+
* @param parameters - List of objects used in myTask (one for each task)
32+
* @param timeoutMs - wait at most this time (ms)
33+
* @return
34+
* @throws Exception
35+
*/
36+
public static boolean runTasks(int numOfThreads, ThreadManagerTask myTask, List<?> parameters,
37+
long timeoutMs) throws Exception {
38+
39+
//Create executor
40+
ExecutorService threadPool = Executors.newFixedThreadPool(numOfThreads);
41+
42+
//Run all tasks
43+
for (Object o : parameters){
44+
Runnable worker = () -> {
45+
myTask.run(o);
46+
};
47+
threadPool.execute(worker);
48+
}
49+
50+
//Await termination
51+
try{
52+
awaitTerminationAfterShutdown(threadPool, timeoutMs);
53+
return true;
54+
55+
}catch (InterruptedException ex){
56+
ex.printStackTrace();
57+
return false;
58+
}
59+
}
60+
/**
61+
* Await thread pool termination or force quit on timeout.
62+
*/
63+
private static void awaitTerminationAfterShutdown(ExecutorService threadPool,
64+
long timeoutMs) throws InterruptedException {
65+
threadPool.shutdown();
66+
try{
67+
if (!threadPool.awaitTermination(timeoutMs, TimeUnit.MILLISECONDS)) {
68+
threadPool.shutdownNow();
69+
}
70+
}catch (InterruptedException ex){
71+
threadPool.shutdownNow();
72+
Thread.currentThread().interrupt();
73+
throw ex;
74+
}
75+
}
76+
77+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package tools;
2+
3+
import java.util.ArrayList;
4+
import java.util.Arrays;
5+
import java.util.List;
6+
import java.util.Map;
7+
8+
import net.b07z.sepia.server.core.data.CmdMap;
9+
import net.b07z.sepia.server.core.java.MaxSizeMap;
10+
import net.b07z.sepia.server.core.tools.ThreadManager;
11+
12+
public class Test_MaxSizeMap {
13+
14+
private static final class UserTestData {
15+
public String name;
16+
public List<CmdMap> map;
17+
public UserTestData(String name, List<CmdMap> map){
18+
this.name = name;
19+
this.map = map;
20+
}
21+
}
22+
23+
public static void main(String[] args) throws Exception {
24+
25+
//TODO: make this a real JUnit test
26+
27+
Map<String, List<CmdMap>> map = MaxSizeMap.getSynchronizedMap(5);
28+
29+
List<String> users = Arrays.asList("uid1", "uid2", "uid3", "uid4", "uid5", "uid6", "uid7", "uid8", "uid9", "uid10");
30+
List<UserTestData> data = new ArrayList<>();
31+
for (String u : users){
32+
List<CmdMap> cmdm = new ArrayList<>();
33+
cmdm.add(new CmdMap(u + ".anyCmd", new ArrayList<>(), Arrays.asList("all")));
34+
data.add(new UserTestData(u, cmdm));
35+
}
36+
boolean success = ThreadManager.runTasks(3, (Object o) -> {
37+
long slp = Math.round(Math.random() * 100);
38+
try{ Thread.sleep(slp); } catch (Exception e) {}
39+
UserTestData utd = (UserTestData) o;
40+
map.put(utd.name, utd.map);
41+
System.out.println(utd.name + " - " + slp); //DEBUG
42+
}, data, 5000l);
43+
44+
System.out.println("Success? " + success);
45+
System.out.println(map.size());
46+
System.out.println(map.keySet());
47+
48+
map.put(data.get(0).name, data.get(0).map);
49+
map.put(data.get(1).name, data.get(1).map);
50+
System.out.println(map);
51+
}
52+
53+
}

0 commit comments

Comments
 (0)