X-Git-Url: http://git.dolda2000.com/gitweb/?a=blobdiff_plain;f=src%2Fdolda%2Fjsvc%2FContextParam.java;fp=src%2Fdolda%2Fjsvc%2FContextParam.java;h=f146dc385a80f83ae34d60cead99c35ad2c77dcd;hb=b5f270350bfadea58c6b14516422df00202e9d46;hp=0000000000000000000000000000000000000000;hpb=a0b186f8f8342791c1d65ca8f04118b0d73d5bb8;p=jsvc.git diff --git a/src/dolda/jsvc/ContextParam.java b/src/dolda/jsvc/ContextParam.java new file mode 100644 index 0000000..f146dc3 --- /dev/null +++ b/src/dolda/jsvc/ContextParam.java @@ -0,0 +1,87 @@ +package dolda.jsvc; + +import java.util.*; + +public class ContextParam { + private boolean bound; + private T value; + private final Object id = new Object(); + private Map perctx = new WeakHashMap(); + private Map perthr = new WeakHashMap(); + + public ContextParam(T def) { + this.value = def; + this.bound = true; + } + + public ContextParam() { + this.bound = false; + } + + public synchronized T get() { + Thread th = Thread.currentThread(); + if(perthr.containsKey(th)) + return(perthr.get(th)); + ThreadContext ctx = getctx(); + if(perctx.containsKey(ctx)) + return(perctx.get(ctx)); + if(!bound) + throw(new IllegalStateException("No value is bound to this parameter.")); + return(value); + } + + public synchronized T ctxset(T val) { + ThreadContext ctx = getctx(); + return(perctx.put(ctx, val)); + } + + private static ThreadContext getctx() { + for(ThreadGroup tg = Thread.currentThread().getThreadGroup(); tg != null; tg = tg.getParent()) { + if(tg instanceof ThreadContext) + return((ThreadContext)tg); + } + return(null); + } + + public static Responder let(final Responder next, Object... params) { + final Map values = new HashMap(); + if((params.length % 2) != 0) + throw(new IllegalArgumentException("SvcConfig.let takes only an even number of parameters")); + for(int i = 0; i < params.length; i += 2) + values.put((ContextParam)params[i], params[i + 1]); + + return(new Responder() { + /* This can very well actually be set to something + * of the wrong type, but since the result would, + * obviously, be a ClassCastException either way, + * this way is at least the more convenient. */ + @SuppressWarnings("unchecked") + public void respond(Request req) { + final Map old = new HashMap(); + Thread th = Thread.currentThread(); + for(Map.Entry val : values.entrySet()) { + ContextParam p = val.getKey(); + synchronized(p) { + if(p.perthr.containsKey(th)) + old.put(p, p.perthr.get(th)); + p.perthr.put(th, val.getValue()); + } + } + try { + next.respond(req); + } finally { + for(Map.Entry val : values.entrySet()) { + ContextParam p = val.getKey(); + synchronized(p) { + if(old.containsKey(p)) { + p.perthr.put(th, old.get(p)); + } else { + p.perthr.remove(th); + } + } + } + } + } + }); + } +}