01: /*
02: * Created on 05-Jan-2006
03: */
04: package uk.org.ponder.rsf.flow.support;
05:
06: import java.util.Collections;
07:
08: import uk.org.ponder.rsf.flow.FlowIDHolder;
09: import uk.org.ponder.rsf.state.LockGetter;
10: import uk.org.ponder.stringutil.StringList;
11: import uk.org.ponder.util.Logger;
12: import uk.org.ponder.util.RunnableInvoker;
13:
14: /**
15: * An alteration wrapper designed to prevent simultaneous access to flow or
16: * scoped data. Only incurs a synchronized overhead if there is actually an
17: * active flow or scope for the current request, i.e. in the case of a scope, it
18: * successfully restored a bean from the scope. If another request in in the
19: * flow, this wrapper will simply block - in practice this is no real burden
20: * since this condition could only be triggered by multiple simultaneous
21: * requests from the same user/browser. Could be a liability however if under
22: * some (possibly failure) condition, normal request handling might take an
23: * unbounded time - in this case you may want to replace this wrapper with an
24: * implementation performing wait/notify with a timeout.
25: * <p>
26: * If operating in a clustered environment where handling of different requests
27: * belonging to the same flow cannot be guaranteed to be passed to the same JVM,
28: * you will certainly require to replace this implementation.
29: *
30: * @author Antranig Basman (amb26@ponder.org.uk)
31: *
32: */
33:
34: public class BasicScopedAlterationWrapper implements RunnableInvoker {
35: private LockGetter lockgetter;
36: private FlowIDHolder flowidholder;
37: private StringList scopelocks;
38:
39: public void setLockGetter(LockGetter flowlockgetter) {
40: this .lockgetter = flowlockgetter;
41: }
42:
43: public void setFlowIDHolder(FlowIDHolder flowidholder) {
44: this .flowidholder = flowidholder;
45: }
46:
47: public void setScopeLocks(StringList scopelocks) {
48: this .scopelocks = scopelocks;
49: }
50:
51: public void invokeRunnable(Runnable towrap) {
52: String flowtoken = flowidholder.getFlowToken();
53: final StringList completelocks = new StringList();
54: if (flowtoken != null) {
55: completelocks.add(flowtoken);
56: }
57: completelocks.addAll(scopelocks);
58: if (completelocks.size() == 0) {
59: towrap.run();
60: return;
61: }
62: Collections.sort(completelocks); // Avoid potential Dedlocks!
63: try {
64: lockUUPP(completelocks, towrap, 0);
65: } finally {
66: lockgetter.returnLock(flowtoken);
67: }
68: }
69:
70: private void lockUUPP(StringList completelocks, Runnable towrap,
71: int i) {
72: if (i >= completelocks.size()) {
73: towrap.run();
74: } else {
75: String lockname = completelocks.stringAt(i);
76: Object lock = lockgetter.getLock(lockname);
77: Logger.log.info("Acquiring lock " + lock
78: + " for scope name " + lockname);
79: synchronized (lock) {
80: lockUUPP(completelocks, towrap, i + 1);
81: }
82: }
83: }
84:
85: }
|