KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > tc > jrexx > set > SAutomaton


1 /*
2 * 01/07/2003 - 15:19:32
3 *
4 * SAutomaton.java -
5 * Copyright (C) 2003 Buero fuer Softwarearchitektur GbR
6 * ralf.meyer@karneim.com
7 * http://jrexx.sf.net
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public License
11 * as published by the Free Software Foundation; either version 2
12 * of the License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */

23 package com.tc.jrexx.set;
24
25 import com.tc.jrexx.automaton.*;
26 import java.util.*;
27 import java.io.*;
28
29 /**
30  * This class represents a (non-)deterministic final automaton (NFA/DFA).
31  * Use this class to create an automaton manually by adding states to the automaton and transitions to other states
32  * or to browse through the automaton's states and implement your own matching strategies.
33  * <br>to create an automaton manually try
34  * <code>
35  * <br>import com.karneim.util.collection.set.*;
36  * <br>public class Test {
37  * <br> public static void main(String[] args) {
38  * <br> SAutomaton automaton = new SAutomaton();
39  * <br> {@link IStatePro} s1 = automaton.addState(false);
40  * <br> IStatePro s2 = automaton.addState(true);
41  * <br> s1.addTransition(new {@link CharSet}("0123456789"),s2);
42  * <br> s2.addTransition(new CharSet("0123456789"),s2);
43  * <br> automaton.setStartState(s1);
44  * <br> }
45  * <br>}
46  * <br>
47  * </code>
48  * <br>to browse through the automaton's states try
49  * <code>
50  * <br> final {@link IStatePro} startState = automaton.getStartState();
51  * <br> final {@link StateProSet} states = new StateProSet(startState);
52  * <br> final {@link StateProSet.Iterator} it = states.iterator();
53  * <br> for (IStatePro state=it.next(); state!=null; state=it.next()) {
54  * <br> IStatePro.ITransition[] transitions = state.getTransitions();
55  * <br> for (int i=0; i transitions.length; ++i) {
56  * <br> states.add(transitions[i].getToState());
57  * <br> System.out.println(
58  * <br> "from " + transitions[i].getFromState()
59  * <br> + " through " + transitions[i].getCharSet()
60  * <br> + " to " + transitions[i].getToState()
61  * <br> );
62  * <br> }
63  * <br> }
64  * <br>
65  * </code>
66  * <br>to implement own matching strategies try
67  * <code>
68  * <br> /**
69  * <br> * returns true if input is an existing path through automaton's states
70  * <br> * otherwise false.
71  * <br> *
72  * <br> public static boolean incompleteMatch(SAutomaton automaton,String input) {
73  * <br> {@link IState} current = automaton.getStartState().visit();
74  * <br> for (int i=0; i input.length(); ++i) {
75  * <br> current = current.next(input.charAt(i));
76  * <br> if (current == null) return false;
77  * <br> }
78  * <br> return true;
79  * <br> }
80  * </code>
81  *
82  * @author Ralf Meyer
83  * @version 1.0
84  */

