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