001: /*
002: * @(#)TransitionImpl.java
003: *
004: * Copyright (C) 2002-2003 Matt Albrecht
005: * groboclown@users.sourceforge.net
006: * http://groboutils.sourceforge.net
007: *
008: * Part of the GroboUtils package at:
009: * http://groboutils.sourceforge.net
010: *
011: * Permission is hereby granted, free of charge, to any person obtaining a
012: * copy of this software and associated documentation files (the "Software"),
013: * to deal in the Software without restriction, including without limitation
014: * the rights to use, copy, modify, merge, publish, distribute, sublicense,
015: * and/or sell copies of the Software, and to permit persons to whom the
016: * Software is furnished to do so, subject to the following conditions:
017: *
018: * The above copyright notice and this permission notice shall be included in
019: * all copies or substantial portions of the Software.
020: *
021: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
022: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
023: * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
024: * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
025: * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
026: * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
027: * DEALINGS IN THE SOFTWARE.
028: */
029: package net.sourceforge.groboutils.mbtf.v1.engine;
030:
031: import net.sourceforge.groboutils.mbtf.v1.IState;
032: import net.sourceforge.groboutils.mbtf.v1.IAction;
033: import net.sourceforge.groboutils.mbtf.v1.IValidate;
034: import net.sourceforge.groboutils.mbtf.v1.ITransition;
035:
036: /**
037: * Nearly-Immutable implementation of ITransition. As an immutable, transitions
038: * cannot be created if there are cycles in the state machine. Therefore,
039: * there needs to be a way to post-creation correctly populate the Transition's
040: * destination state. Thus, the destination state may be set once.
041: *
042: * @author Matt Albrecht <a href="mailto:groboclown@users.sourceforge.net">groboclown@users.sourceforge.net</a>
043: * @version $Date: 2003/02/10 22:52:26 $
044: * @since June 12, 2002
045: */
046: public class TransitionImpl implements ITransition {
047: private String name;
048: private IState destination;
049: private IAction action;
050: private IValidate[] validate;
051:
052: public TransitionImpl(String name, IState dest, IAction a,
053: IValidate[] v) {
054: // allow destination to be null
055:
056: if (name == null || a == null) {
057: throw new IllegalArgumentException("no null args");
058: }
059:
060: if (v == null) {
061: v = new IValidate[0];
062: } else {
063: int len = v.length;
064: IValidate[] vv = new IValidate[len];
065: for (int i = len; --i >= 0;) {
066: if (v[i] == null) {
067: throw new IllegalArgumentException(
068: "no nulls allowed in IValidate array");
069: }
070: // else
071: vv[i] = v[i];
072: }
073: v = vv;
074: }
075:
076: this .name = name;
077: setDestinationState(dest);
078: this .action = a;
079: this .validate = v;
080: }
081:
082: /**
083: * Retrieves the name for the transition. This should be unique for
084: * state-machine assembly purposes, but it does not have to be.
085: *
086: * @return a non-null name for this transition.
087: */
088: public String getName() {
089: return this .name;
090: }
091:
092: /**
093: * Returns the next state if the corresponding action is executed.
094: *
095: * @return destination state, which can never be <tt>null</tt>.
096: */
097: public IState getDestinationState() {
098: if (isDestinationStateSet()) {
099: return this .destination;
100: }
101: // else
102: throw new IllegalStateException("Destination was never set.");
103: }
104:
105: /**
106: * Returns the action used to transition to the destination state.
107: *
108: * @return transition's action, which can never be <tt>null</tt>.
109: */
110: public IAction getAction() {
111: return this .action;
112: }
113:
114: /**
115: * Returns all validation methods used to assert that the system can
116: * perform this transition.
117: *
118: * @return a list of associated validation instances.
119: */
120: public IValidate[] getValidates() {
121: int len = this .validate.length;
122: IValidate v[] = new IValidate[len];
123: System.arraycopy(this .validate, 0, v, 0, len);
124: return v;
125: }
126:
127: //-------------------------------------------------------------------------
128:
129: /**
130: * Allows for post-creation setting of the destination. The destination
131: * may only be set to a non-<tt>null</tt> value once. If there is an
132: * attempt to pull the destination through <tt>getDestinationState()</tt>
133: * and it has not been set yet, then an IllegalStateException will
134: * be thrown.
135: */
136: public void setDestinationState(IState dest) {
137: if (isDestinationStateSet()) {
138: throw new IllegalStateException(
139: "Destination has already been set.");
140: } else {
141: this .destination = dest;
142: }
143: }
144:
145: /**
146: * Allows for a builder system to detect if the destination state has
147: * been set or not, without causing the IllegalStateException through
148: * the <tt>getDestinationState()</tt>.
149: */
150: public boolean isDestinationStateSet() {
151: return (this .destination != null);
152: }
153:
154: public String toString() {
155: return "[Transition " + getName() + "]";
156: }
157: }
|