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 &quot;up segment&quot; that traces up to
    33   * the least common ancestor and a &quot;down segment&quot; 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 &quot;up segment&quot;.
    46       */
    47      private List upSeg = new ArrayList();
    48
    49      /***
    50       * The list of TransitionTargets in the &quot;down segment&quot;.
    51       */
    52      private List downSeg = new ArrayList();
    53
    54      /***
    55       * &quot;Lowest&quot; 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 &quot;path&quot; 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         List 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         List 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