rlm@10
|
1 /**
|
rlm@10
|
2 * Copyright (c) Rich Hickey. All rights reserved.
|
rlm@10
|
3 * The use and distribution terms for this software are covered by the
|
rlm@10
|
4 * Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
|
rlm@10
|
5 * which can be found in the file epl-v10.html at the root of this distribution.
|
rlm@10
|
6 * By using this software in any fashion, you are agreeing to be bound by
|
rlm@10
|
7 * the terms of this license.
|
rlm@10
|
8 * You must not remove this notice, or any other, from this software.
|
rlm@10
|
9 **/
|
rlm@10
|
10
|
rlm@10
|
11 /* rich Jan 1, 2009 */
|
rlm@10
|
12
|
rlm@10
|
13 package clojure.lang;
|
rlm@10
|
14
|
rlm@10
|
15 import java.util.Map;
|
rlm@10
|
16
|
rlm@10
|
17 public abstract class ARef extends AReference implements IRef{
|
rlm@10
|
18 protected volatile IFn validator = null;
|
rlm@10
|
19 private volatile IPersistentMap watches = PersistentHashMap.EMPTY;
|
rlm@10
|
20
|
rlm@10
|
21 public ARef(){
|
rlm@10
|
22 super();
|
rlm@10
|
23 }
|
rlm@10
|
24
|
rlm@10
|
25 public ARef(IPersistentMap meta){
|
rlm@10
|
26 super(meta);
|
rlm@10
|
27 }
|
rlm@10
|
28
|
rlm@10
|
29 void validate(IFn vf, Object val){
|
rlm@10
|
30 try
|
rlm@10
|
31 {
|
rlm@10
|
32 if(vf != null && !RT.booleanCast(vf.invoke(val)))
|
rlm@10
|
33 throw new IllegalStateException("Invalid reference state");
|
rlm@10
|
34 }
|
rlm@10
|
35 catch(RuntimeException re)
|
rlm@10
|
36 {
|
rlm@10
|
37 throw re;
|
rlm@10
|
38 }
|
rlm@10
|
39 catch(Exception e)
|
rlm@10
|
40 {
|
rlm@10
|
41 throw new IllegalStateException("Invalid reference state", e);
|
rlm@10
|
42 }
|
rlm@10
|
43 }
|
rlm@10
|
44
|
rlm@10
|
45 void validate(Object val){
|
rlm@10
|
46 validate(validator, val);
|
rlm@10
|
47 }
|
rlm@10
|
48
|
rlm@10
|
49 public void setValidator(IFn vf){
|
rlm@10
|
50 try
|
rlm@10
|
51 {
|
rlm@10
|
52 validate(vf, deref());
|
rlm@10
|
53 }
|
rlm@10
|
54 catch(Exception e)
|
rlm@10
|
55 {
|
rlm@10
|
56 throw new RuntimeException(e);
|
rlm@10
|
57 }
|
rlm@10
|
58 validator = vf;
|
rlm@10
|
59 }
|
rlm@10
|
60
|
rlm@10
|
61 public IFn getValidator(){
|
rlm@10
|
62 return validator;
|
rlm@10
|
63 }
|
rlm@10
|
64
|
rlm@10
|
65 public IPersistentMap getWatches(){
|
rlm@10
|
66 return watches;
|
rlm@10
|
67 }
|
rlm@10
|
68
|
rlm@10
|
69 synchronized public IRef addWatch(Object key, IFn callback){
|
rlm@10
|
70 watches = watches.assoc(key, callback);
|
rlm@10
|
71 return this;
|
rlm@10
|
72 }
|
rlm@10
|
73
|
rlm@10
|
74 synchronized public IRef removeWatch(Object key){
|
rlm@10
|
75 try
|
rlm@10
|
76 {
|
rlm@10
|
77 watches = watches.without(key);
|
rlm@10
|
78 }
|
rlm@10
|
79 catch(Exception e)
|
rlm@10
|
80 {
|
rlm@10
|
81 throw new RuntimeException(e);
|
rlm@10
|
82 }
|
rlm@10
|
83
|
rlm@10
|
84 return this;
|
rlm@10
|
85 }
|
rlm@10
|
86
|
rlm@10
|
87 public void notifyWatches(Object oldval, Object newval){
|
rlm@10
|
88 IPersistentMap ws = watches;
|
rlm@10
|
89 if(ws.count() > 0)
|
rlm@10
|
90 {
|
rlm@10
|
91 for(ISeq s = ws.seq(); s != null; s = s.next())
|
rlm@10
|
92 {
|
rlm@10
|
93 Map.Entry e = (Map.Entry) s.first();
|
rlm@10
|
94 IFn fn = (IFn) e.getValue();
|
rlm@10
|
95 try
|
rlm@10
|
96 {
|
rlm@10
|
97 if(fn != null)
|
rlm@10
|
98 fn.invoke(e.getKey(), this, oldval, newval);
|
rlm@10
|
99 }
|
rlm@10
|
100 catch(Exception e1)
|
rlm@10
|
101 {
|
rlm@10
|
102 throw new RuntimeException(e1);
|
rlm@10
|
103 }
|
rlm@10
|
104 }
|
rlm@10
|
105 }
|
rlm@10
|
106 }
|
rlm@10
|
107 }
|