Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
DialogImpl |
|
| 1.5625;1.562 |
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 | 0 | 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 | 0 | private Class dataClass = HashMap.class; |
44 | ||
45 | ||
46 | /** | |
47 | * <p>Name of this {@link Dialog}.</p> | |
48 | */ | |
49 | 0 | private String name = null; |
50 | ||
51 | ||
52 | /** | |
53 | * <p>Name of the starting {@link State} for this {@link Dialog}.</p> | |
54 | */ | |
55 | 0 | 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 | 0 | 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 | 0 | 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 | 0 | 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 | 0 | 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 | 0 | 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 | 0 | 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 | 0 | 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 | 0 | 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 | 0 | 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 | 0 | 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 | 0 | if (states.containsKey(state.getName())) { |
206 | 0 | throw new IllegalArgumentException(state.getName()); |
207 | } | |
208 | 0 | states.put(state.getName(), state); |
209 | 0 | if (state instanceof AbstractState) { |
210 | 0 | ((AbstractState) state).setDialog(this); |
211 | } | |
212 | ||
213 | 0 | } |
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 | 0 | transitions.put(transition.getOutcome(), transition); |
229 | ||
230 | 0 | } |
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 | 0 | 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 | 0 | ClassLoader loader = Thread.currentThread().getContextClassLoader(); |
258 | 0 | if (loader == null) { |
259 | 0 | loader = DialogImpl.class.getClassLoader(); |
260 | } | |
261 | try { | |
262 | 0 | this.dataClass = loader.loadClass(dataClassName); |
263 | 0 | } catch (RuntimeException e) { |
264 | 0 | throw e; |
265 | 0 | } catch (Exception e) { |
266 | 0 | throw new IllegalArgumentException(e.toString()); |
267 | 0 | } |
268 | ||
269 | 0 | } |
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 | 0 | this.name = name; |
280 | ||
281 | 0 | } |
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 | 0 | this.start = start; |
293 | ||
294 | 0 | } |
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 | 0 | states.remove(state.getName()); |
307 | 0 | if (state instanceof AbstractState) { |
308 | 0 | ((AbstractState) state).setDialog(null); |
309 | } | |
310 | ||
311 | 0 | } |
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 | 0 | transitions.remove(transition.getOutcome()); |
324 | ||
325 | 0 | } |
326 | ||
327 | ||
328 | } |