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 }