2009/05/20 - Apache Shale has been retired.

For more information, please explore the Attic.

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  
18  package org.apache.shale.dialog.basic.config;
19  
20  import java.util.HashMap;
21  import java.util.Iterator;
22  import java.util.Map;
23  import org.apache.shale.dialog.basic.model.Dialog;
24  import org.apache.shale.dialog.basic.model.State;
25  import org.apache.shale.dialog.basic.model.Transition;
26  
27  /***
28   * <p>{@link DialogImpl} is a basic implementation of {@link Dialog}.</p>
29   *
30   * @since 1.0.4
31   */
32  public final class DialogImpl implements Dialog {
33  
34  
35      // ------------------------------------------------------ Instance Variables
36  
37  
38      /***
39       * <p>The class of a JavaBean to be instantiated as the initial
40       * value of the <code>data</code> property of a newly instantiated
41       * <code>DialogContext</code>.</p>
42       */
43      private Class dataClass = HashMap.class;
44  
45  
46      /***
47       * <p>Name of this {@link Dialog}.</p>
48       */
49      private String name = null;
50  
51  
52      /***
53       * <p>Name of the starting {@link State} for this {@link Dialog}.</p>
54       */
55      private String start = null;
56  
57  
58      /***
59       * <p>The {@link State}s owned by this {@link Dialog}, keyed by
60       * identifier.</p>
61       */
62      private Map states = new HashMap();
63  
64  
65      /***
66       * <p>The global {@link Transition}s owned by this {@link Dialog}, keyed by
67       * outcome.  Logic that performs transition management should first check
68       * for a {@link Transition} associated with the origin {@link State}, then
69       * consult the {@link Dialog} for a global definition.</p>
70       */
71      private Map transitions = new HashMap();
72  
73  
74      // -------------------------------------------------------------- Properties
75  
76  
77      /***
78       * <p>Return the class of a JavaBean to be instantiated as the initial
79       * value of the <code>data</code> property of a newly instantiated
80       * <code>DialogContext</code>.</p>
81       *
82       * @return The JavaBean class whose instance becomes the <code>data</code>
83       *         property of a new instance of this dialog
84       */
85      public Class getDataClass() {
86  
87          return this.dataClass;
88  
89      }
90  
91  
92      /***
93       * <p>Return the name of this {@link Dialog}.</p>
94       *
95       * @return The name of this {@link Dialog}
96       */
97      public String getName() {
98  
99          return this.name;
100 
101     }
102 
103 
104     /***
105      * <p>Return the name of the starting {@link State} for this
106      * {@link Dialog}.</p>
107      *
108      * @return The starting state associated with this {@link Dialog}
109      */
110     public String getStart() {
111 
112         return this.start;
113 
114     }
115 
116 
117     /***
118      * <p>Return an <code>Iterator</code> over the names of {@link State}s
119      * that are owned by this {@link Dialog}.  If there are no such
120      * {@link State}s, an empty <code>Iterator</code> is returned.</p>
121      *
122      * @return An <code>Iterator</code> over all the {@link State}s in this
123      *         {@link Dialog}
124      */
125     public Iterator getStateIds() {
126 
127         return this.states.keySet().iterator();
128 
129     }
130 
131 
132     /***
133      * <p>Return an <code>Iterator</code> over the logical outcomes of
134      * global {@link Transition}s for this {@link Dialog}.  If there are
135      * no such {@link Transition}s, an empty <code>Iterator</code> is
136      * returned.</p>
137      *
138      * @return An <code>Iterator</code> over the logical outcomes of global
139      *         {@link Transition}s for this {@link Dialog}
140      */
141     public Iterator getTransitionOutcomes() {
142 
143         return this.transitions.keySet().iterator();
144 
145     }
146 
147 
148     // ---------------------------------------------------------- Public Methods
149 
150 
151     /***
152      * <p>Return the specified {@link State}, owned by this {@link Dialog},
153      * if any.  Otherwise, return <code>null</code>.</p>
154      *
155      * @param id Identifier of the requested {@link State}
156      * @return The {@link State} specified by the identifier, may be null
157      */
158     public State findState(String id) {
159 
160         return (State) states.get(id);
161 
162     }
163 
164 
165     /***
166      * <p>Return the global {@link Transition} for the specified logical outcome,
167      * if any; otherwise, return <code>null</code>.</p>
168      *
169      * @param outcome Logical outcome for which to return a {@link Transition}
170      * @return The global {@link Transition} for the specified logical outcome
171      */
172     public Transition findTransition(String outcome) {
173 
174         return (Transition) transitions.get(outcome);
175 
176     }
177 
178 
179     /***
180      * <p>Render a printable version of this instance.</p>
181      *
182      * @return A printable version of this instance
183      */
184     public String toString() {
185 
186         return "Dialog[name=" + this.name + ",start=" + this.start + "]";
187 
188     }
189 
190 
191     // --------------------------------------------------- Configuration Methods
192 
193 
194     /***
195      * <p>Add the specified {@link State} to the {@link State}s owned by
196      * this {@link Dialog}.</p>
197      *
198      * @param state {@link State} to be added
199      *
200      * @exception IllegalArgumentException if there is already a {@link State}
201      *  with the specified <code>id</code> owned by this {@link Dialog}
202      */
203     public void addState(State state) throws IllegalArgumentException {
204 
205         if (states.containsKey(state.getName())) {
206             throw new IllegalArgumentException(state.getName());
207         }
208         states.put(state.getName(), state);
209         if (state instanceof AbstractState) {
210             ((AbstractState) state).setDialog(this);
211         }
212 
213     }
214 
215 
216     /***
217      * <p>Add the specified {@link Transition} to the global {@link Transition}s
218      * associated with this {@link Dialog}.</p>
219      *
220      * @param transition {@link Transition} to be added
221      *
222      * @exception IllegalArgumentException if the specified {@link Transition}
223      *  cannot be added to this {@link State}
224      */
225     public void addTransition(Transition transition) throws IllegalArgumentException {
226 
227         // FIXME - addTransition() - ignore duplicate outcomes for now
228         transitions.put(transition.getOutcome(), transition);
229 
230     }
231 
232 
233     /***
234      * <p>Return the data class name for the <code>data</code> property
235      * of a newly instantiated <code>DialogContext</code>.</p>
236      *
237      * @return The fully qualified class name whose instance becomes the
238      *         <code>data</code> property of a new instance of this dialog
239      */
240     public String getDataClassName() {
241 
242         return dataClass.getName();
243 
244     }
245 
246 
247     /***
248      * <p>Set the data class name for the <code>data</code> property
249      * of a newly instantiated <code>DialogContext</code>.</p>
250      *
251      * @param dataClassName New data class name
252      *
253      * @exception Exception if the specified class name cannot be loaded
254      */
255     public void setDataClassName(String dataClassName) {
256 
257         ClassLoader loader = Thread.currentThread().getContextClassLoader();
258         if (loader == null) {
259             loader = DialogImpl.class.getClassLoader();
260         }
261         try {
262             this.dataClass = loader.loadClass(dataClassName);
263         } catch (RuntimeException e) {
264             throw e;
265         } catch (Exception e) {
266             throw new IllegalArgumentException(e.toString());
267         }
268 
269     }
270 
271 
272     /***
273      * <p>Set the name of this {@link Dialog}.</p>
274      *
275      * @param name New name
276      */
277     public void setName(String name) {
278 
279         this.name = name;
280 
281     }
282 
283 
284     /***
285      * <p>Set the name of the starting {@link State} for this
286      * {@link Dialog}.</p>
287      *
288      * @param start Name of the starting {@link State}
289      */
290     public void setStart(String start) {
291 
292         this.start = start;
293 
294     }
295 
296 
297     /***
298      * <p>Remove the specified {@link State} from the {@link State}s owned by
299      * this {@link Dialog}, if it is currently registered.  Otherwise,
300      * do nothing.</p>
301      *
302      * @param state {@link State} to be removed
303      */
304     public void removeState(State state) {
305 
306         states.remove(state.getName());
307         if (state instanceof AbstractState) {
308             ((AbstractState) state).setDialog(null);
309         }
310 
311     }
312 
313 
314     /***
315      * <p>Remove the specified {@link Transition} from the global
316      * {@link Transition}s associated with this {@link Dialog}, if it is
317      * currently registered.  Otherwise, do nothing.</p>
318      *
319      * @param transition {@link Transition} to be removed
320      */
321     public void removeTransition(Transition transition) {
322 
323         transitions.remove(transition.getOutcome());
324 
325     }
326 
327 
328 }