Improved on the SvcConfig and renamed it.
[jsvc.git] / src / dolda / jsvc / ContextParam.java
CommitLineData
b5f27035
FT
1package dolda.jsvc;
2
3import java.util.*;
4
5public class ContextParam<T> {
6 private boolean bound;
7 private T value;
8 private final Object id = new Object();
9 private Map<ThreadContext, T> perctx = new WeakHashMap<ThreadContext, T>();
10 private Map<Thread, T> perthr = new WeakHashMap<Thread, T>();
11
12 public ContextParam(T def) {
13 this.value = def;
14 this.bound = true;
15 }
16
17 public ContextParam() {
18 this.bound = false;
19 }
20
21 public synchronized T get() {
22 Thread th = Thread.currentThread();
23 if(perthr.containsKey(th))
24 return(perthr.get(th));
25 ThreadContext ctx = getctx();
26 if(perctx.containsKey(ctx))
27 return(perctx.get(ctx));
28 if(!bound)
29 throw(new IllegalStateException("No value is bound to this parameter."));
30 return(value);
31 }
32
33 public synchronized T ctxset(T val) {
34 ThreadContext ctx = getctx();
35 return(perctx.put(ctx, val));
36 }
37
38 private static ThreadContext getctx() {
39 for(ThreadGroup tg = Thread.currentThread().getThreadGroup(); tg != null; tg = tg.getParent()) {
40 if(tg instanceof ThreadContext)
41 return((ThreadContext)tg);
42 }
43 return(null);
44 }
45
46 public static Responder let(final Responder next, Object... params) {
47 final Map<ContextParam, Object> values = new HashMap<ContextParam, Object>();
48 if((params.length % 2) != 0)
49 throw(new IllegalArgumentException("SvcConfig.let takes only an even number of parameters"));
50 for(int i = 0; i < params.length; i += 2)
51 values.put((ContextParam)params[i], params[i + 1]);
52
53 return(new Responder() {
54 /* This can very well actually be set to something
55 * of the wrong type, but since the result would,
56 * obviously, be a ClassCastException either way,
57 * this way is at least the more convenient. */
58 @SuppressWarnings("unchecked")
59 public void respond(Request req) {
60 final Map<ContextParam, Object> old = new HashMap<ContextParam, Object>();
61 Thread th = Thread.currentThread();
62 for(Map.Entry<ContextParam, Object> val : values.entrySet()) {
63 ContextParam p = val.getKey();
64 synchronized(p) {
65 if(p.perthr.containsKey(th))
66 old.put(p, p.perthr.get(th));
67 p.perthr.put(th, val.getValue());
68 }
69 }
70 try {
71 next.respond(req);
72 } finally {
73 for(Map.Entry<ContextParam, Object> val : values.entrySet()) {
74 ContextParam p = val.getKey();
75 synchronized(p) {
76 if(old.containsKey(p)) {
77 p.perthr.put(th, old.get(p));
78 } else {
79 p.perthr.remove(th);
80 }
81 }
82 }
83 }
84 }
85 });
86 }
87}