View Javadoc

1   /*
2    * All Rights Reserved.
3    * Copyright (C) 1999-2005 Tsukuba Bunko.
4    *
5    * Licensed under the BSD License ("the License"); you may not use
6    * this file except in compliance with the License.
7    * You may obtain a copy of the License at
8    *
9    *       http://www.tsukuba-bunko.org/licenses/LICENSE.txt
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   * $Id: SceneContext.java,v 1.2 2005/07/23 19:06:28 ppoi Exp $
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 }