View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  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  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              //a local "stay" transition
74              scope = (State) source;
75              //all segments remain empty
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