001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: *
017: */
018: package org.apache.lenya.cms.usecase;
019:
020: import org.apache.lenya.util.Assert;
021:
022: /**
023: * A simple state machine.
024: */
025: public class StateMachine {
026:
027: String currentState;
028: private Model model;
029:
030: /**
031: * @param model The model to use.
032: */
033: public StateMachine(Model model) {
034: this .model = model;
035: this .currentState = model.getInitialState();
036: }
037:
038: void invoke(String event) {
039: Transition transition = getTransition(event);
040: checkTransition(event, transition);
041: this .currentState = transition.destination;
042: }
043:
044: protected Transition getTransition(String event) {
045: Assert.notNull("event", event);
046: Transition[] transitions = this .model.getTransitions();
047: Transition transition = null;
048: for (int i = 0; i < transitions.length; i++) {
049: Transition t = transitions[i];
050: if (canFire(t, event)) {
051: if (transition != null) {
052: throw new IllegalStateException(
053: "More than 1 transition for event ["
054: + event + "] in state ["
055: + this .currentState + "]!");
056: }
057: transition = t;
058: }
059: }
060: return transition;
061: }
062:
063: protected boolean canFire(Transition t, String event) {
064: return t.getSource().equals(this .currentState)
065: && t.getEvent().equals(event);
066: }
067:
068: void checkEvent(String event) {
069: Transition transition = getTransition(event);
070: checkTransition(event, transition);
071: }
072:
073: protected void checkTransition(String event, Transition transition) {
074: if (transition == null) {
075: throw new IllegalStateException(
076: "No transition found for event [" + event
077: + "] in state [" + this .currentState + "]!");
078: }
079: }
080:
081: /**
082: * A state machine model.
083: */
084: public static class Model {
085:
086: private String initialState;
087:
088: /**
089: * @param initialState The initial state.
090: * @param transitions The transitions.
091: */
092: public Model(String initialState, Transition[] transitions) {
093: this .transitions = transitions;
094: this .initialState = initialState;
095: }
096:
097: /**
098: * @return The initial state.
099: */
100: public String getInitialState() {
101: return this .initialState;
102: }
103:
104: private Transition[] transitions;
105:
106: /**
107: * @return The transitions.
108: */
109: public Transition[] getTransitions() {
110: return this .transitions;
111: }
112: }
113:
114: /**
115: * A transition switches from a source state to a destination state if an
116: * event is invoked.
117: */
118: public static class Transition {
119:
120: /**
121: * @param source The source state.
122: * @param destination The destination state.
123: * @param event The event.
124: */
125: public Transition(String source, String destination,
126: String event) {
127: this .source = source;
128: this .destination = destination;
129: this .event = event;
130: }
131:
132: private String source;
133: private String destination;
134: private String event;
135:
136: /**
137: * @return The destination state.
138: */
139: public String getDestination() {
140: return destination;
141: }
142:
143: /**
144: * @return The event.
145: */
146: public String getEvent() {
147: return event;
148: }
149:
150: /**
151: * @return The source state.
152: */
153: public String getSource() {
154: return source;
155: }
156: }
157:
158: }
|