View Javadoc

1   /*
2    *
3    *   Copyright 2005 The Apache Software Foundation.
4    *
5    *  Licensed under the Apache License, Version 2.0 (the "License");
6    *  you may not use this file except in compliance with the License.
7    *  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   *  Unless required by applicable law or agreed to in writing, software
12   *  distributed under the License is distributed on an "AS IS" BASIS,
13   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   *  See the License for the specific language governing permissions and
15   *  limitations under the License.
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              //a local "stay" transition
69              scope = (State) source;
70              //all segments remain empty
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