1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.scxml.model;
19
20 import java.util.ArrayList;
21 import java.util.Iterator;
22 import java.util.LinkedList;
23 import java.util.List;
24
25 import org.apache.commons.scxml.SCXMLHelper;
26
27 /***
28 * A helper class for this SCXML implementation that represents the
29 * path taken to transition from one TransitionTarget to another in
30 * the SCXML document.
31 *
32 * The Path consists of the "up segment" that traces up to
33 * the least common ancestor and a "down segment" that traces
34 * down to the target of the Transition.
35 *
36 */
37 public class Path {
38
39 /***
40 * The list of TransitionTargets in the "up segment".
41 */
42 private List upSeg = new ArrayList();
43
44 /***
45 * The list of TransitionTargets in the "down segment".
46 */
47 private List downSeg = new ArrayList();
48
49 /***
50 * "Lowest" state which is not being exited nor entered by
51 * the transition.
52 */
53 private State scope = null;
54
55 /***
56 * Whether the path crosses region border(s).
57 */
58 private boolean crossRegion = false;
59
60 /***
61 * Constructor.
62 *
63 * @param source The source TransitionTarget
64 * @param target The target TransitionTarget
65 */
66 Path(final TransitionTarget source, final TransitionTarget target) {
67 if (target == null) {
68
69 scope = (State) source;
70
71 } else {
72 TransitionTarget tt = SCXMLHelper.getLCA(source, target);
73 if (tt != null) {
74 if (tt instanceof State) {
75 scope = (State) tt;
76 } else {
77 scope = tt.getParentState();
78 }
79 if (scope == source || scope == target) {
80 scope = scope.getParentState();
81 }
82 }
83 tt = source;
84 while (tt != scope) {
85 upSeg.add(tt);
86 if (tt instanceof State) {
87 State st = (State) tt;
88 if (st.isRegion()) {
89 crossRegion = true;
90 }
91 }
92 tt = tt.getParent();
93 }
94 tt = target;
95 while (tt != scope) {
96 downSeg.add(0, tt);
97 if (tt instanceof State) {
98 State st = (State) tt;
99 if (st.isRegion()) {
100 crossRegion = true;
101 }
102 }
103 tt = tt.getParent();
104 }
105 }
106 }
107
108 /***
109 * Does this "path" cross regions.
110 *
111 * @return true when the path crosses a region border(s)
112 * @see State#isRegion()
113 */
114 public final boolean isCrossRegion() {
115 return crossRegion;
116 }
117
118 /***
119 * Get the list of regions exited.
120 *
121 * @return List a list of exited regions sorted bottom-up;
122 * no order defined for siblings
123 * @see State#isRegion()
124 */
125 public final List getRegionsExited() {
126 LinkedList ll = new LinkedList();
127 for (Iterator i = upSeg.iterator(); i.hasNext();) {
128 Object o = i.next();
129 if (o instanceof State) {
130 State st = (State) o;
131 if (st.isRegion()) {
132 ll.add(st);
133 }
134 }
135 }
136 return ll;
137 }
138
139 /***
140 * Get the list of regions entered.
141 *
142 * @return List a list of entered regions sorted top-down; no order
143 * defined for siblings
144 * @see State#isRegion()
145 */
146 public final List getRegionsEntered() {
147 LinkedList ll = new LinkedList();
148 for (Iterator i = downSeg.iterator(); i.hasNext();) {
149 Object o = i.next();
150 if (o instanceof State) {
151 State st = (State) o;
152 if (st.isRegion()) {
153 ll.add(st);
154 }
155 }
156 }
157 return ll;
158 }
159
160 /***
161 * Get the farthest state from root which is not being exited
162 * nor entered by the transition (null if scope is document root).
163 *
164 * @return State scope of the transition path, null means global transition
165 * (SCXML document level) Scope is the least state which is not
166 * being exited nor entered by the transition.
167 */
168 public final State getScope() {
169 return scope;
170 }
171
172 /***
173 * Get the upward segment.
174 *
175 * @return List upward segment of the path up to the scope
176 */
177 public final List getUpwardSegment() {
178 return upSeg;
179 }
180
181 /***
182 * Get the downward segment.
183 *
184 * @return List downward segment from the scope to the target
185 */
186 public final List getDownwardSegment() {
187 return downSeg;
188 }
189 }
190