380 likes | 586 Views
Reading C2-style Applications Built in c2.fw. Eric M. Dashofy edashofy@ics.uci.edu For ICS 52 October 20, 2004. Overview. Software architectures The C2 architectural style With live example The Klax application. Software Architecture: Basic Elements. Interfaces. Clock. Component.
E N D
Reading C2-style Applications Built in c2.fw Eric M. Dashofy edashofy@ics.uci.edu For ICS 52 October 20, 2004
Overview • Software architectures • The C2 architectural style • With live example • The Klax application
Software Architecture:Basic Elements Interfaces Clock Component Connector Bus1 Interfaces
Software Architecture:Basic Elements (cont). Clock Configuration Links Bus1 LCD Driver
An Architectural Style • One definition of an architectural style: • An architectural style is a named set of constraints (e.g., rules) you put on your development • Constraints may be topological, behavioral, communication-oriented, you name it • This can complicate development because these constraints may be inconvenient or unfamiliar • BUT architectural styles elicit beneficial system properties that would be really hard to get otherwise
Examples from building architecture: • Name some constraints in each style • Name some benefits (-ilities) elicited by each style.
The C2 Architectural Style • Topological Constraints • All components, connectors have two interfaces, “top” and “bottom” • Components can be connected to 0-1 connector on each interface • Connectors can be connected to 0+ components or connectors on each interface
The C2 Architectural Style • Communication Constraints • Components & connectors communicate using only independent events or messages • Requests go up (“requests rise”) • Notifications go down • No passing pointers • Components & connectors communicate asynchronously • Can send/receive events at any time • No blocking!
The C2 Architectural Style • Dependency Constraints • Components may make assumptions about services provided above them • But not who is providing them • Components may NOT make assumptions about services provided below them • Concurrency Constraints • Each component & connector assumes it’s running in its own thread of control
Live Example Data Store GUI Interpreter Alarm GUI
Live Example Data Store Stores data; emits notifications whenever data changes. GUI Interpreter Alarm GUI
Live Example Interprets basic GUI actions & translates them into data store operations Data Store GUI Interpreter Alarm GUI
Live Example Data Store Rings a bell whenever value of X changes GUI Interpreter Alarm GUI
Live Example Data Store GUI Interpreter Alarm Accept & process user actions GUI
Live Example Data Store GUI Interpreter Alarm Bus connector – routes messages GUI
Live Example Data Store GUI Interpreter Alarm GUI
What –ilities does C2 buy us? • What do you think?
-ilities bought by C2 • Flexibility • Loose coupling lets you swap out components, interpose components • Flexible connectors allow run-time changes • Distributability • Since no assumption of shared address space, distributing an app across machines is easy • Visibility • Since all messages go through connectors, they are easy to catch and log • Parallelizability • One-thread-per-brick means multiprocessor machines are effectively utilized
Event-based Communication by events Mostly asynchronous Requests emitted to unknown parties Responses and state changes go to many parties No shared pointers Object Oriented Communication by procedure calls Mostly synchronous Requests emitted to named party only Responses to caller only, state changes to many Lots of shared pointers Event-based vs. OO
Implementing a C2 architecture C2 architecture Event-basedWorld Implemented by… Application (implemented) ??? How do we bridge this gap? Java/JVM Object-orientedWorld Uses services provided by… Native OS
Implementing a C2 architecture C2 architecture Event-basedWorld Implemented by… Application (implemented) Uses services provided by… Architecture Framework Uses services provided by… Java/JVM Object-orientedWorld Uses services provided by… Native OS
What’s an architecture framework? • An architecture framework is software that helps to bridge the gaps between an architectural style and a particular implementation platform.
C2 World Components Connectors Events Links Many threads Asynchronous communication Java World Objects Method calls Parameters References Few threads Synchronous communication Example
Enter c2.fw • c2.fw is an architecture framework for the C2 style built in Java, providing: • Abstract base classes for components, connectors • Reusable connectors (local & network) • (Pluggable) topology management • (Pluggable) message queuing policies • (Pluggable) threading policies • Essentially, c2.fw does the hard work, components and connectors simply implement behaviors.
What does a message look like? • In c2.fw, a message can be any serializable (e.g. no pointers) object • NamedPropertyMessages (or subclasses) are popular though • Have a String name • Plus a set of name-value pairs • e.g. {“description”, “Rectangle 1”} • e.g. {“width”, 123} • e.g. {“color”, java.awt.Color.BLACK}
“Reading” a c2.fw application • Basic format • Lifecycle methods: • init(), begin(), end(), destroy() • start(), stop(), suspend(), resume() • Handling messages • void handle(Message m) • Sending messages • sendToAll(Message m, Interface i)
Your basic c2.fw component… package edu.uci.ics.mypackage;import c2.fw.*; //import c2.fw packageimport c2.legacy.*; //import support for 2-interface //C2 components
Your basic c2.fw component… package edu.uci.ics.mypackage;import c2.fw.*; //import c2.fw packageimport c2.legacy.*; //import support for 2-interface //C2 componentspublic class MyC2Component extends AbstractC2Brick{} Implements lots of boilerplate functionality from the base c2.fw.Brick interface; declares a top interface topIface and a bottom interface bottomIface.
A boilerplate c2.fw component… package edu.uci.ics.mypackage;import c2.fw.*; //import c2.fw packageimport c2.legacy.*; //import support for 2-interface //C2 componentspublic class MyC2Component extends AbstractC2Brick{ public MyC2Component(Identifier id){ super(id); }} Each component or connector has a unique identifier.
A boilerplate c2.fw component… package edu.uci.ics.mypackage;import c2.fw.*; //import c2.fw packageimport c2.legacy.*; //import support for 2-interface //C2 componentspublic class MyC2Component extends AbstractC2Brick{ public MyC2Component(Identifier id){ super(id); } public void begin(){ //called automatically by fw. //send out initial events }}
Lifecycle Methods public void init(){ //called when component/connector is created //but component not guaranteed to be hooked up} public void begin(){ //called when component/connector is hooked up //in the architecture, should send initial messages} public void end(){ //called when component/connector is about to be //unhooked, should send final messages} public void destroy(){ //called when component/connector is about to be //destroyed}
A boilerplate c2.fw component… package edu.uci.ics.mypackage;import c2.fw.*; //import c2.fw packageimport c2.legacy.*; //import support for 2-interface //C2 componentspublic class MyC2Component extends AbstractC2Brick{ public MyC2Component(Identifier id){ super(id); } public void begin(){ //called automatically by fw. //send out initial events }public void handle(Message m){ //handle message }}
Implementing handle() //handle() method for our hypothetical alarm component //Called automatically when component receives a message //Should ring bell whenever value of ‘X’ changes public void handle(Message m){ //handle message }
Implementing handle() //handle() method for our hypothetical alarm component public void handle(Message m){ //handle messageif(m instanceof NamedPropertyMessage){ NamedPropertyMessage npm = (NamedPropertyMessage)m; } }
Implementing handle() //handle() method for our hypothetical alarm component public void handle(Message m){ //handle message if(m instanceof NamedPropertyMessage){ NamedPropertyMessage npm = (NamedPropertyMessage)m; String name = npm.getName(); if((name != null) && (name.equals(“valueChanged”)){ } } }
Implementing handle() //handle() method for our hypothetical alarm component public void handle(Message m){ //handle message if(m instanceof NamedPropertyMessage){ NamedPropertyMessage npm = (NamedPropertyMessage)m; String name = npm.getName(); if((name != null) && (name.equals(“valueChanged”)){ String varName = (String)npm.getParameter(“varName”); if((varName != null) && (varName.equals(“x”)){ } } } }
Implementing handle() //handle() method for our hypothetical alarm component public void handle(Message m){ //handle message if(m instanceof NamedPropertyMessage){ NamedPropertyMessage npm = (NamedPropertyMessage)m; String name = npm.getName(); if((name != null) && (name.equals(“valueChanged”)){ String varName = (String)npm.getParameter(“varName”); if((varName != null) && (varName.equals(“x”)){ ringBell(); NamedPropertyMessage rnpm = new NamedPropertyMessage(“AlarmFired”); rnpm.addProperty(“time”, System.currentTimeMillis()); sendToAll(rnpm, bottomIface); } } } }
Implementing handle() If we care, we could have checked what interface that message came in on: if(m.getDestination().getInterfaceIdentifier().equals( AbstractC2Brick.TOP_INTERFACE_ID)){ //it’s a notification }