1 package com.bonevich.util.dependency;
2
3 import java.util.*;
4
5 /***
6 * Provides automatic tracking of dependencies on dynamic and other
7 * dependent attributes in and outside an information model.
8 */
9 public class Dependent extends Sentry
10 {
11 private static class Status { }
12 private static final Status INVALID = new Status();
13 private static final Status VALID = new Status();
14 private static final Status VALIDATING = new Status();
15
16 private UpdateAction _update;
17 private Status _status = INVALID;
18 private List _sentries = new LinkedList();
19 private DependentProxy _this = new DependentProxy()
20 {
21 public void invalidate()
22 {
23 Dependent.this.invalidate();
24 }
25 public void addSentry(SentryProxy sentry)
26 {
27 Dependent.this.addSentry(sentry);
28 }
29 };
30
31 public Dependent(UpdateAction update)
32 {
33 _update = update;
34 }
35
36 public boolean isValid() { return _status == VALID; }
37 public boolean isInvalid() { return _status == INVALID; }
38 public boolean isValidating() { return _status == VALIDATING; }
39
40 public void cleanup()
41 {
42 if ( isValid() )
43 {
44 // This will make all sentries forget about me
45 invalidate();
46 }
47
48 assertStatus(INVALID);
49 super.cleanup();
50 }
51
52 /***
53 * Check the current status and, if invalid, call onUpdate. If the
54 * current status is validating, throws an <code>IllegalStateException</code>
55 * as this indicates the presence of a cycle in the update process.
56 * NOTE: in order for a Dependent to automatically detect that the
57 * underlying information model has changed, it must use the model
58 * class instances on which it depends inside the <code>UpdateAction.onUpdate()</code>
59 * implementation.
60 */
61 public final void onGet()
62 {
63 // Bring this attribute up to date whenever it is referenced
64 if ( isValidating() )
65 {
66 throw new IllegalStateException("Cycle discovered during update");
67 }
68 else if ( isInvalid() )
69 {
70 // Push myself to the active dependent stack
71 DependentProxy stack = _activeDependent;
72 _activeDependent = _this;
73
74 // Update the attribute
75 _status = VALIDATING;
76 try
77 {
78 _update.onUpdate();
79 }
80 finally
81 {
82 _status = VALID;
83
84 // Pop myself off the active dependent stack
85 // FIXME: is this really thread safe??
86 _activeDependent = stack;
87 }
88 }
89 // else VALID: No action required
90 assertStatus(VALID);
91
92 // Establish dependency between the current update
93 // and this attribute
94 recordDependent();
95 }
96
97 protected void invalidate()
98 {
99 assertStatus(VALID);
100
101 // Tell all sentries to forget about me
102 Iterator itr = _sentries.iterator();
103 while (itr.hasNext())
104 {
105 SentryProxy sentry = (SentryProxy)itr.next();
106 sentry.removeDependent(_this);
107 }
108 _sentries.clear();
109
110 // Make all indirect dependents out-of-date, too
111 invalidateDependents();
112 _status = INVALID;
113 }
114
115 private void addSentry(SentryProxy sentry)
116 {
117 _sentries.add(sentry);
118 }
119
120 private void assertStatus(Status s)
121 {
122 if (_status != s)
123 {
124 throw new IllegalStateException("Improper usage of dependency sentries");
125 }
126 }
127 } /*** end class Dependent */
This page was automatically generated by Maven