85 public class SAutomaton {
86
87   private final class SAutomatonChangeListener implements Automaton.IChangedListener {
88
89     public void stateAdded(Automaton.State state) {
90       StatePro wrapper = (StatePro)SAutomaton.this.state2wrapper.get(state);
91       if (wrapper==null) wrapper = new StatePro((AutomatonSet_String.SState)state);
92     
93       final Iterator it = SAutomaton.this.listeners.iterator();
94       for (int i=SAutomaton.this.listeners.size(); i>0; --i) {
95         ((SAutomaton.IChangeListener)it.next()).stateAdded(wrapper);
96       }
97     }
98
99     public void stateRemoved(Automaton.State state) {
100       StatePro wrapper = (StatePro)SAutomaton.this.state2wrapper.get(state);
101       if (wrapper==null) wrapper = new StatePro((AutomatonSet_String.SState)state);
102     
103       final Iterator it = SAutomaton.this.listeners.iterator();
104       for (int i=SAutomaton.this.listeners.size(); i>0; --i) {
105         ((SAutomaton.IChangeListener)it.next()).stateRemoved(wrapper);
106       }
107     }
108
109     public void startStateChanged(Automaton.State oldStartState,Automaton.State newStartState) {
110       StatePro oldWrapper = null;
111       if (oldStartState!=null) {
112         oldWrapper = (StatePro)SAutomaton.this.state2wrapper.get(oldStartState);
113         if (oldWrapper==null) oldWrapper = new StatePro((AutomatonSet_String.SState)oldStartState);
114       }
115     
116       StatePro newWrapper = null;
117       if (newStartState!=null) {
118         newWrapper = (StatePro)SAutomaton.this.state2wrapper.get(newStartState);
119         if (newWrapper==null) newWrapper = new StatePro((AutomatonSet_String.SState)newStartState);
120       }
121     
122       final Iterator it = SAutomaton.this.listeners.iterator();
123       for (int i=SAutomaton.this.listeners.size(); i>0; --i) {
124         ((SAutomaton.IChangeListener)it.next()).startStateChanged(oldWrapper,newWrapper);
125       }
126     }
127   }
128
129   /**
130    * The listener interface for receiving change events of a SAutomaton.
131    * The class that is interested in processing an automaton's change event implements this interface.
132    * A listener instance of that class is registered with the automaton using the automaton's addChangeListener method.
133    * @author Ralf Meyer
134    * @version 1.0
135    */

136   public interface IChangeListener {
137     /**
138      The Automaton invokes this method on all registered listener if a new state has been added to the automaton.
139      */

140     public void stateAdded(IStatePro state);
141     /**
142      The Automaton invokes this method on all registered listener if an existing state has been removed from the automaton.
143      */

144     public void stateRemoved(IStatePro state);
145     /**
146      The Automaton invokes this method on all registered listener if the automaton's current startState has been changed.
147      Both oldStartState and newStartState can be null.
148      */

149     public void startStateChanged(IStatePro oldStartState, IStatePro newStartState);
150   }
151
152   protected class State implements IState {
153     protected final AutomatonSet_String.ISState state;
154     protected State(AutomatonSet_String.ISState state) {
155       this.state = state;
156     }
157
158     public boolean isFinal() {
159       return this.state.isFinal();
160     }
161
162     public IState next(char ch) {
163       final Automaton.IState nextState = this.state.next(ch);
164       return nextState==null ? null : new State((AutomatonSet_String.ISState)nextState);
165     }
166 /*
167     public IState nnext(String s) {
168       return this.nnext(s,0,s.length());
169     }
170
171     public IState nnext(String s,int offset) {
172       return this.nnext(s,0,s.length()-offset);
173     }
174
175     public IState nnext(String s,int offset,int length) {
176       AutomatonSet_String.IState state = this.state;
177       for (;length>0; --length, ++offset) {
178         AutomatonSet_String.IState newState = state.next(s.charAt(offset));
179         if (newState==null) break;
180         state = newState;
181       }
182       return new State((AutomatonSet_String.ISState)state);
183     }
184 */

185
186     public StateProSet getAllReachableStates() {
187       final StateProSet result = new StateProSet();
188       final Automaton.LinkedSet_State states = this.state.getAllReachableStates();
189       for (Automaton.Wrapper_State w = states.elements; w!=null; w=w.next) {
190
191         StatePro wrapper = (StatePro)SAutomaton.this.state2wrapper.get(w.state);
192         if (wrapper==null) wrapper = new StatePro((AutomatonSet_String.SState)w.state);
193         result.add(wrapper);
194       }
195       return result;
196     }
197
198     public String JavaDoc toString() {
199       return this.state.toString();
200     }
201   }
202
203   protected class Transition implements IStatePro.ITransition {
204     protected final Automaton.State.Transition transition;
205     protected Transition(Automaton.State.Transition transition) {
206       this.transition = transition;
207       SAutomaton.this.transition2wrapper.put(transition,this);
208     }
209 /*
210     protected void finalize() {
211       SAutomaton.this.transition2wrapper.remove(this.transition);
212     }
213 */

214     public IStatePro getFromState() {
215       StatePro wrapper = (StatePro)SAutomaton.this.state2wrapper.get(this.transition.getFromState());
216       if (wrapper==null)
217         wrapper = new StatePro((AutomatonSet_String.SState)this.transition.getFromState());
218       return wrapper;
219     }
220
221     public Set getLabels() {
222       final HashSet labels = (HashSet)this.transition.properties;
223 // if (labels!=null) return java.util.Collections.unmodifiableSet(labels);
224
if (labels!=null) return labels;
225       return java.util.Collections.EMPTY_SET;
226     }
227
228     public ISet_char getCharSet() {
229       return this.transition.getCharSet();
230     }
231
232     public IStatePro getToState() {
233       StatePro wrapper = (StatePro)SAutomaton.this.state2wrapper.get(this.transition.getToState());
234       if (wrapper==null)
235         wrapper = new StatePro((AutomatonSet_String.SState)this.transition.getToState());
236       return wrapper;
237     }
238
239     public String JavaDoc toString() {
240       final StringBuffer JavaDoc buffer = new StringBuffer JavaDoc();
241       final AutomatonSet_String.SState fromState = (AutomatonSet_String.SState)this.transition.getFromState();
242       final AutomatonSet_String.SState toState = (AutomatonSet_String.SState)this.transition.getToState();
243
244       if (fromState.isFinal()) buffer.append('[').append(fromState.stateNr).append(']');
245       else buffer.append('(').append(fromState.stateNr).append(')');
246
247       if (this.transition.getCharSet()==null) {
248         if (this.transition.properties==null) buffer.append(" --> ");
249         else buffer.append(" - " ).append(this.transition.properties).append(": -> ");
250       } else {
251         if (this.transition.properties==null) buffer.append(" - ").append(this.transition.getCharSet()).append(" -> ");
252         else buffer.append(" - ").append(this.transition.properties).append(':').append(this.transition.getCharSet()).append(" ->");
253       }
254
255       if (toState.isFinal()) buffer.append('[').append(toState.stateNr).append(']');
256       else buffer.append('(').append(toState.stateNr).append(')');
257
258       return buffer.toString();
259     }
260
261   }
262
263   private final class StateProVisitedListener implements AutomatonSet_String.IStateVisitedListener {
264     private final StatePro statePro;
265
266     public StateProVisitedListener(StatePro statePro) {
267       this.statePro = statePro;
268     }
269
270     public void stateVisited(Automaton.State state) {
271       StatePro wrapper = (StatePro)SAutomaton.this.state2wrapper.get(state);
272       if (wrapper==null) wrapper = new StatePro((AutomatonSet_String.SState)state);
273       
274       final Iterator it = statePro.visitListeners.iterator();
275       for (int i=statePro.visitListeners.size(); i>0; --i) {
276         ((IStatePro.IVisitListener)it.next()).stateVisited(wrapper);
277       }
278     }
279     
280     public void stateVisited(Automaton.State state,char ch) {
281       StatePro wrapper = (StatePro)SAutomaton.this.state2wrapper.get(state);
282       if (wrapper==null) wrapper = new StatePro((AutomatonSet_String.SState)state);
283       
284       final Iterator it = statePro.visitListeners.iterator();
285       for (int i=statePro.visitListeners.size(); i>0; --i) {
286         ((IStatePro.IVisitListener)it.next()).stateVisited(wrapper,ch);
287       }
288     }
289     
290     public void stateUnVisited(Automaton.State state) {
291       StatePro wrapper = (StatePro)SAutomaton.this.state2wrapper.get(state);
292       if (wrapper==null) wrapper = new StatePro((AutomatonSet_String.SState)state);
293       
294       final Iterator it = statePro.visitListeners.iterator();
295       for (int i=statePro.visitListeners.size(); i>0; --i) {
296         ((IStatePro.IVisitListener)it.next()).stateUnVisited(wrapper);
297       }
298     }
299   }
300
301   private final class StateProChangedListener implements AutomatonSet_String.ISStateChangedListener {
302     
303     private final StatePro statePro;
304
305     public StateProChangedListener(StatePro statePro) {
306       this.statePro = statePro;
307     }
308
309     public void transitionAdded(Automaton.State.Transition transition) {
310       Transition wrapper = (Transition)SAutomaton.this.transition2wrapper.get(transition);
311       if (wrapper==null) wrapper = new Transition(transition);
312       
313       final Iterator it = statePro.changeListeners.iterator();
314       for (int i=statePro.changeListeners.size(); i>0; --i) {
315         ((IStatePro.IChangeListener)it.next()).transitionAdded(wrapper);
316       }
317     }
318     
319     public void transitionRemoved(Automaton.State.Transition transition) {
320       Transition wrapper = (Transition)SAutomaton.this.transition2wrapper.get(transition);
321       if (wrapper==null) wrapper = new Transition(transition);
322       final Iterator it = statePro.changeListeners.iterator();
323       for (int i=statePro.changeListeners.size(); i>0; --i) {
324         ((IStatePro.IChangeListener)it.next()).transitionRemoved(wrapper);
325       }
326     }
327     
328     public void isFinalChanged(AutomatonSet_String.SState state, boolean isFinal) {
329       StatePro wrapper = (StatePro)SAutomaton.this.state2wrapper.get(state);
330       if (wrapper==null) wrapper = new StatePro((AutomatonSet_String.SState)state);
331       
332       final Iterator it = statePro.changeListeners.iterator();
333       for (int i=statePro.changeListeners.size(); i>0; --i) {
334         ((IStatePro.IChangeListener)it.next()).isFinalChanged(wrapper,isFinal);
335       }
336     }
337   }
338
339   
340   protected class StatePro implements IStatePro {
341
342     protected final Automaton.IStateVisitedListener stateVisitedListener = new StateProVisitedListener(this);
343
344     protected final Automaton.IStateChangedListener stateChangedListener = new StateProChangedListener(this);
345
346     protected LinkedList visitListeners = null;
347     protected LinkedList changeListeners = null;
348
349     public void addVisitListener(IStatePro.IVisitListener listener) {
350       if (this.visitListeners==null) {
351         this.visitListeners = new LinkedList();
352         this.state.addVisitedListener(this.stateVisitedListener);
353       }
354       this.visitListeners.add(listener);
355     }
356
357     public boolean removeVisitListener(IStatePro.IVisitListener listener) {
358       if (this.visitListeners!=null) {
359         final Iterator it = this.visitListeners.iterator();
360         for (int i=this.visitListeners.size(); i>0; --i) {
361           if (listener==it.next()) {
362             if (this.visitListeners.size()>1) it.remove();
363             else {
364               this.state.removeVisitedListener(this.stateVisitedListener);
365               this.visitListeners = null;
366             }
367             return true;
368           }
369         }
370       }
371       return false;
372     }
373
374     public void addChangeListener(IStatePro.IChangeListener listener) {
375       if (this.changeListeners==null) {
376         this.changeListeners = new LinkedList();
377         this.state.addChangedListener(this.stateChangedListener);
378       }
379       this.changeListeners.add(listener);
380     }
381
382     public boolean removeChangeListener(IStatePro.IChangeListener listener) {
383       if (this.changeListeners!=null) {
384         final Iterator it = this.changeListeners.iterator();
385         for (int i=this.changeListeners.size(); i>0; --i) {
386           if (listener==it.next()) {
387             if (this.changeListeners.size()>1) it.remove();
388             else {
389               this.state.removeChangedListener(this.stateChangedListener);
390               this.changeListeners = null;
391             }
392             return true;
393           }
394         }
395       }
396       return false;
397     }
398
399     protected final AutomatonSet_String.SState state;
400     protected StatePro(AutomatonSet_String.SState state) {
401 if (state==null) throw new Error JavaDoc("state==null");
402       this.state = state;
403       SAutomaton.this.state2wrapper.put(state,this);
404     }
405
406     protected void finalize() {
407       SAutomaton.this.state2wrapper.remove(this.state);
408     }
409
410     protected SAutomaton parent() {
411       return SAutomaton.this;
412     }
413
414     public boolean isFinal() {
415       return this.state.isFinal();
416     }
417
418     public void setFinal(boolean isFinal) {
419       this.state.setFinal(isFinal);
420     }
421
422     public IState visit() {
423       return new State((AutomatonSet_String.ISState)this.state.visit());
424     }
425
426     public IStatePro.ITransition addTransition(ISet_char charSet,IStatePro toState) {
427       final AutomatonSet_String.SState.Transition trans = this.state.addTransition(null,charSet,((StatePro)toState).state);
428       Transition wrapper = (Transition)SAutomaton.this.transition2wrapper.get(trans);
429       if (wrapper==null) wrapper = new Transition(trans);
430       return wrapper;
431     }
432
433     public boolean removeTransition(IStatePro.ITransition transition) {
434       return this.state.removeTransition(((Transition)transition).transition);
435     }
436
437     public void removeAllTransitions() {
438       this.state.removeAllTransitions();
439     }
440
441     public StateProSet getAllReachableStates() {
442       final StateProSet result = new StateProSet();
443       final Automaton.LinkedSet_State states = this.state.getAllReachableStates();
444       for (Automaton.Wrapper_State w = states.elements; w!=null; w=w.next) {
445
446         StatePro wrapper = (StatePro)SAutomaton.this.state2wrapper.get(w.state);
447         if (wrapper==null) wrapper = new StatePro((AutomatonSet_String.SState)w.state);
448         result.add(wrapper);
449       }
450       return result;
451     }
452
453
454     public IStatePro.ITransition[] getTransitions() {
455       final LinkedList list = new LinkedList();
456       for (AutomatonSet_String.State.Transition trans=this.state.transitions; trans!=null; trans=trans.next) {
457         Transition wrapper = (Transition)SAutomaton.this.transition2wrapper.get(trans);
458         if (wrapper==null) wrapper = new Transition(trans);
459 // list.add(wrapper);
460
list.addFirst(wrapper);
461       }
462       return (IStatePro.ITransition[])list.toArray(new IStatePro.ITransition[list.size()]);
463     }
464
465     public IStatePro.ITransition[] getETransitions() {
466       final LinkedList list = new LinkedList();
467       for (AutomatonSet_String.State.Transition trans=this.state.eTransitions; trans!=null; trans=trans.next) {
468         Transition wrapper = (Transition)SAutomaton.this.transition2wrapper.get(trans);
469         if (wrapper==null) wrapper = new Transition(trans);
470 // list.add(wrapper);
471
list.addFirst(wrapper);
472       }
473       return (IStatePro.ITransition[])list.toArray(new IStatePro.ITransition[list.size()]);
474     }
475
476     /**
477      * returns all transitions (normal and epsilon transitions) of this state.
478      * the result array contains first all epsilon transitions and then all normal transitions
479      */

480     public IStatePro.ITransition[] getAllTransitions() {
481       final LinkedList list = new LinkedList();
482       for (AutomatonSet_String.State.Transition trans=this.state.transitions; trans!=null; trans=trans.next) {
483         Transition wrapper = (Transition)SAutomaton.this.transition2wrapper.get(trans);
484         if (wrapper==null) wrapper = new Transition(trans);
485 // list.add(wrapper);
486
list.addFirst(wrapper);
487       }
488       for (AutomatonSet_String.State.Transition trans=this.state.eTransitions; trans!=null; trans=trans.next) {
489         Transition wrapper = (Transition)SAutomaton.this.transition2wrapper.get(trans);
490         if (wrapper==null) wrapper = new Transition(trans);
491 // list.add(wrapper);
492
list.addFirst(wrapper);
493       }
494       return (IStatePro.ITransition[])list.toArray(new IStatePro.ITransition[list.size()]);
495     }
496
497     public int getStateNumber() {
498       return this.state.stateNr;
499     }
500
501     public String JavaDoc toString() {
502       if (this.isFinal()) return "["+this.state.stateNr+"]";
503       return "("+this.state.stateNr+")";
504     }
505
506   }
507
508   // should be IdentityMap
509
protected transient HashMap state2wrapper = null;
510   protected transient HashMap transition2wrapper = null;
511
512   protected transient Automaton.IChangedListener automatonChangedListener = null;
513
514   protected Automaton.IChangedListener getAutomatonChangedListener() {
515     if (this.automatonChangedListener!=null) return this.automatonChangedListener;
516
517     this.automatonChangedListener = new SAutomatonChangeListener();
518
519     return this.automatonChangedListener;
520   }
521
522   protected transient LinkedList listeners = null;
523
524   /**
525    * Adds the specified listener to receive change events from this automaton.
526    * The listener will be registered as listener in any case, even if it has been registered yet.
527    * If a listener instance is added two times, it will receive events twice.
528    * important: don't forget to remove the listener, if you don't need it any longer but still have the automaton in use.
529    * Otherwise your listener won't be carbage collected (because it is registered with this automaton)
530    * and still will receive events.
531    */

532   public void addChangeListener(SAutomaton.IChangeListener listener) {
533     if (this.listeners==null) {
534       this.listeners = new LinkedList();
535       ((AutomatonSet_String)this.automaton).addChangedListener(this.getAutomatonChangedListener());
536     }
537     this.listeners.add(listener);
538   }
539
540   /**
541    * Removes the specified listener so that it no longer receives change events from this automaton.
542    * If the listener instance is registered more than ones, only one instance will be removed.
543    * @param listener
544    * @throw IllegalArgumentException - if null is passed as listener
545    * @return true if the listener was registered else false
546    */

547   public boolean removeChangeListener(SAutomaton.IChangeListener listener) {
548     if (this.listeners!=null) {
549       final Iterator it = this.listeners.iterator();
550       for (int i=this.listeners.size(); i>0; --i) {
551         if (listener==it.next()) {
552           if (this.listeners.size()>1) it.remove();
553           else {
554             this.automaton.removeChangedListener(this.automatonChangedListener);
555             this.automatonChangedListener = null;
556             this.listeners = null;
557           }
558           return true;
559         }
560       }
561     }
562     return false;
563   }
564
565
566
567
568   protected transient AutomatonSet_String automaton;
569
570   /**
571    * Creates a new empty automaton
572    */

573   public SAutomaton() {
574     this(new AutomatonSet_String());
575   }
576
577   public SAutomaton(FSAData data) {
578     this(new AutomatonSet_String());
579     this.init(data);
580   }
581
582   protected static FSAData toFSAData(Object JavaDoc obj) {
583     if (obj.getClass()!=FSAData.class) {
584       SAutomatonData data = (SAutomatonData)obj;
585
586       FSAData.State[] newStates = new FSAData.State[data.states==null ? 0 : data.states.length];
587       for (int i=0; i<newStates.length; ++i) {
588         SAutomatonData.State state = data.states[i];
589         if (state!=null) {
590           FSAData.State.Transition[] newTransitions =
591             new FSAData.State.Transition[state.transitions==null ? 0 : state.transitions.length];
592           for (int t=0; t<newTransitions.length; ++t) {
593             SAutomatonData.State.Transition trans = state.transitions[t];
594             newTransitions[t] = new FSAData.State.Transition(trans.properties,trans.charSet,trans.toStateNumber);
595           }
596           newStates[i] = new FSAData.State(state.number,state.isFinal,newTransitions,state.transitionsAreDeterministic);
597         }
598       }
599       return new FSAData(newStates,data.startStateNumber,data.isDeterministic);
600
601     } else {
602       FSAData data = (FSAData)obj;
603       switch(data.objectVersion) {
604         case FSAData.classVersion : return data;
605         default : return data;
606       }
607     }
608   }
609
610   public SAutomaton(InputStream automatonDataStream) throws IOException, ClassNotFoundException JavaDoc {
611     this(new AutomatonSet_String());
612 // this.init((FSAData)automatonDataStream.readObject());
613
this.init(toFSAData(new ObjectInputStream(automatonDataStream).readObject()));
614   }
615
616   protected SAutomaton(AutomatonSet_String automaton) {
617     this.automaton = automaton;
618     this.state2wrapper = new HashMap();
619     this.transition2wrapper = new HashMap();
620   }
621
622   public boolean isDeterministic() {
623     return this.automaton.isDeterministic();
624   }
625
626   /**
627    * Returns the current start state of the automaton.
628    * important: The result is null, if and only if the current start state is null
629    * @return the current start state of the automaton
630    */

631   public IStatePro getStartState() {
632     Automaton.State startState = ((AutomatonSet_String)this.automaton).getStartState();
633     if (startState==null) return null;
634
635     StatePro wrapper = (StatePro)this.state2wrapper.get(startState);
636     if (wrapper==null)
637       wrapper = new StatePro((AutomatonSet_String.SState)startState);
638     return wrapper;
639   }
640
641
642   /**
643    * Sets the automaton's start state to the specified state.
644    * If the automaton should have no start state pass null.
645    * <br>important: the specified state must be a state of this automaton which means
646    * <br>a) the state must have been created via the addState() method of this automaton
647    * <br>b) the state must not have been removed from this automaton via the removeState method
648    * @param state
649    */

650   public void setStartState(IStatePro state) {
651     if ((state instanceof StatePro)==false) throw new IllegalArgumentException JavaDoc("state is no state of mine");
652
653     final StatePro wrapper = (StatePro)state;
654     if (wrapper.parent()!=this) throw new IllegalArgumentException JavaDoc("state is no state of mine");
655
656     this.automaton.setStartState(wrapper.state);
657   }
658
659   /**
660    * Adds a new non final state to this automaton.
661    * @return a new state
662    */

663   public IStatePro addState() {
664     return this.addState(false);
665   }
666
667   /**
668    * Adds a new final or non final state to this automaton.
669    * @return a new state
670    */

671   public IStatePro addState(boolean isFinal) {
672     final AutomatonSet_String.SState newState = this.automaton.addState(isFinal);
673     StatePro wrapper = (StatePro)SAutomaton.this.state2wrapper.get(newState);
674     if (wrapper==null) wrapper = new StatePro((AutomatonSet_String.SState)newState);
675     return wrapper;
676   }
677
678   /**
679    * Removes the specified state from this automaton.
680    * <br>First all transitions pointing to state are removed and then the state itself.
681    * <br>If state is this automaton's start state then first of all this automaton's start state is set to null.
682    * <br>important: the specified state must have been created via the addState method of this automaton
683    * otherwise an IllegalArgumentException is thrown.
684    * @param state
685    * @return true if this automaton owns the specified state else false
686    */

687   public boolean removeState(IStatePro state) {
688     if ((state instanceof StatePro)==false) throw new IllegalArgumentException JavaDoc("state is no state of mine");
689
690     final StatePro wrapper = (StatePro)state;
691     if (wrapper.parent()!=this) throw new IllegalArgumentException JavaDoc("state is no state of mine");
692     return this.automaton.removeState(wrapper.state);
693   }
694
695   /**
696    * Removes all states of this automaton.
697    */

698   public void clear() {
699     this.automaton.clear();
700   }
701
702   /**
703    * Minimizes this automaton as much as possible.
704    * The resulting automaton has as less states as possible.
705    * <br>important: the current implementation removes all properties from all transitions
706    */

707   public void minimize() {
708     this.automaton.minimize();
709   }
710
711   /**
712    * Returns all states of this automaton whatever they are reachable through the current start state or not.
713    * @return
714    */

715   public StateProSet getStates() {
716     final StateProSet result = new StateProSet();
717     final Automaton.LinkedSet_State states = this.automaton.getStates();
718     for (Automaton.Wrapper_State w = states.elements; w!=null; w=w.next) {
719       StatePro wrapper = (StatePro)SAutomaton.this.state2wrapper.get(w.state);
720       if (wrapper==null) wrapper = new StatePro((AutomatonSet_String.SState)w.state);
721       result.add(wrapper);
722     }
723     return result;
724   }
725
726   public void complement() {
727     this.automaton.complement();
728   }
729
730   public void addAll(SAutomaton automaton) {
731     this.automaton.addAll(automaton.automaton);
732   }
733
734   public void retainAll(SAutomaton automaton) {
735     this.automaton.retainAll(automaton.automaton);
736   }
737
738   public void removeAll(SAutomaton automaton) {
739     this.automaton.removeAll(automaton.automaton);
740   }
741
742   public String JavaDoc toString() {
743     return this.automaton.toString();
744   }
745
746   private String JavaDoc getCharSet(ISet_char charSet) {
747     if (charSet==null) return null;
748     final StringBuffer JavaDoc buffer = new StringBuffer JavaDoc(charSet.size());
749     ISet_char.Iterator it_charSet = charSet.iterator();
750     for (int i=charSet.size(); i>0; --i) buffer.append(it_charSet.next());
751
752     ISet_char cs = new CharSet(buffer.toString());
753     if (cs.equals(charSet)==false)
754       throw new Error JavaDoc(""+charSet+" "+cs);
755
756     return buffer.toString();
757   }
758
759   public FSAData toData() {
760     Automaton.LinkedSet_State xxx = this.automaton.getStates();
761     AutomatonSet_String.SState[] states = new AutomatonSet_String.SState[xxx.size()];
762     int x=0;
763     for (Automaton.Wrapper_State w=xxx.elements; w!=null; w=w.next,++x) {
764       states[x] = (AutomatonSet_String.SState)w.state;
765     }
766
767     FSAData.State[] data_states = new FSAData.State[states.length];
768     for (int i=0; i<states.length; ++i) {
769       LinkedList data_transitions = new LinkedList();
770       for (Automaton.State.Transition trans=states[i].transitions; trans!=null; trans=trans.next) {
771 // int toStateNr = 0; while (states[toStateNr]!=trans.toState) ++toStateNr;
772
data_transitions.addFirst(
773           new FSAData.State.Transition(
774             trans.properties,
775             this.getCharSet(trans.charSet)
776 // ,toStateNr
777
,trans.toState.stateNr
778           )
779         );
780       }
781       for (Automaton.State.Transition trans=states[i].eTransitions; trans!=null; trans=trans.next) {
782 // int toStateNr = 0; while (states[toStateNr]!=trans.toState) ++toStateNr;
783
data_transitions.addFirst(
784 // new SAutomatonData.State.Transition(trans.properties,null,toStateNr)
785
new FSAData.State.Transition(trans.properties,null,trans.toState.stateNr)
786         );
787       }
788
789       FSAData.State.Transition[] transitions =
790         (FSAData.State.Transition[])data_transitions.toArray(
791           new FSAData.State.Transition[data_transitions.size()]
792         );
793
794 // data_states[i] = new SAutomatonData.State(i,states[i].isFinal,transitions,states[i].isDeterministic());
795
data_states[i] = new FSAData.State(states[i].stateNr,states[i].isFinal,transitions,states[i].isDeterministic());
796     }
797
798     final Automaton.State startState = this.automaton.getStartState();
799     if (startState==null) return new FSAData(data_states,null,this.automaton.isDeterministic());
800
801 // int startStateNr = 0; while (states[startStateNr]!=startState) ++startStateNr;
802

803     FSAData result = new FSAData(data_states,new Integer JavaDoc(startState.stateNr),this.automaton.isDeterministic());
804
805     return result;
806   }
807
808   protected void init(FSAData a) {
809 // this.automatonChangedListener = null;
810
// this.state2wrapper = new HashMap();
811
// this.transition2wrapper = new HashMap();
812
// this.automaton = this.newAutomaton();
813

814     final HashMap map = new HashMap();
815
816     if (a.states!=null) {
817       for (int i=0; i<a.states.length; ++i) {
818         Integer JavaDoc stateNr = new Integer JavaDoc(a.states[i].number);
819         if (map.containsKey(stateNr))
820           throw new IllegalArgumentException JavaDoc("bad automatonData: state with number "+stateNr+" does already exists");
821
822         AutomatonSet_String.SState state =
823           this.automaton.addState(a.states[i].isFinal,a.states[i].number);
824
825         map.put(stateNr,state);
826       }
827
828       for (int i=0; i<a.states.length; ++i) {
829         FSAData.State stateData = a.states[i];
830
831         AutomatonSet_String.SState state =
832           (AutomatonSet_String.SState)map.get(new Integer JavaDoc(stateData.number));
833
834         if (stateData.transitions!=null) {
835           for (int t=0; t<stateData.transitions.length; ++t) {
836             FSAData.State.Transition transData = stateData.transitions[t];
837
838             CharSet charSet = (transData.charSet==null) ? null : new CharSet(transData.charSet);
839
840             AutomatonSet_String.SState toState =
841               (AutomatonSet_String.SState)map.get(new Integer JavaDoc(transData.toStateNumber));
842
843             state.addTransition(transData.properties,charSet,toState);
844           }
845         }
846
847         state.setDeterministic(stateData.transitionsAreDeterministic);
848       }
849     }
850
851     if (a.startStateNumber!=null) {
852       AutomatonSet_String.SState startState =
853         (AutomatonSet_String.SState)map.get(a.startStateNumber);
854
855       if (startState==null)
856         throw new IllegalArgumentException JavaDoc("bad automatonData: startState "+a.startStateNumber+" does not exists");
857
858       this.automaton.setStartState(startState);
859     }
860
861     this.automaton.setDeterministic(
862       a.isDeterministic
863     );
864   }
865
866   public void toData(OutputStream automatonDataStream) throws IOException {
867     new ObjectOutputStream(automatonDataStream).writeObject(this.toData());
868   }
869
870
871
872 }
Popular Tags