1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package tsukuba_bunko.peko.scenario;
20
21 import java.io.Serializable;
22
23 import java.util.List;
24 import java.util.Map;
25 import java.util.Set;
26
27 import tsukuba_bunko.peko.Logger;
28
29 import tsukuba_bunko.peko.session.Session;
30
31
32 /***
33 * シーン処理のコンテクストです。
34 * @author $Author: ppoi $
35 * @version $Revision: 1.2 $
36 */
37 public class SceneContext implements Serializable {
38
39 /***
40 * serial version UID
41 */
42 private static final long serialVersionUID = 1698890995605002291L;
43
44 /***
45 * シーン名
46 */
47 protected String _sceneName = null;
48
49 /***
50 * シーンタイトル
51 */
52 protected String _sceneTitle = null;
53
54 /***
55 * シーンのプロパティ情報
56 */
57 protected Map _properties = null;
58
59 /***
60 * シーン遷移先表
61 */
62 protected NextSceneMapping _nextSceneMapping = null;
63
64 /***
65 * 現在位置
66 */
67 transient protected Node _current = null;
68
69 /***
70 * 保存された最後の位置
71 */
72 protected Node _lastCommittedNode = null;
73
74 /***
75 * シーンスコープ フラグ
76 */
77 protected Set _sceneScopeFlags = null;
78
79 /***
80 * セッション
81 */
82 transient protected Session _session = null;
83
84 /***
85 * このシーンを処理中の SceneProcessor
86 */
87 transient protected SceneProcessor _processor = null;
88
89
90 /***
91 * <code>SceneContext</code> のインスタンスを生成します。
92 * @param sceneName シーン名
93 * @param session セッション
94 * @param processor このシーンを処理するシーンプロセッサ
95 */
96 public SceneContext( String sceneName, Session session, SceneProcessor processor )
97 {
98 _sceneName = sceneName;
99 _session = session;
100 _processor = processor;
101
102 SceneContext previous = session.getSceneContext();
103 if( previous != null ) {
104 _lastCommittedNode = previous.getLastCommittedNode();
105 _properties = previous._properties;
106 _nextSceneMapping = previous.getNextSceneMapping();
107 _sceneScopeFlags = previous._sceneScopeFlags;
108 }
109 else {
110 _nextSceneMapping = new NextSceneMapping();
111 _sceneScopeFlags = new java.util.HashSet();
112 }
113 }
114
115
116 /***
117 * シーン名を取得します。
118 * @return シーン名
119 */
120 public String getSceneName()
121 {
122 return _sceneName;
123 }
124
125 /***
126 * シーンタイトルを設定します。
127 * @param title シーンタイトル
128 */
129 public void setSceneTitle( String title )
130 {
131 _sceneTitle = title;
132 }
133
134 /***
135 * シーンタイトルを取得します。
136 * @return シーンタイトル
137 */
138 public String getSceneTitle()
139 {
140 return _sceneTitle;
141 }
142
143 /***
144 * セッションを取得します。
145 * @return セッション
146 */
147 public Session getSession()
148 {
149 return _session;
150 }
151
152 /***
153 * シーンプロセッサを取得します。
154 * @return シーンプロセッサ
155 */
156 public SceneProcessor getSceneProcessor()
157 {
158 return _processor;
159 }
160
161 /***
162 * シーンプロパティを設定します。
163 * @param name プロパティ名
164 * @param value プロパティ値
165 */
166 public void setProperty( String name, String value )
167 {
168 if( _properties == null ) {
169 _properties = new java.util.HashMap( 17 );
170 }
171 _properties.put( name, value );
172 }
173
174 /***
175 * シーンプロパティを取得します。
176 * @param name プロパティ名
177 * @return プロパティ値。<code>name</code> で識別されるプロパティが設定されていない場合は <code>null</code>。
178 */
179 public String getProperty( String name )
180 {
181 if( _properties == null ) {
182 return null;
183 }
184 else {
185 return (String)_properties.get( name );
186 }
187 }
188
189 /***
190 * 遷移先表を設定します。
191 * @param mapping 遷移先表
192 */
193 public void setNextSceneMapping( NextSceneMapping mapping )
194 {
195 _nextSceneMapping = mapping;
196 }
197
198 /***
199 * 遷移先表を取得します。
200 * @return 遷移先表
201 */
202 public NextSceneMapping getNextSceneMapping()
203 {
204 return _nextSceneMapping;
205 }
206
207 /***
208 * 次のシーンを取得します。
209 * @return このシーンの処理後に遷移するシーンのシーン名
210 */
211 public String getNextSceneName()
212 {
213 return _nextSceneMapping.getNextScene( this );
214 }
215
216 /***
217 * 指定されたノードの処理が開始されたことを通知します。
218 */
219 public void pushNode( String nodeName )
220 {
221 if( _current == null ) {
222 _current = new Node( null, nodeName.intern(), 1 );
223 }
224 else {
225 int position = _current.countSibling(nodeName) + 1;
226 Node child = new Node( _current, nodeName.intern(), position );
227 _current.addChildNode( child );
228 _current = child;
229 }
230 }
231
232 /***
233 * 現在のノードの処理が終了したことを通知します。
234 */
235 public void popNode()
236 {
237 if( _current == null ) {
238 Logger.error( "[scenario] BUG! invalid state of SceneLog." );
239 }
240 else {
241 _current.removeChildren();
242 _current = _current.getParentNode();
243 }
244 }
245
246 /***
247 * 現在の位置を保存します。
248 */
249 public void saveCurrentNode()
250 {
251 _lastCommittedNode = _current;
252 }
253
254 /***
255 * 保存された最後の位置を取得します。
256 * @return 保存された最後の位置
257 */
258 public Node getLastCommittedNode()
259 {
260 return _lastCommittedNode;
261 }
262
263 /***
264 * <code>node</code> が現在処理中のノードと同一であるかどうかを判定します。
265 * @param node 判定対象のノード
266 * @return 同一での場合 <code>true</code>、それ以外の場合 <code>false</code>
267 */
268 public boolean isCurrentNode( Node node )
269 {
270 if( node == _current ) {
271 return true;
272 }
273 else if( _current != null ) {
274 return _current.equals(node);
275 }
276 else {
277 return false;
278 }
279 }
280
281 /***
282 * 現在処理中のノードのコピーを取得します。コピーには、子ノードリストは含まれません。
283 * @return 現在処理中のノードのコピー
284 */
285 public Node getCurrentNode()
286 {
287 Node node = _current;
288 if( node == null ) {
289 return null;
290 }
291 else {
292 Node copy = new Node( null, node._nodeName, node._position );
293 Node temp = copy;
294 while( (node = node.getParentNode()) != null ) {
295 temp._parent = new Node( null, node.getNodeName(), node.getPosition() );
296 temp = temp.getParentNode();
297 }
298 return copy;
299 }
300 }
301
302 /***
303 * 現在処理中のパスを XPath で取得します。
304 * @return 現在処理中のパス
305 */
306 public String getCurrentPath()
307 {
308 if( _current != null ) {
309 return _current.getPath();
310 }
311 else {
312 return "/";
313 }
314 }
315
316
317 /***
318 * フラグを立てます。
319 * @param flagID フラグ ID
320 * @param scope フラグスコープ
321 * @throws IllegalArgumentException <code>flagID</code> が <code>null</code> の場合
322 */
323 public void declareFlag( String flagID, FlagScope scope )
324 {
325 if( flagID == null ) {
326 throw new IllegalArgumentException();
327 }
328
329 if( scope == FlagScope.SCENE ) {
330 _sceneScopeFlags.add( flagID );
331 }
332 else if( scope == FlagScope.SESSION ) {
333 _session.declareSessionFlag( flagID );
334 }
335 else if( scope == FlagScope.SYSTEM ) {
336 _session.declareSystemFlag( flagID );
337 }
338 }
339
340 /***
341 * フラグをおろします。
342 * @param flagID フラグ ID
343 * @param scope フラグスコープ
344 * @throws IllegalArgumentException <code>flagID</code> が <code>null</code> の場合
345 */
346 public void undeclareFlag( String flagID, FlagScope scope )
347 {
348 if( flagID == null ) {
349 throw new IllegalArgumentException();
350 }
351
352 if( scope == FlagScope.SCENE ) {
353 _sceneScopeFlags.remove( flagID );
354 }
355 else if( scope == FlagScope.SESSION ) {
356 _session.undeclareSessionFlag( flagID );
357 }
358 else if( scope == FlagScope.SYSTEM ) {
359 _session.undeclareSystemFlag( flagID );
360 }
361 }
362
363 /***
364 * スコープを問わず、フラグが立っているかどうかを判定します。
365 * @param flagID フラグ ID
366 */
367 public boolean isDeclaredFlag( String flagID )
368 {
369 if( _sceneScopeFlags.contains(flagID) ) {
370 return true;
371 }
372 else if( _session.isDeclaredSessionFlag(flagID) ) {
373 return true;
374 }
375 else if( _session.isDeclaredSystemFlag(flagID) ) {
376 return true;
377 }
378 else {
379 return false;
380 }
381 }
382
383 /***
384 * 指定されたスコープでフラグが立っているかどうかを判定します。
385 * @param flagID フラグ ID
386 * @param scope フラグスコープ
387 * @return 指定されたフラグスコープでフラグが立っている場合 <code>true</code>、それ以外の場合 <code>false</code>
388 */
389 public boolean isDeclaredFlag( String flagID, FlagScope scope )
390 {
391 if( scope == FlagScope.SCENE ) {
392 return _sceneScopeFlags.contains( flagID );
393 }
394 else if( scope == FlagScope.SESSION ) {
395 return _session.isDeclaredSessionFlag( flagID );
396 }
397 else if( scope == FlagScope.SYSTEM ) {
398 return _session.isDeclaredSystemFlag( flagID );
399 }
400 else {
401 return false;
402 }
403 }
404
405
406
407
408 /***
409 * PSML Scene 文書を構成するノードです。
410 */
411 public static class Node implements Serializable {
412
413 /***
414 * serial version UID
415 */
416 private static final long serialVersionUID = 7590190847826566241L;
417
418 /***
419 * 親ノード
420 */
421 protected Node _parent = null;
422
423 /***
424 * ノード名
425 */
426 protected String _nodeName = null;
427
428 /***
429 * position
430 */
431 protected int _position = 0;
432
433 /***
434 * 子ノードリスト
435 */
436 protected List _children = null;
437
438
439 /***
440 * <code>SceneContext.Node</code> のインスタンスを生成します。
441 */
442 public Node( Node parent, String nodeName, int position )
443 {
444 _parent = parent;
445 _nodeName = nodeName.intern();
446 _position = position;
447 }
448
449 /***
450 * 親ノードを取得します。
451 * @return 親ノード
452 */
453 public Node getParentNode()
454 {
455 return _parent;
456 }
457
458 /***
459 * ノード名を取得します。
460 * @return ノード名
461 */
462 public String getNodeName()
463 {
464 return _nodeName;
465 }
466
467 /***
468 * ポジションを取得します。
469 * @return ポジション
470 */
471 public int getPosition()
472 {
473 return _position;
474 }
475
476
477 /***
478 * 子ノードを追加します。
479 * @param child 子ノード
480 */
481 public void addChildNode( Node child )
482 {
483 if( _children == null ) {
484 _children = new java.util.ArrayList();
485 }
486 _children.add( child );
487 }
488
489 /***
490 * 子ノードのなかで、指定された名前のノードの数をカウントします。
491 * @param nodeName 子ノード名
492 * @return ノード数
493 */
494 public int countSibling( String nodeName )
495 {
496 if( _children == null ) {
497 return 0;
498 }
499 else {
500 String symbol = nodeName.intern();
501 List children = _children;
502 int size = children.size();
503 Node node = null;
504 int count = 0;
505 for( int i = 0; i < size; ++i ) {
506 node = (Node)children.get( i );
507 if( node._nodeName == symbol ) {
508 count++;
509 }
510 }
511 return count;
512 }
513 }
514
515 /***
516 * このノードをルートとするサブツリーを破棄します。
517 */
518 public void removeChildren()
519 {
520 if( _children != null ) {
521 List children = _children;
522 int size = children.size();
523 for( int i = 0; i < size; ++i ) {
524 ((Node)children.get(i)).removeChildren();
525 }
526 children.clear();
527 _children = null;
528 }
529 }
530
531 /***
532 * このノードまでのパスを XPath 形式で取得します。
533 * @return このノードまでのパス
534 */
535 public String getPath()
536 {
537 StringBuffer sink = new StringBuffer();
538 Node node = this;
539 while( node != null ) {
540 sink.insert( 0, node );
541 node = node.getParentNode();
542 }
543 return new String(sink);
544 }
545
546 public boolean equals( Object obj )
547 {
548 if( obj instanceof Node ) {
549 Node target = (Node)obj;
550 Node node = this;
551 while( (node != null) && (target != null) ) {
552 if( !node._nodeName.equals(target._nodeName) || (node._position != target._position) ) {
553 return false;
554 }
555 node = node._parent;
556 target = target._parent;
557 }
558 return ((node == null) && (target == null));
559 }
560 else {
561 return false;
562 }
563 }
564
565 public String toString()
566 {
567 return "/" + _nodeName + "[" + _position + "]";
568 }
569 }
570 }