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" transition target which is not being exited nor
56       * entered by the transition.
57       */
58      private TransitionTarget 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 = source;
75              //all segments remain empty
76          } else {
77              TransitionTarget tt = SCXMLHelper.getLCA(source, target);
78              if (tt != null) {
79                  scope = tt;
80                  if (scope == source || scope == target) {
81                      scope = scope.getParent();
82                  }
83              }
84              tt = source;
85              while (tt != scope) {
86                  upSeg.add(tt);
87                  if (tt instanceof State) {
88                      State st = (State) tt;
89                      if (st.isRegion()) {
90                          crossRegion = true;
91                      }
92                  }
93                  tt = tt.getParent();
94              }
95              tt = target;
96              while (tt != scope) {
97                  downSeg.add(0, tt);
98                  if (tt instanceof State) {
99                      State st = (State) tt;
100                     if (st.isRegion()) {
101                         crossRegion = true;
102                     }
103                 }
104                 tt = tt.getParent();
105             }
106         }
107     }
108 
109     /**
110      * Does this "path" cross regions.
111      *
112      * @return true when the path crosses a region border(s)
113      * @see State#isRegion()
114      */
115     public final boolean isCrossRegion() {
116         return crossRegion;
117     }
118 
119     /**
120      * Get the list of regions exited.
121      *
122      * @return List a list of exited regions sorted bottom-up;
123      *         no order defined for siblings
124      * @see State#isRegion()
125      */
126     public final List getRegionsExited() {
127         List ll = new LinkedList();
128         for (Iterator i = upSeg.iterator(); i.hasNext();) {
129             Object o = i.next();
130             if (o instanceof State) {
131                 State st = (State) o;
132                 if (st.isRegion()) {
133                     ll.add(st);
134                 }
135             }
136         }
137         return ll;
138     }
139 
140     /**
141      * Get the list of regions entered.
142      *
143      * @return List a list of entered regions sorted top-down; no order
144      *         defined for siblings
145      * @see State#isRegion()
146      */
147     public final List getRegionsEntered() {
148         List ll = new LinkedList();
149         for (Iterator i = downSeg.iterator(); i.hasNext();) {
150             Object o = i.next();
151             if (o instanceof State) {
152                 State st = (State) o;
153                 if (st.isRegion()) {
154                     ll.add(st);
155                 }
156             }
157         }
158         return ll;
159     }
160 
161     /**
162      * Get the farthest state from root which is not being exited
163      * nor entered by the transition (null if scope is document root).
164      *
165      * @return State scope of the transition path, null means global transition
166      *         (SCXML document level) or parent parallel. Scope is the least
167      *         state which is not being exited nor entered by the transition.
168      *
169      * @deprecated Use {@link #getPathScope()} instead.
170      */
171     public final State getScope() {
172         if (scope instanceof State) {
173             return (State) scope;
174         }
175         return null;
176     }
177 
178     /**
179      * Get the farthest transition target from root which is not being exited
180      * nor entered by the transition (null if scope is document root).
181      *
182      * @return Scope of the transition path, null means global transition
183      *         (SCXML document level). Scope is the least transition target
184      *         which is not being exited nor entered by the transition.
185      *
186      * @since 0.9
187      */
188     public final TransitionTarget getPathScope() {
189         return scope;
190     }
191 
192     /**
193      * Get the upward segment.
194      *
195      * @return List upward segment of the path up to the scope
196      */
197     public final List getUpwardSegment() {
198         return upSeg;
199     }
200 
201     /**
202      * Get the downward segment.
203      *
204      * @return List downward segment from the scope to the target
205      */
206     public final List getDownwardSegment() {
207         return downSeg;
208     }
209 }
210