1818 * @version 1.5.2
1919 */
2020public abstract class GraphScript <C extends ClientContext > extends PollingScript <C > {
21- private final Deque <AtomicInteger > i ;
22-
23- /**
24- * The root chain where the node cursor will start.
25- */
26- protected final AtomicReference <Action <C >> current = new AtomicReference <Action <C >>();
27- protected final NavigableSet <Action <C >> chain ;
28-
29- /**
30- * Creates a {@link GraphScript}. The root {@link #chain} should be populated here.
31- */
32- public GraphScript () {
33- i = new LinkedList <AtomicInteger >();
34- chain = new ConcurrentSkipListSet <Action <C >>();
35- }
36-
37- /**
38- * {@inheritDoc}
39- */
40- @ Override
41- public final void poll () {
42- propagate (chain );
43- }
44-
45- private void propagate (final Iterable <Action <C >> chain ) {
46- final AtomicInteger c = new AtomicInteger (0 );
47- i .push (c );
48- boolean anyEnabled = false ;
49- for ( final Action < C > a : chain ) {
50- if ( a . enabled ()) {
51- anyEnabled = true ;
52- current . set ( a );
53- a . run ();
54- propagate ( a . chain );
55- }
56- c . incrementAndGet ();
57- }
58- i . pop ();
59- if (! anyEnabled ) {
60- current .set (null );
61- }
62- }
63-
64- /**
65- * A node for {@link GraphScript}. In practical terms this is an atomic (independent) module which holds a
66- * small task and/or condition.
67- */
68- public static abstract class Action <T extends ClientContext > extends ClientAccessor <T > implements Runnable , Comparable <Action <T >>, Validatable {
69- private static final AtomicInteger s = new AtomicInteger (0 );
70- private final int q ;
71- private final Queue <Validator > validators ;
72-
73- /**
74- * The chain of this node.
75- */
76- protected final Queue <Action <T >> chain ;
77- /**
78- * The priority value, which is relative to other nodes in the same leaf. By default the value is 0.
79- */
80- protected final AtomicInteger priority ;
81-
82- /**
83- * Creates a new {@link Action} (a node).
84- *
85- * @param script the container script
86- */
87- public Action (final GraphScript <T > script ) {
88- this (script .ctx );
89- }
90-
91- /**
92- * Creates a new {@link Action} (a node).
93- *
94- * @param ctx the client context
95- */
96- public Action (final T ctx ) {
97- super (ctx );
98- chain = new PriorityBlockingQueue <Action <T >>();
99- priority = new AtomicInteger (0 );
100- q = s .getAndIncrement ();
101- validators = new ConcurrentLinkedQueue <Validator >();
102-
103- push (new Validator () {
104- @ Override
105- public boolean valid () {
106- return Action .this .valid ();
107- }
108- });
109- }
110-
111- /**
112- * {@inheritDoc}
113- */
114- @ Override
115- public boolean valid () {
116- return true ;
117- }
118-
119- /**
120- * Pushes a new {@link GraphScript.Action.Validator} to the checking queue.
121- *
122- * @param v a new {@link GraphScript.Action.Validator}
123- * @return {@code true} if the {@link GraphScript.Action.Validator} was added, otherwise {@code false}
124- */
125- public final boolean push (final Validator v ) {
126- return !validators .contains (v ) && validators .offer (v );
127- }
128-
129- private boolean enabled () {
130- boolean blocked = false ;
131-
132- final Iterator <Validator > i = validators .iterator ();
133- while (i .hasNext ()) {
134- final Validator c = i .next ();
135- if (!c .enabled .get ()) {
136- c .pop ();
137- i .remove ();
138- } else if (!blocked && !c .valid ()) {
139- blocked = true ;
140- }
141- }
142-
143- return !blocked ;
144- }
145-
146- /**
147- * Returns the index of the cursor on the graph which takes the form {@code [X]n, n>1}. This value represents
148- * the path of the branch at which the node was accessed.
149- *
150- * @return the index of the cursor on the graph
151- */
152- protected final String getCursorIndex () {
153- final AbstractScript c = ctx .controller .script ();
154- if (!(c instanceof GraphScript )) {
155- return "" ;
156- }
157- @ SuppressWarnings ("unchecked" )
158- final GraphScript <T > parent = (GraphScript <T >) c ;
159- int i = parent .i .size ();
160- final char [] s = new char [i ];
161-
162- for (final AtomicInteger n : parent .i ) {
163- s [--i ] = (char ) ((n .get () % 26 ) + 'A' );
164- }
165-
166- return new String (s );
167- }
168-
169- /**
170- * {@inheritDoc}
171- */
172- @ Override
173- public final int compareTo (final Action <T > o ) {
174- final int r = o .priority .get () - priority .get ();
175- return r == 0 ? q - o .q : r ;
176- }
177-
178- /**
179- * A class indicating a validation state, which can be disabled externally.
180- */
181- protected static abstract class Validator implements Validatable {
182- private final AtomicBoolean enabled = new AtomicBoolean (true );
183-
184- /**
185- * Removes this {@link GraphScript.Action.Validator} from the checking queue.
186- */
187- public final void pop () {
188- enabled .set (false );
189- }
190- }
191- }
21+ private final Deque <AtomicInteger > i ;
22+
23+ /**
24+ * The root chain where the node cursor will start.
25+ */
26+ protected final AtomicReference <Action <C >> current = new AtomicReference <Action <C >>();
27+ protected final NavigableSet <Action <C >> chain ;
28+
29+ /**
30+ * Creates a {@link GraphScript}. The root {@link #chain} should be populated here.
31+ */
32+ public GraphScript () {
33+ i = new LinkedList <AtomicInteger >();
34+ chain = new ConcurrentSkipListSet <Action <C >>();
35+ }
36+
37+ /**
38+ * {@inheritDoc}
39+ */
40+ @ Override
41+ public final void poll () {
42+ propagate (chain );
43+ }
44+
45+ private void propagate (final Iterable <Action <C >> chain ) {
46+ final AtomicInteger c = new AtomicInteger (0 );
47+ i .push (c );
48+ for ( final Action < C > a : chain ) {
49+ if ( a . enabled () ) {
50+ current . set ( a );
51+ a . run () ;
52+ propagate ( a . chain );
53+ }
54+ c . incrementAndGet ( );
55+ }
56+ i . pop ();
57+
58+ final Action < C > action = current . get ();
59+ if ( action != null && ! action . valid () ) {
60+ current .set (null );
61+ }
62+ }
63+
64+ /**
65+ * A node for {@link GraphScript}. In practical terms this is an atomic (independent) module which holds a
66+ * small task and/or condition.
67+ */
68+ public static abstract class Action <T extends ClientContext > extends ClientAccessor <T > implements Runnable , Comparable <Action <T >>, Validatable {
69+ private static final AtomicInteger s = new AtomicInteger (0 );
70+ private final int q ;
71+ private final Queue <Validator > validators ;
72+
73+ /**
74+ * The chain of this node.
75+ */
76+ protected final Queue <Action <T >> chain ;
77+ /**
78+ * The priority value, which is relative to other nodes in the same leaf. By default the value is 0.
79+ */
80+ protected final AtomicInteger priority ;
81+
82+ /**
83+ * Creates a new {@link Action} (a node).
84+ *
85+ * @param script the container script
86+ */
87+ public Action (final GraphScript <T > script ) {
88+ this (script .ctx );
89+ }
90+
91+ /**
92+ * Creates a new {@link Action} (a node).
93+ *
94+ * @param ctx the client context
95+ */
96+ public Action (final T ctx ) {
97+ super (ctx );
98+ chain = new PriorityBlockingQueue <Action <T >>();
99+ priority = new AtomicInteger (0 );
100+ q = s .getAndIncrement ();
101+ validators = new ConcurrentLinkedQueue <Validator >();
102+
103+ push (new Validator () {
104+ @ Override
105+ public boolean valid () {
106+ return Action .this .valid ();
107+ }
108+ });
109+ }
110+
111+ /**
112+ * {@inheritDoc}
113+ */
114+ @ Override
115+ public boolean valid () {
116+ return true ;
117+ }
118+
119+ /**
120+ * Pushes a new {@link GraphScript.Action.Validator} to the checking queue.
121+ *
122+ * @param v a new {@link GraphScript.Action.Validator}
123+ * @return {@code true} if the {@link GraphScript.Action.Validator} was added, otherwise {@code false}
124+ */
125+ public final boolean push (final Validator v ) {
126+ return !validators .contains (v ) && validators .offer (v );
127+ }
128+
129+ private boolean enabled () {
130+ boolean blocked = false ;
131+
132+ final Iterator <Validator > i = validators .iterator ();
133+ while (i .hasNext ()) {
134+ final Validator c = i .next ();
135+ if (!c .enabled .get ()) {
136+ c .pop ();
137+ i .remove ();
138+ } else if (!blocked && !c .valid ()) {
139+ blocked = true ;
140+ }
141+ }
142+
143+ return !blocked ;
144+ }
145+
146+ /**
147+ * Returns the index of the cursor on the graph which takes the form {@code [X]n, n>1}. This value represents
148+ * the path of the branch at which the node was accessed.
149+ *
150+ * @return the index of the cursor on the graph
151+ */
152+ protected final String getCursorIndex () {
153+ final AbstractScript c = ctx .controller .script ();
154+ if (!(c instanceof GraphScript )) {
155+ return "" ;
156+ }
157+ @ SuppressWarnings ("unchecked" )
158+ final GraphScript <T > parent = (GraphScript <T >) c ;
159+ int i = parent .i .size ();
160+ final char [] s = new char [i ];
161+
162+ for (final AtomicInteger n : parent .i ) {
163+ s [--i ] = (char ) ((n .get () % 26 ) + 'A' );
164+ }
165+
166+ return new String (s );
167+ }
168+
169+ /**
170+ * {@inheritDoc}
171+ */
172+ @ Override
173+ public final int compareTo (final Action <T > o ) {
174+ final int r = o .priority .get () - priority .get ();
175+ return r == 0 ? q - o .q : r ;
176+ }
177+
178+ /**
179+ * A class indicating a validation state, which can be disabled externally.
180+ */
181+ protected static abstract class Validator implements Validatable {
182+ private final AtomicBoolean enabled = new AtomicBoolean (true );
183+
184+ /**
185+ * Removes this {@link GraphScript.Action.Validator} from the checking queue.
186+ */
187+ public final void pop () {
188+ enabled .set (false );
189+ }
190+ }
191+ }
192192}
0 commit comments