1 / 76

Automated Extraction of Transition Systems from Component-model Architectures

Automated Extraction of Transition Systems from Component-model Architectures. Matt Hoosier. SAnToS Laboratory, Kansas State University, USA. http://cadena.projects.cis.ksu.edu. Overview. Distributed mission-critical software is starting a trend toward component-based middleware

valiant
Download Presentation

Automated Extraction of Transition Systems from Component-model Architectures

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Automated Extraction of Transition Systems from Component-model Architectures Matt Hoosier SAnToS Laboratory, Kansas State University, USA http://cadena.projects.cis.ksu.edu

  2. Overview • Distributed mission-critical software is starting a trend toward component-based middleware • Some initial tools (one from KSU) have come along to help the design of such distributed real-time event-driven (DRE) software • I describe the work to automate model checker verification (more realistically, “bug finding”) of these mission-critical applications Extracting Transition Systems from Component Models

  3. Outline • Component architectures • Cadena design and analysis tool for component architectures • Bogor model checking framework • Model checking Cadena projects • High-level approaches • Translation strategies • Evaluation vs. manually constructed models • Future work Extracting Transition Systems from Component Models

  4. Component Organization A software component is a unit of composition with contractually specified interfaces and explicit context dependencies only. A software component can be deployed independently and is subject to composition by third parties. Szyperski, Component Software Extracting Transition Systems from Component Models

  5. Component Organization All communication with outside is through typed “ports” • Interface ports • Aggregation of operations on an object • Synchronous semantics just like any other OO method call • Event ports • Notification messages • Asynchronous semantics (“fire and forget”) Extracting Transition Systems from Component Models

  6. Component Organization “Receptacle” “Facet” Required interface Provided interface Interface ports All communication with outside is through typed “ports” • Interface ports • Aggregation of operations on an object • Synchronous semantics just like any other OO method call • Event ports • Notification messages • Asynchronous semantics (“fire and forget”) Extracting Transition Systems from Component Models

  7. Component Organization Publisher Subscriber Event ports “Source” “Sink” All communication with outside is through typed “ports” • Interface ports • Aggregation of operations on an object • Synchronous semantics just like any other OO method call • Event ports • Notification messages • Asynchronous semantics (“fire and forget”) Extracting Transition Systems from Component Models

  8. Embedded Components • Real-time distributed component model very similar to the CORBA Component Model • Computation driven by a set of regular system interrupts (timeouts) • All components are passive; a threadpool with event-dispatching threads provides all the CPU time. Boeing’s Prism Avionics Middleware Extracting Transition Systems from Component Models

  9. Prism Development Methodologies • Little abstract design • Natural language requirements often used directly to inspire C++ code • UML is often relegated to documentation, when kept in sync • Engineers want to reason about high-level “mode” transitions • Overall long-run control flow is hard to analyze manually • Formal verification tools would be useful here. • Open Experimental Program was established to solicit new tools to help in the design process. One was developed at KSU… Extracting Transition Systems from Component Models

  10. Cadena Cadena CCM Interface Definition Language Java/C++ Component Code Product Line Customizations Model Checking State Transitions System Configuration <CONFIGURATION_PASS> <HOME> <…> <COMPONENT> <ID> <…></ID> <EVENT_SUPPLIER> <…events this component supplies…> </EVENT_SUPPLIER> </COMPONENT> </HOME> </CONFIGURATION_PASS> High-level Specification Language Eclipse Plug-In Prism XML Configurator Info Integrated Development Environment Analysis and QoS Aspect Synthesis Extracting Transition Systems from Component Models

  11. Behavioral Specification The component is the unit of specification, so we’ll examine one of the more interesting ones. Extracting Transition Systems from Component Models

  12. Behavioral Specification • componentBMModal { • providesChangeModemodeChange; • providesReadDatadataOut; • usesReadDatadataIn; • publishesDataAvailableoutDataAvailable; • consumesDataAvailableinDataAvailable; • modebmModalModeofcommon.OnOffMode • initcommon.OnOffMode.enabled; • behavior { • stringbuf; • handleinDataAvailable(DataAvailablee) { • casebmModalModeof { • common.OnOffMode.enabled: • buf := dataIn.data; • pushnewDataAvailable {} onoutDataAvailable; • common.OnOffMode.disabled: • } • } • … • } • }; Extracting Transition Systems from Component Models

  13. Structure Specification • componentBMModal { • providesChangeModemodeChange; • providesReadDatadataOut; • usesReadDatadataIn; • publishesDataAvailableoutDataAvailable; • consumesDataAvailableinDataAvailable; • modebmModalModeofcommon.OnOffMode • initcommon.OnOffMode.enabled; • behavior { • stringbuf; • handleinDataAvailable(DataAvailablee) { • casebmModalModeof { • common.OnOffMode.enabled: • buf := dataIn.data; • pushnewDataAvailable {} onoutDataAvailable; • common.OnOffMode.disabled: • } • } • … • } • }; CORBA Interface Definition Language (IDL): Structural Definitions Extracting Transition Systems from Component Models

  14. Structure: Event Sources • componentBMModal { • providesChangeModemodeChange; • providesReadDatadataOut; • usesReadDatadataIn; • publishesDataAvailableoutDataAvailable; • consumesDataAvailableinDataAvailable; • modebmModalModeofcommon.OnOffMode • initcommon.OnOffMode.enabled; • behavior { • stringbuf; • handleinDataAvailable(DataAvailablee) { • casebmModalModeof { • common.OnOffMode.enabled: • buf := dataIn.data; • pushnewDataAvailable {} onoutDataAvailable; • common.OnOffMode.disabled: • } • } • … • } • }; Event source port Extracting Transition Systems from Component Models

  15. Structure: Event Sinks • componentBMModal { • providesChangeModemodeChange; • providesReadDatadataOut; • usesReadDatadataIn; • publishesDataAvailableoutDataAvailable; • consumesDataAvailableinDataAvailable; • modebmModalModeofcommon.OnOffMode • initcommon.OnOffMode.enabled; • behavior { • stringbuf; • handleinDataAvailable(DataAvailablee) { • casebmModalModeof { • common.OnOffMode.enabled: • buf := dataIn.data; • pushnewDataAvailable {} onoutDataAvailable; • common.OnOffMode.disabled: • } • } • … • } • }; Event sink port Extracting Transition Systems from Component Models

  16. Structure: Interface Consumers • componentBMModal { • providesChangeModemodeChange; • providesReadDatadataOut; • usesReadDatadataIn; • publishesDataAvailableoutDataAvailable; • consumesDataAvailableinDataAvailable; • modebmModalModeofcommon.OnOffMode • initcommon.OnOffMode.enabled; • behavior { • stringbuf; • handleinDataAvailable(DataAvailablee) { • casebmModalModeof { • common.OnOffMode.enabled: • buf := dataIn.data; • pushnewDataAvailable {} onoutDataAvailable; • common.OnOffMode.disabled: • } • } • … • } • }; Remote interface client Extracting Transition Systems from Component Models

  17. Structure: Interface Providers • componentBMModal { • providesChangeModemodeChange; • providesReadDatadataOut; • usesReadDatadataIn; • publishesDataAvailableoutDataAvailable; • consumesDataAvailableinDataAvailable; • modebmModalModeofcommon.OnOffMode • initcommon.OnOffMode.enabled; • behavior { • stringbuf; • handleinDataAvailable(DataAvailablee) { • casebmModalModeof { • common.OnOffMode.enabled: • buf := dataIn.data; • pushnewDataAvailable {} onoutDataAvailable; • common.OnOffMode.disabled: • } • } • … • } • }; Interfaces accessible to others remotely (servers) Extracting Transition Systems from Component Models

  18. Behavioral Specification Cadena Component Property Specification (CPS) • componentBMModal { • providesChangeModemodeChange; • providesReadDatadataOut; • usesReadDatadataIn; • publishesDataAvailableoutDataAvailable; • consumesDataAvailableinDataAvailable; • modebmModalModeofcommon.OnOffMode • initcommon.OnOffMode.enabled; • behavior { • stringbuf; • handleinDataAvailable(DataAvailablee) { • casebmModalModeof { • common.OnOffMode.enabled: • buf := dataIn.data; • pushnewDataAvailable {} onoutDataAvailable; • common.OnOffMode.disabled: • } • } • … • } • }; Extracting Transition Systems from Component Models

  19. Behavior: Mode Variables enum OnOffMode {enabled, disabled}; Small, bounded domains • componentBMModal { • providesChangeModemodeChange; • providesReadDatadataOut; • usesReadDatadataIn; • publishesDataAvailableoutDataAvailable; • consumesDataAvailableinDataAvailable; • modebmModalModeofcommon.OnOffMode • initcommon.OnOffMode.enabled; • behavior { • stringbuf; • handleinDataAvailable(DataAvailablee) { • casebmModalModeof { • common.OnOffMode.enabled: • buf := dataIn.data; • pushnewDataAvailable {} onoutDataAvailable; • common.OnOffMode.disabled: • } • } • … • } • }; Behavior-control variables Like finite state control in an automaton Extracting Transition Systems from Component Models

  20. Behavior: Handler Methods The event itself. Can carry payload (not used here). • componentBMModal { • providesChangeModemodeChange; • providesReadDatadataOut; • usesReadDatadataIn; • publishesDataAvailableoutDataAvailable; • consumesDataAvailableinDataAvailable; • modebmModalModeofcommon.OnOffMode • initcommon.OnOffMode.enabled; • behavior { • stringbuf; • handleinDataAvailable(DataAvailablee) { • casebmModalModeof { • common.OnOffMode.enabled: • buf := dataIn.data; • pushnewDataAvailable {} onoutDataAvailable; • common.OnOffMode.disabled: • } • } • … • } • }; Handler method for event sink Extracting Transition Systems from Component Models

  21. Behavior: Modal Control I/O Port Dependencies Differ • componentBMModal { • providesChangeModemodeChange; • providesReadDatadataOut; • usesReadDatadataIn; • publishesDataAvailableoutDataAvailable; • consumesDataAvailableinDataAvailable; • modebmModalModeofcommon.OnOffMode • initcommon.OnOffMode.enabled; • behavior { • stringbuf; • handleinDataAvailable(DataAvailablee) { • casebmModalModeof { • common.OnOffMode.enabled: • buf := dataIn.data; • pushnewDataAvailable {} onoutDataAvailable; • common.OnOffMode.disabled: • } • } • … • } • }; Modal Control Flow Extracting Transition Systems from Component Models

  22. Behavior: Dataflow • componentBMModal { • providesChangeModemodeChange; • providesReadDatadataOut; • usesReadDatadataIn; • publishesDataAvailableoutDataAvailable; • consumesDataAvailableinDataAvailable; • modebmModalModeofcommon.OnOffMode • initcommon.OnOffMode.enabled; • behavior { • stringbuf; • handleinDataAvailable(DataAvailablee) { • casebmModalModeof { • common.OnOffMode.enabled: • buf := dataIn.data; • pushnewDataAvailable {} onoutDataAvailable; • common.OnOffMode.disabled: • } • } • … • } • }; Tracks inflow/outflow of values, but not computation Extracting Transition Systems from Component Models

  23. Behavior: Event Propagation • componentBMModal { • providesChangeModemodeChange; • providesReadDatadataOut; • usesReadDatadataIn; • publishesDataAvailableoutDataAvailable; • consumesDataAvailableinDataAvailable; • modebmModalModeofcommon.OnOffMode • initcommon.OnOffMode.enabled; • behavior { • stringbuf; • handleinDataAvailable(DataAvailablee) { • casebmModalModeof { • common.OnOffMode.enabled: • buf := dataIn.data; • pushnewDataAvailable {} onoutDataAvailable; • common.OnOffMode.disabled: • } • } • … • } • }; Emit event through source port Extracting Transition Systems from Component Models

  24. Event Correlation … + An A3 A2 A1 • Something introduced in Cadena to allow detection and reaction to complex patterns of events • Reduce network bandwidth • Keep components simple B Extracting Transition Systems from Component Models

  25. Event Correlation: Example When a component only cares if each of two others has new data Correlator becomes a bona fide type: And Two event sink ports, and one (implicit) event source port DataAvailablecorrelation And ( DataAvailable e1, DataAvailable e2) e1 + e2 { case true: push new DataAvailable {}; } Extracting Transition Systems from Component Models

  26. Prism Middleware Implementation Each middleware has its own method of achieving the abstraction of inter-component connections. Taken from “A Correlation Framework for the CORBA Component Model” [FASE ’04] Extracting Transition Systems from Component Models

  27. Prism Middleware Implementation Abstractly… consume produce Taken from “A Correlation Framework for the CORBA Component Model” [FASE ’04] Extracting Transition Systems from Component Models

  28. Prism Middleware Implementation Proxy Supplier … … … … … Event channel In reality… proxy dispatch consume threading timer/ thread pool queuing filtering network multiplexing produce consumer references Proxy Consumer proxy Taken from “A Correlation Framework for the CORBA Component Model” [FASE ’04] Extracting Transition Systems from Component Models

  29. My Contributions • Implement front end of CPS language • Lexing, Parsing, Semantic Checking [with Jung, Greenwald] • Implement event correlation language • Front end again • Simulated implementation (re-used in model checking backend) • Automate the creation of checkable models from Cadena specification artifacts • Compiler from CPS  Bogor input language • Generate OO structures to mimic component layout • Map CADL configuration  Bogor input language API calls to initialize “embedded system” Extracting Transition Systems from Component Models

  30. On the model checker used… Before diving into details about the translation, we give some general information about the model checker used. Extracting Transition Systems from Component Models

  31. Bogor Model Checker Front-end Model Checking Components Lexer IStateMgr IActionTaker IBacktrackIF .bir Parser ISearcher IExpEvaluator ITransformer Type Checking IStateFactory IValueFactory ISchedulingStg .config Semantic Analyses • Developed at Kansas State University [Robby] • Actually, a framework with swappable modules • … as opposed to SPIN Verified Counter Example Extracting Transition Systems from Component Models

  32. Bogor Modeling Language:BIR BIR = Bandera Intermediate Representation • Used as the intermediate language for the Bandera Tool Set for model-checking Java programs • Guarded command language • when <condition> do <command> • Native support for a variety of object-oriented language features • dynamically created objects and threads, exceptions, methods, inheritance, etc. Extracting Transition Systems from Component Models

  33. BIR Example:2 Dining Philosophers right left right left Taken from the Bogor Tutorial [ETAPS ’04] Extracting Transition Systems from Component Models

  34. BIR Example:2 Dining Philosophers systemTwoDiningPhilosophers { recordFork { booleanisHeld; } mainthreadMAIN() { Forkfork1; Forkfork2; locloc0: do { // create forks fork1 := newFork; fork2 := newFork; // start philosophers startPhil(fork1, fork2); startPhil(fork2, fork1); } return; } threadPhil(Forkleft, Forkright) { locloc0: // take left fork when !left.isHelddo { left.isHeld := true; } gotoloc1; locloc1: // take right fork when !right.isHelddo { right.isHeld := true; } gotoloc2; locloc2: // put right fork do { right.isHeld := false; } gotoloc3; locloc3: // put left fork do { left.isHeld := false; } gotoloc0; } } Extracting Transition Systems from Component Models

  35. BIR Example:2 Dining Philosophers Uses a record to model forks systemTwoDiningPhilosophers { recordFork { booleanisHeld; } mainthreadMAIN() { Forkfork1; Forkfork2; locloc0: do { // create forks fork1 := newFork; fork2 := newFork; // start philosophers startPhil(fork1, fork2); startPhil(fork2, fork1); } return; } threadPhil(Forkleft, Forkright) { locloc0: // take left fork when !left.isHelddo { left.isHeld := true; } gotoloc1; locloc1: // take right fork when !right.isHelddo { right.isHeld := true; } gotoloc2; locloc2: // put right fork do { right.isHeld := false; } gotoloc3; locloc3: // put left fork do { left.isHeld := false; } gotoloc0; } } Extracting Transition Systems from Component Models

  36. BIR Example:2 Dining Philosophers Thread declarations systemTwoDiningPhilosophers { recordFork { booleanisHeld; } mainthreadMAIN() { Forkfork1; Forkfork2; locloc0: do { // create forks fork1 := newFork; fork2 := newFork; // start philosophers startPhil(fork1, fork2); startPhil(fork2, fork1); } return; } threadPhil(Forkleft, Forkright) { locloc0: // take left fork when !left.isHelddo { left.isHeld := true; } gotoloc1; locloc1: // take right fork when !right.isHelddo { right.isHeld := true; } gotoloc2; locloc2: // put right fork do { right.isHeld := false; } gotoloc3; locloc3: // put left fork do { left.isHeld := false; } gotoloc0; } } Extracting Transition Systems from Component Models

  37. BIR Example:2 Dining Philosophers threadPhil(Forkleft, Forkright) { locloc0: // take left fork when !left.isHelddo { left.isHeld := true; } gotoloc1; locloc1: // take right fork when !right.isHelddo { right.isHeld := true; } gotoloc2; locloc2: // put right fork do { right.isHeld := false; } gotoloc3; locloc3: // put left fork do { left.isHeld := false; } gotoloc0; } } Local variable declarations systemTwoDiningPhilosophers { recordFork { booleanisHeld; } mainthreadMAIN() { Forkfork1; Forkfork2; locloc0: do { // create forks fork1 := newFork; fork2 := newFork; // start philosophers startPhil(fork1, fork2); startPhil(fork2, fork1); } return; } Extracting Transition Systems from Component Models

  38. BIR Example:2 Dining Philosophers threadPhil(Forkleft, Forkright) { locloc0: // take left fork when !left.isHelddo { left.isHeld := true; } gotoloc1; locloc1: // take right fork when !right.isHelddo { right.isHeld := true; } gotoloc2; locloc2: // put right fork do { right.isHeld := false; } gotoloc3; locloc3: // put left fork do { left.isHeld := false; } gotoloc0; } } Control locations systemTwoDiningPhilosophers { recordFork { booleanisHeld; } mainthreadMAIN() { Forkfork1; Forkfork2; locloc0: do { // create forks fork1 := newFork; fork2 := newFork; // start philosophers startPhil(fork1, fork2); startPhil(fork2, fork1); } return; } Extracting Transition Systems from Component Models

  39. BIR Example:2 Dining Philosophers When condition is true Execute these statement(s) atomically Trivially true guards …aka “guarded transitions”, “guarded commands” Guarded transformations threadPhil(Forkleft, Forkright) { locloc0: // take left fork when !left.isHelddo { left.isHeld := true; } gotoloc1; locloc1: // take right fork when !right.isHelddo { right.isHeld := true; } gotoloc2; locloc2: // put right fork do { right.isHeld := false; } gotoloc3; locloc3: // put left fork do { left.isHeld := false; } gotoloc0; } } Extracting Transition Systems from Component Models

  40. Modeling Approach • Use Bogor model checker • Extend Bogor input language with primitives specific to DRE software • Build translator to map CPS specifications into Bogor input language constructs • Exploit knowledge of runtime scheduling policies to reduce interleavings • Integrate whole thing into Cadena for instant model checking Extracting Transition Systems from Component Models

  41. Publish/Subscribe Primitives Add abstract types (like channels in SPIN) extensionCADforSystemModule { // declaration of abstract types typedefEvent; typedefComponent; // constructors expdefCAD.Component createComponent(string); expdefCAD.EventcreateEvent<'a>('a); // manipulation of subscriber lists actiondefaddSubscriberList(CAD.Component, string); actiondefaddSubscriber<'a>(CAD.Component, string, 'a); expdef'a[] getSubscribers<'a>(CAD.Component, string); } recordSubscriber { EventHandlerTypehandlerFunction; stringportName; } functionfireEventFromComponent( CAD.ComponentsourceComp, stringport, CAD.Eventevent) {} Populate/query subscriber lists } Unit of subscribership } Event multiplexing and queuing Extracting Transition Systems from Component Models

  42. Publish/Subscribe Primitives: Event Correlators extensionCorrelatorforCorrelatorModule { // abstract type for correlator; encapsulates acceptor automaton typedeftype; // Constructor: builds complete automaton from spec. string expdefCorrelator.typecreate(string); // Handle incoming event and dump a newly allocated ‘evtType // into the list for each compound event triggered actiondefhandleEvent<'evtType>( Correlator.type, string, List.type<'evtType>); // subscriber list maintenance actiondefaddSubscriber<'a>(Correlator.type, 'a); expdef'a[] getSubscribers<'a>(Correlator.type); } // allow correlators to be consumers of component events recordCorrelatorSubscriberextendsSubscriber { … } // analagous to event multiplexing and queuing from components functionfireEventFromCorrelator(Correlator.typecor, CAD.Evente) { … } Extracting Transition Systems from Component Models

  43. Interface Port Primitives extensionCADforSystemModule { // abstract type for provided (server) port typedefPort; // constructors expdefCAD.PortcreatePort(); // attach server ports to components actiondefregisterPort(CAD.Component, CAD.Port, string); expdefCAD.PortgetPort(CAD.Component, string); // put BIR function pseudo-references into ports (for named methods) actiondefsetPortMethodHandler<'a>(CAD.Port, string, 'a); expdef'agetPortMethodHandler<'a>(CAD.Port, string); // make client <-> server connections actiondefconnectPorts( Pair.type<CAD.Component, string>, Pair.type<CAD.Component, string> ); expdefPair.type<CAD.Component, string> getProvider( Pair.type<CAD.Component, string>); } Extracting Transition Systems from Component Models

  44. Using the primitives function{|common.BMDevice.dataOut.data<get>()|}(…) returnsstring { … } CAD.ComponentGPS CAD.ComponentAirFrame server ports client port connections CAD.Port methods Extracting Transition Systems from Component Models

  45. Why BIR Extensions? • Avoid slowdown of interpreting “uninteresting” procedures in BIR. • Only relevant parts of configuration go into state vector (sometimes none). • Atomicity of actiondef operations means no intermediate states to be stored. Extension API’s based loosely on work presented in “Model Checking Middleware-based Event-driven Real-time Embedded Software” [FMCO ’02] Extracting Transition Systems from Component Models

  46. Remote Method Indirection • When a client calls a method on some receptacle interface, this must be mapped to the correct BIR function for the facet on the end of the connection • E.g, dataOut.data<get> is implemented by two completely separate functions on BMDevice and BMClosedED components • Client must know which to call! Extracting Transition Systems from Component Models

  47. Remote Method Indirection Solution: • Require all facet methods that implement a particular interface method (ReadData.data<get>) to be enumerated as a BIR virtual function • Wrap client receptacle call in BIR function that looks up remote method host component and function name (prev. slide), then do BIR invoke virtual • Example (next slide)… Extracting Transition Systems from Component Models

  48. Remote Method Indirection enum{|common.ReadData.data<get>()|} { {|common.BMClosedED.dataOut.data<get>()|}, {|common.BMDevice.dataOut.data<get>()|} } virtual{|common.ReadData.data<get>()|}on {|common.ReadData.data<get>()|} { {|common.BMClosedED.dataOut.data<get>()|} -> {|common.BMClosedED.dataOut.data<get>()|} {|common.BMDevice.dataOut.data<get>()|} -> {|common.BMDevice.dataOut.data<get>()|} } function{|common.ReadData.data<get><invoke>()|}( CAD.Componentconsumer, stringportName, stringmethodName) returnsstring { // CAD extension API calls to resolve remote facet component … // handlerFunction is vtable key, provider is CAD.Component result := invokevirtual{|common.ReadData.data<get>()|}( handlerFunction, provider) returnresult; } Generate a set of enumerated values, virtual table, and “lookup” function for each interface method used anywhere in a facet Extracting Transition Systems from Component Models

  49. Value Storage extensionCADforSystemModule { expdefbooleanhasAttribute(CAD.Component, string); expdef'agetAttribute<'a>(CAD.Component, string); actiondefsetAttribute<'a>(CAD.Component, string, 'a); } • Persistent simple variables (modes, buffers) must be stored • We add an internal key-value table indexed by variable name inside each CAD.Component • Only the keys and values are exposed in Bogor’s state vector; avoids lots of data structure overhead Mode variable appears asr-value: use getAttribute() Mode variable appears asl-value: use setAttribute() Extracting Transition Systems from Component Models

  50. Constants • CPS is purposely abstract. It allows only enumerated type constants (no int or other scalars). • All CCM enumerated types are visible to CPS, plus private domains of mode variables. E.g., • IDL:enum OnOffMode { enabled, disabled }; • CPS:mode amEnabled of { enabled, disabled } init enabled; • Generates… Extracting Transition Systems from Component Models

More Related