1 29 package net.sourceforge.groboutils.mbtf.v1.engine; 30 31 32 import java.util.Vector ; 33 import java.util.Stack ; 34 import java.util.Hashtable ; 35 36 import net.sourceforge.groboutils.mbtf.v1.IPath; 37 import net.sourceforge.groboutils.mbtf.v1.IState; 38 import net.sourceforge.groboutils.mbtf.v1.ITransition; 39 import net.sourceforge.groboutils.mbtf.v1.IPathGenerator; 40 41 import org.apache.log4j.Logger; 42 43 44 56 public class BreadthPathGenerator implements IPathGenerator 57 { 58 private static final Logger LOG = Logger.getLogger( 59 BreadthPathGenerator.class ); 60 61 66 static class InnerState 67 { 68 private IState state; 69 private InnerTransition[] dest; 70 private Vector sources = new Vector (); 71 private Vector endStatePaths = new Vector (); 72 73 public InnerState( IState s, Hashtable stateHash ) 74 { 75 if (s == null || stateHash == null) 76 { 77 throw new IllegalArgumentException ("no null args"); 78 } 79 LOG.debug("Adding state '"+s.getName()+"' to inner set"); 80 81 this.state = s; 82 83 stateHash.put( s, this ); 85 86 ITransition t[] = s.getTransitions(); 88 if (t == null) 89 { 90 throw new IllegalStateException ("state "+s+ 91 " getTransitions() returned null."); 92 } 93 int len = t.length; 94 this.dest = new InnerTransition[ len ]; 95 for (int i = len; --i >= 0;) 96 { 97 if (t[i] == null) 98 { 99 throw new IllegalStateException ("Transition "+i+ 100 " for state "+s.getName()+" is null."); 101 } 102 IState nextState = t[i].getDestinationState(); 103 if (nextState == null) 104 { 105 throw new IllegalStateException ("Transition "+i+ 106 " for state "+s.getName()+ 107 " has null destination state."); 108 } 109 110 InnerState ns = (InnerState)stateHash.get( nextState ); 111 if (ns == null) 112 { 113 ns = new InnerState( nextState, stateHash ); 114 } 115 LOG.debug("Adding transition "+t[i]+" from "+this+" to "+ns); 116 this.dest[i] = new InnerTransition( t[i], ns, this ); 117 118 ns.addSourceTransition( this.dest[i] ); 120 } 121 } 122 123 124 public InnerStatePath createStatePath() 125 { 126 return new InnerStatePath( this ); 127 } 128 129 130 public InnerTransition[] getDestinations() 131 { 132 return this.dest; 133 } 134 135 136 public InnerTransition[] getSources() 137 { 138 InnerTransition[] t = new InnerTransition[ this.sources.size() ]; 139 this.sources.copyInto( t ); 140 return t; 141 } 142 143 144 public IState getState() 145 { 146 return this.state; 147 } 148 149 150 private void addSourceTransition( InnerTransition it ) 151 { 152 if (it != null && !this.sources.contains( it )) 153 { 154 this.sources.addElement( it ); 155 } 156 } 157 158 159 public String toString() 160 { 161 if (getState() != null) 162 { 163 return getState().toString(); 164 } 165 return "[initial state]"; 166 } 167 } 168 169 170 private static class InnerTransition 171 { 172 private ITransition trans; 173 private InnerState nextState; 174 private InnerState prevState; 175 176 177 public InnerTransition( ITransition trans, InnerState next, 178 InnerState prev ) 179 { 180 this.trans = trans; 181 this.nextState = next; 182 this.prevState = prev; 183 } 184 185 186 public ITransition getTransition() 187 { 188 return this.trans; 189 } 190 191 192 public InnerState getNextState() 193 { 194 return this.nextState; 195 } 196 197 198 public InnerState getSourceState() 199 { 200 return this.prevState; 201 } 202 203 204 public String toString() 205 { 206 return "["+this.trans+" from "+getSourceState()+" to "+ 207 getNextState()+"]"; 208 } 209 } 210 211 212 217 private static class InnerStatePath 218 { 219 private InnerState is; 220 private InnerTransition[] trans; 221 private InnerStatePath[] nextPaths; 222 private int currentIndex; 223 224 protected InnerStatePath( InnerState is ) 225 { 226 this.is = is; 227 228 this.trans = is.getDestinations(); 230 if (this.trans == null) 231 { 232 this.trans = new InnerTransition[0]; 233 } 234 235 reset(); 236 } 237 238 239 protected InnerStatePath( InnerState[] states ) 241 { 242 this.is = null; 243 int len = states.length; 244 this.trans = new InnerTransition[ len ]; 245 for (int i = len; --i >= 0;) 246 { 247 this.trans[i] = new InnerTransition( null, states[i], null ); 248 } 249 250 reset(); 251 } 252 253 254 public InnerStatePath getCurrentPath() 255 { 256 if (this.nextPaths.length <= 0) 257 { 258 return null; 259 } 260 int index = this.currentIndex; 261 if (index >= this.nextPaths.length) 263 { 264 throw new IllegalStateException ( 265 "Inner index is outside expected range." ); 266 } 267 268 if (this.nextPaths[ index ] == null) 269 { 270 this.nextPaths[ index ] = getCurrentTransition(). 271 getNextState().createStatePath(); 272 } 273 LOG.debug("current path index = "+(index+1)+" / "+ 274 this.nextPaths.length); 275 return this.nextPaths[ index ]; 276 } 277 278 279 public InnerTransition getCurrentTransition() 280 { 281 if (this.trans.length <= 0) 282 { 283 return null; 284 } 285 if (this.currentIndex >= this.trans.length) 287 { 288 throw new IllegalStateException ( 289 "Inner index is outside expected range." ); 290 } 291 292 return this.trans[ this.currentIndex ]; 293 } 294 295 296 301 public boolean advanceTransition() 302 { 303 boolean ret = false; 304 305 ++this.currentIndex; 306 307 if (this.currentIndex >= this.trans.length) 308 { 309 reset(); 311 312 ret = true; 314 } 315 if (this.currentIndex < this.trans.length) 316 { 317 LOG.debug("advanced path to "+getCurrentTransition()); 318 } 319 320 return ret; 321 } 322 323 324 332 public boolean addPath( int remainingDepth, Vector path ) 333 { 334 336 if (this.trans.length <= 0) 338 { 339 return true; 340 } 341 342 LOG.debug("Entering addPath with state "+this.is); 343 344 boolean ret = false; 345 InnerTransition it = getCurrentTransition(); 346 ITransition trans = it.getTransition(); 347 int nextDepth = remainingDepth; 348 349 if (trans != null) 351 { 352 path.addElement( trans ); 353 --nextDepth; 354 } 355 356 if (remainingDepth > 0) 358 { 359 if (getCurrentPath().addPath( nextDepth, path )) 360 { 361 LOG.debug("addPath state "+this.is+ 364 " advancing Transition"); 365 ret = advanceTransition(); 366 } 367 } 368 else 369 { 370 LOG.debug( "no remaining depth to enter" ); 372 ret = true; 373 374 } 377 378 LOG.debug("Leaving addPath with state "+this.is+ 379 " and return code "+ret); 380 381 return ret; 382 } 383 384 385 protected void reset() 386 { 387 int len = this.trans.length; 388 389 this.nextPaths = new InnerStatePath[ len ]; 392 this.currentIndex = 0; 393 } 394 } 395 396 397 private InnerState startStates[]; 399 400 private InnerStatePath startNode; 403 404 private int currentDepth; 406 407 408 421 public BreadthPathGenerator( IState startStates[], IState endStates[] ) 422 { 423 if (startStates == null) 425 { 426 throw new IllegalArgumentException ("no null start states allowed"); 427 } 428 if (endStates == null) 429 { 430 endStates = new IState[0]; 431 } 432 433 Hashtable knownStates = new Hashtable (); 435 int startLen = startStates.length; 436 this.startStates = new InnerState[ startLen ]; 437 for (int i = startLen; --i >= 0;) 438 { 439 this.startStates[i] = new InnerState( startStates[i], 440 knownStates ); 441 } 442 443 int endLen = endStates.length; 445 for (int i = endLen; --i >= 0;) 446 { 447 if (!knownStates.contains( endStates[i] )) 448 { 449 throw new IllegalArgumentException ("End state "+ 450 endStates[i].getName()+" is unreachable."); 451 } 452 } 453 454 458 } 459 460 461 464 public IPath getNextPath() 465 { 466 LOG.debug( "enter getNextPath()" ); 467 if (this.startNode == null) 468 { 469 reset(); 470 } 471 472 InnerTransition it = this.startNode.getCurrentTransition(); 474 if (it == null) 475 { 476 throw new IllegalStateException ( 477 "No known start states." ); 478 } 479 InnerState is = it.getNextState(); 480 if (is == null) 481 { 482 throw new IllegalStateException ( 483 "Transition destination state is null." ); 484 } 485 486 Vector v = new Vector ( this.currentDepth ); 487 LOG.debug( "forming path" ); 488 if (this.startNode.addPath( this.currentDepth, v )) 489 { 490 ++this.currentDepth; 492 } 493 494 ITransition t[] = new ITransition[ v.size() ]; 495 v.copyInto( t ); 496 LOG.debug( "creating IPath" ); 497 IPath p = new PathImpl( is.getState(), t ); 498 499 LOG.debug( "leaving getNextPath()" ); 500 return p; 501 } 502 503 504 509 public void reset() 510 { 511 LOG.debug("Entering reset()"); 512 this.startNode = new InnerStatePath( startStates ); 513 514 this.currentDepth = 1; 518 519 LOG.debug("Leaving reset()"); 520 } 521 } 522 523 | Popular Tags |