16 Implementation_Techniques
Download
Report
Transcript 16 Implementation_Techniques
Implementation
Techniques
Software Architecture
Lecture 16
Copyright © Richard N. Taylor, Nenad Medvidovic, and Eric M. Dashofy. All rights reserved.
Software Architecture: Foundations, Theory, and Practice
Objectives
Concepts
Implementation as a mapping problem
Architecture implementation frameworks
Evaluating frameworks
Relationships between middleware, frameworks,
component models
Building new frameworks
Concurrency and generative technologies
Ensuring architecture-to-implementation consistency
Examples
Different frameworks for pipe-and-filter
Different frameworks for the C2 style
Application
Implementing Lunar Lander in different frameworks
2
Software Architecture: Foundations, Theory, and Practice
Objectives
Concepts
Implementation as a mapping problem
Architecture implementation frameworks
Evaluating frameworks
Relationships between middleware, frameworks,
component models
Building new frameworks
Concurrency and generative technologies
Ensuring architecture-to-implementation consistency
Examples
Different frameworks for pipe-and-filter
Different frameworks for the C2 style
Application
Implementing Lunar Lander in different frameworks
3
Software Architecture: Foundations, Theory, and Practice
Recall Pipe-and-Filter
Components (‘filters’) organized linearly,
communicate through character-stream ‘pipes,’ which
are the connectors
Filters may run concurrently on partial data
In general, all input comes in through the left and all
output exits from the right
4
Software Architecture: Foundations, Theory, and Practice; Richard N. Taylor, Nenad Medvidovic, and Eric M. Dashofy; (C) 2008 John Wiley & Sons, Inc. Reprinted with permission.
Software Architecture: Foundations, Theory, and Practice
Framework #1: stdio
Standard I/O framework used in C programming language
Each process is a filter
Reads input from standard input (aka ‘stdin’)
Writes output to standard output (aka ‘stdout’)
Also a third, unbuffered output stream called standard error
(‘stderr’) not considered here
Low and high level operations
getchar(…), putchar(…) move one character at a time
printf(…) and scanf(…) move and format entire strings
Different implementations may vary in details (buffering
strategy, etc.)
5
Software Architecture: Foundations, Theory, and Practice
Evaluating stdio
Platform support
Available with most, if
not all, implementations
of C programming
language
Operates somewhat
differently on OSes with
no concurrency (e.g.,
MS-DOS)
Fidelity
Good support for
developing P&F
applications, but no
restriction that apps have
to use this style
Matching assumptions
Filters are processes and
pipes are implicit. Inprocess P&F applications
might require
modifications
Efficiency
Whether filters make
maximal use of
concurrency is partially
up to filter
implementations and
partially up to the OS
6
Software Architecture: Foundations, Theory, and Practice
Framework #2: java.io
Standard I/O framework used in Java language
Object-oriented
Can be used for in-process or inter-process P&F
applications
All stream classes derive from InputStream or
OutputStream
Distinguished objects (System.in and System.out) for
writing to process’ standard streams
Additional capabilities (formatting, buffering) provided
by creating composite streams (e.g., a FormattingBuffered-InputStream)
7
Software Architecture: Foundations, Theory, and Practice
Evaluating java.io
Matching assumptions
Platform support
Available with all Java
implementations on many
platforms
Platform-specific
differences abstracted
away
Fidelity
Good support for
developing P&F
applications, but no
restriction that apps have
to use this style
Easy to construct intraand inter-process P&F
applications
Concurrency can be an
issue; many calls are
blocking
Efficiency
Users have fine-grained
control over, e.g.,
buffering
Very high efficiency
mechanisms (memory
mapped I/O, channels)
not available (but are in
java.nio)
8
Software Architecture: Foundations, Theory, and Practice
Recall the C2 Style
Layered style
with event-based
communication
over two-way
broadcast
buses
Strict rules on
concurrency,
dependencies,
and so on
Many frameworks developed for
different languages; focus on two
alternative Java frameworks here
9
Software Architecture: Foundations, Theory, and Practice; Richard N. Taylor, Nenad Medvidovic, and Eric M. Dashofy; (C) 2008 John Wiley & Sons, Inc. Reprinted with permission.
Software Architecture: Foundations, Theory, and Practice
Framework #1: Lightweight C2
Framework
16 classes, 3000
lines of code
Components &
connectors extend
abstract base classes
Concurrency,
queuing handled at
individual
comp/conn level
Messages are
request or
notification objects
10
Software Architecture: Foundations, Theory, and Practice; Richard N. Taylor, Nenad Medvidovic, and Eric M. Dashofy; (C) 2008 John Wiley & Sons, Inc. Reprinted with permission.
Software Architecture: Foundations, Theory, and Practice
Evaluating Lightweight C2
Framework
Matching assumptions
Platform support
Available with all Java
implementations on
many platforms
Fidelity
Assists developers with
many aspects of C2
but does not enforce
these constraints
Leaves threading and
queuing policies up to
individual elements
Comp/conn main
classes must inherit
from distinguished
base classes
All messages must be
in dictionary form
Efficiency
Lightweight
framework; efficiency
may depend on
threading and queuing
policy implemented by
individual elements
11
Software Architecture: Foundations, Theory, and Practice
Framework #2: Flexible C2
Framework
73 classes, 8500
lines of code
Uses interfaces
rather than base
classes
Threading policy
for application
is pluggable
Message queuing policy is
also pluggable
12
Software Architecture: Foundations, Theory, and Practice; Richard N. Taylor, Nenad Medvidovic, and Eric M. Dashofy; (C) 2008 John Wiley & Sons, Inc. Reprinted with permission.
Software Architecture: Foundations, Theory, and Practice
Framework #2: Flexible C2
Framework
13
Software Architecture: Foundations, Theory, and Practice; Richard N. Taylor, Nenad Medvidovic, and Eric M. Dashofy; (C) 2008 John Wiley & Sons, Inc. Reprinted with permission.
Software Architecture: Foundations, Theory, and Practice
Evaluating Flexible C2 Framework
Platform support
Available with all Java
implementations on
many platforms
Fidelity
Assists developers with
many aspects of C2
but does not enforce
these constraints
Provides several
alternative applicationwide threading and
queuing policies
Matching assumptions
Comp/conn main classes
must implement
distinguished interfaces
Messages can be any
serializable object
Efficiency
User can easily swap out
and tune threading and
queuing policies without
disturbing remainder of
application code
14
Software Architecture: Foundations, Theory, and Practice
Objectives
Concepts
Implementation as a mapping problem
Architecture implementation frameworks
Evaluating frameworks
Relationships between middleware, frameworks,
component models
Building new frameworks
Concurrency and generative technologies
Ensuring architecture-to-implementation consistency
Examples
Different frameworks for pipe-and-filter
Different frameworks for the C2 style
Application
Implementing Lunar Lander in different frameworks
15
Software Architecture: Foundations, Theory, and Practice
Implementing Pipe and Filter
Lunar Lander
Framework: java.io
Implementing as a multi-process application
Each component (filter) will be a separate OS process
Operating system will provide the pipe connectors
Going to use just the standard input and output streams
Ignoring standard error
Ignoring good error handling practices and corner cases for
simplicity
16
Software Architecture: Foundations, Theory, and Practice; Richard N. Taylor, Nenad Medvidovic, and Eric M. Dashofy; (C) 2008 John Wiley & Sons, Inc. Reprinted with permission.
Software Architecture: Foundations, Theory, and Practice
Implementing Pipe and Filter
Lunar Lander
A note on I/O:
Some messages sent from components are intended for output
to the console (to be read by the user)
These messages must be passed all the way through the
pipeline and output at the end
We will preface these with a ‘#’
Some messages are control messages meant to communicate
state to a component down the pipeline
These messages are intercepted by a component and
processed
We will preface these with a ‘%’
17
Software Architecture: Foundations, Theory, and Practice; Richard N. Taylor, Nenad Medvidovic, and Eric M. Dashofy; (C) 2008 John Wiley & Sons, Inc. Reprinted with permission.
Software Architecture: Foundations, Theory, and Practice
Implementing Pipe and Filter
Lunar Lander
First: GetBurnRate component
Loops; on each loop:
Prompt user for new burn rate
Read burn rate from the user on standard input
Send burn rate to next component
Quit if burn rate read < 0
18
Software Architecture: Foundations, Theory, and Practice; Richard N. Taylor, Nenad Medvidovic, and Eric M. Dashofy; (C) 2008 John Wiley & Sons, Inc. Reprinted with permission.
Software Architecture: Foundations, Theory, and Practice
GetBurnRate Filter
//Import the java.io framework
import java.io.*;
public class GetBurnRate{
public static void main(String[] args){
//Send welcome message
System.out.println("#Welcome to Lunar Lander");
try{
//Begin reading from System input
BufferedReader inputReader =
new BufferedReader(new InputStreamReader(System.in));
//Set initial burn rate to 0
int burnRate = 0;
do{
//Prompt user
System.out.println("#Enter burn rate or <0 to quit:");
. . .
19
Software Architecture: Foundations, Theory, and Practice; Richard N. Taylor, Nenad Medvidovic, and Eric M. Dashofy; (C) 2008 John Wiley & Sons, Inc. Reprinted with permission.
Software Architecture: Foundations, Theory, and Practice
GetBurnRate Filter
//Import the java.io framework
import java.io.*;
. . .
public class GetBurnRate{
//Read user response
public static void
try{main(String[] args){
String burnRateString = inputReader.readLine();
//Send welcome message
burnRate = Integer.parseInt(burnRateString);
System.out.println("#Welcome to Lunar Lander");
//Send user-supplied burn rate to next filter
try{
System.out.println("%" + burnRate);
//Begin reading
from System input
}
BufferedReader
inputReader =
catch(NumberFormatException
nfe){
new BufferedReader(new
InputStreamReader(System.in));
System.out.println("#Invalid burn rate.");
}
//Set initial
burn rate to>=0 0);
}while(burnRate
int burnRate
= 0;
inputReader.close();
do{
}
//Prompt
user
catch(IOException
ioe){
System.out.println("#Enter
burn rate or <0 to quit:");
ioe.printStackTrace();
}
. . .
}
}
20
Software Architecture: Foundations, Theory, and Practice; Richard N. Taylor, Nenad Medvidovic, and Eric M. Dashofy; (C) 2008 John Wiley & Sons, Inc. Reprinted with permission.
Software Architecture: Foundations, Theory, and Practice
Implementing Pipe and Filter
Lunar Lander
Second: CalcNewValues Component
Read burn rate from standard input
Calculate new game state including game-over
Send new game state to next component
New game state is not sent in a formatted string;
that’s the display component’s job
21
Software Architecture: Foundations, Theory, and Practice; Richard N. Taylor, Nenad Medvidovic, and Eric M. Dashofy; (C) 2008 John Wiley & Sons, Inc. Reprinted with permission.
Software Architecture: Foundations, Theory, and Practice
CalcBurnRate Filter
import java.io.*;
public class CalcNewValues{
public static void main(String[] args){
//Initialize values
final int GRAVITY = 2;
int altitude = 1000;
int fuel = 500;
int velocity = 70;
int time = 0;
try{
BufferedReader inputReader = new
BufferedReader(new InputStreamReader(System.in));
//Print initial values
System.out.println("%a"
System.out.println("%f"
System.out.println("%v"
System.out.println("%t"
. . .
+
+
+
+
altitude);
fuel);
velocity);
time);
22
Software Architecture: Foundations, Theory, and Practice; Richard N. Taylor, Nenad Medvidovic, and Eric M. Dashofy; (C) 2008 John Wiley & Sons, Inc. Reprinted with permission.
Software Architecture: Foundations, Theory, and Practice
CalcBurnRate Filter
import java.io.*;
String inputLine = null;
do{
public class CalcNewValues{
inputLine = inputReader.readLine();
if((inputLine != null) &&
public static void
(inputLine.length()
main(String[] args){
> 0)){
//Initialize values
final int GRAVITY
if(inputLine.startsWith("#")){
= 2;
int altitude = 1000;
//This is a status line of text, and
int fuel = 500; //should be passed down the pipeline
int velocity = 70;
System.out.println(inputLine);
int time = 0; }
else if(inputLine.startsWith("%")){
try{
//This is an input burn rate
BufferedReadertry{
inputReader = new
BufferedReader(new
int burnRate
InputStreamReader(System.in));
= Integer.parseInt(inputLine.substring(1));
if(altitude <= 0){
//Print initial values
System.out.println("#The game is over.");
System.out.println("%a"
}
+ altitude);
System.out.println("%f"
else if(burnRate
+ fuel); > fuel){
System.out.println("%v"
System.out.println("#Sorry,
+ velocity);
you don't" +
System.out.println("%t"
"have
+ that
time);
much fuel.");
}
23
. . .
. . .
Software Architecture: Foundations, Theory, and Practice; Richard N. Taylor, Nenad Medvidovic, and Eric M. Dashofy; (C) 2008 John Wiley & Sons, Inc. Reprinted with permission.
Software Architecture: Foundations, Theory, and Practice
CalcBurnRate Filter
else{ inputLine = null;
import java.io.*;
String
//Calculate new application state
do{
time = time
+ 1;
public class CalcNewValues{
inputLine
= inputReader.readLine();
altitude = altitude
- velocity;
if((inputLine
!= null)
&&
velocity
=
((velocity
+
GRAVITY) * 10 public static void
(inputLine.length()
main(String[] args){
> 0)){
burnRate * 2) / 10;
//Initialize values
fuel
==fuel
final int GRAVITY
if(inputLine.startsWith("#")){
2; - burnRate;
<=a 0){
int altitudeif(altitude
= 1000;
//This is
status line of text, and
altitude
=
0;
int fuel = 500; //should be passed down the pipeline
<= 5){
int velocity =if(velocity
70;
System.out.println(inputLine);
int time = 0; } System.out.println("#You have landed safely.");
}
else
if(inputLine.startsWith("%")){
else{
try{
//This is an input burn rate
System.out.println("#You
have crashed.");
BufferedReadertry{
inputReader = new
}
BufferedReader(new
int burnRate
InputStreamReader(System.in));
= Integer.parseInt(inputLine.substring(1));
}
if(altitude <= 0){
}
//Print initial values
System.out.println("#The game is over.");
//Print
new
values
System.out.println("%a"
}
+ altitude);
System.out.println("%a"
System.out.println("%f"
else if(burnRate
+ fuel);+> altitude);
fuel){
System.out.println("%f"
+
fuel);
System.out.println("%v"
System.out.println("#Sorry,
+ velocity);
you don't" +
System.out.println("%v"
+
velocity);
System.out.println("%t"
"have
+ that
time);
much fuel.");
System.out.println("%t"
+ time);
}
}
. . .
. . .
catch(NumberFormatException nfe){
}
24
. . .
Software Architecture: Foundations, Theory, and Practice; Richard N. Taylor, Nenad Medvidovic, and Eric M. Dashofy; (C) 2008 John Wiley & Sons, Inc. Reprinted with permission.
Software Architecture: Foundations, Theory, and Practice
CalcBurnRate Filter
else{ inputLine = null;
import java.io.*;
String
//Calculate new application state
do{
time = time
+ 1;
public class CalcNewValues{
inputLine
= inputReader.readLine();
altitude = altitude
- velocity;
if((inputLine
!= null)
&&
velocity
=
((velocity
+
GRAVITY) * 10 public static void
(inputLine.length()
main(String[] args){
> 0)){
burnRate * 2) / 10;
//Initialize values
fuel
==fuel
final int GRAVITY
if(inputLine.startsWith("#")){
2; - burnRate;
<=a}0){
int altitudeif(altitude
= 1000;
//This is
status line of text, and
altitude
=
0;
int fuel = 500; //should }be passed down the pipeline
<= 5){
}while((inputLine
!= null) && (altitude > 0));
int velocity =if(velocity
70;
System.out.println(inputLine);
have landed safely.");
inputReader.close();
int time = 0; } System.out.println("#You
}
}
else
if(inputLine.startsWith("%")){
else{
catch(IOException
try{
//This
is an input burnioe){
rate
System.out.println("#You
have crashed.");
ioe.printStackTrace();
BufferedReadertry{
inputReader
= new
}
BufferedReader(new
int} burnRate
InputStreamReader(System.in));
= Integer.parseInt(inputLine.substring(1));
}
}
if(altitude <= 0){
}
}
//Print initial values
System.out.println("#The game is over.");
//Print
new
values
System.out.println("%a"
}
+ altitude);
System.out.println("%a"
System.out.println("%f"
else if(burnRate
+ fuel);+> altitude);
fuel){
System.out.println("%f"
+
fuel);
System.out.println("%v"
System.out.println("#Sorry,
+ velocity);
you don't" +
System.out.println("%v"
+
velocity);
System.out.println("%t"
"have
+ that
time);
much fuel.");
System.out.println("%t"
+ time);
}
}
. . .
. . .
catch(NumberFormatException nfe){
}
25
. . .
Software Architecture: Foundations, Theory, and Practice; Richard N. Taylor, Nenad Medvidovic, and Eric M. Dashofy; (C) 2008 John Wiley & Sons, Inc. Reprinted with permission.
Software Architecture: Foundations, Theory, and Practice
Implementing Pipe and Filter
Lunar Lander
Third: DisplayValues component
Read value updates from standard input
Format them for human reading and send them to
standard output
26
Software Architecture: Foundations, Theory, and Practice; Richard N. Taylor, Nenad Medvidovic, and Eric M. Dashofy; (C) 2008 John Wiley & Sons, Inc. Reprinted with permission.
Software Architecture: Foundations, Theory, and Practice
DisplayValues Filter
import java.io.*;
public class DisplayValues{
public static void main(String[] args){
try{
BufferedReader inputReader = new
BufferedReader(new InputStreamReader(System.in));
String inputLine = null;
do{
inputLine = inputReader.readLine();
if((inputLine != null) &&
(inputLine.length() > 0)){
if(inputLine.startsWith("#")){
//This is a status line of text, and
//should be passed down the pipeline with
//the pound-sign stripped off
System.out.println(inputLine.substring(1));
}
. . .
27
Software Architecture: Foundations, Theory, and Practice; Richard N. Taylor, Nenad Medvidovic, and Eric M. Dashofy; (C) 2008 John Wiley & Sons, Inc. Reprinted with permission.
Software Architecture: Foundations, Theory, and Practice
DisplayValues Filter
else if(inputLine.startsWith("%")){
import java.io.*;//This is a value to display
if(inputLine.length() > 1){
public class DisplayValues{
try{
char valueType = inputLine.charAt(1);
public static void int
main(String[]
args){
value = Integer.parseInt(inputLine.substring(2));
try{
BufferedReader switch(valueType){
inputReader = new
BufferedReader(new
case InputStreamReader(System.in));
'a':
System.out.println("Altitude: " + value);
String inputLine = break;
null;
do{
case 'f':
inputLine = inputReader.readLine();
System.out.println("Fuel remaining: " + value);
if((inputLine != break;
null) &&
(inputLine.length()
> 0)){
case 'v':
System.out.println("Current Velocity: “ + value);
if(inputLine.startsWith("#")){
break;
//This is acase
status
't':line of text, and
//should be passed
down the pipeline with
System.out.println("Time
elapsed: " + value);
//the pound-sign
stripped
off
break;
System.out.println(inputLine.substring(1));
}
}
}
. . .
. . .
catch(NumberFormatException nfe){
}
28
Software Architecture: Foundations, Theory, and Practice; Richard N. Taylor, Nenad Medvidovic, and Eric M. Dashofy; (C) 2008 John Wiley & Sons, Inc. Reprinted with permission.
Software Architecture: Foundations, Theory, and Practice
DisplayValues Filter
else if(inputLine.startsWith("%")){
import java.io.*;//This is a value to display
if(inputLine.length() > 1){
public class DisplayValues{
try{
char valueType = inputLine.charAt(1);
public static void int
main(String[]
args){
value = Integer.parseInt(inputLine.substring(2));
try{
BufferedReader switch(valueType){
inputReader = new
}
BufferedReader(new
InputStreamReader(System.in));
case 'a': }
System.out.println("Altitude:
" + value);
}
String inputLine = break;
null;
}while(inputLine != null);
do{
case 'f':
inputReader.close();
inputLine = inputReader.readLine();
System.out.println("Fuel
remaining: " + value);
}
if((inputLine != break;
null) &&
catch(IOException ioe){
(inputLine.length()
> 0)){
case 'v':
ioe.printStackTrace();
System.out.println("Current
Velocity: “ + value);
}
if(inputLine.startsWith("#")){
}break;
//This is acase
status
't':line of text, and
}
//should be passed
down the pipeline with
System.out.println("Time
elapsed: " + value);
//the pound-sign
stripped
off
break;
System.out.println(inputLine.substring(1));
}
}
}
catch(NumberFormatException nfe){
. . .
}
. . .
29
Software Architecture: Foundations, Theory, and Practice; Richard N. Taylor, Nenad Medvidovic, and Eric M. Dashofy; (C) 2008 John Wiley & Sons, Inc. Reprinted with permission.
Software Architecture: Foundations, Theory, and Practice
Implementing Pipe and Filter
Lunar Lander
Instantiating the application
java GetBurnRate | java CalcNewValues | java DisplayValues
30
Software Architecture: Foundations, Theory, and Practice; Richard N. Taylor, Nenad Medvidovic, and Eric M. Dashofy; (C) 2008 John Wiley & Sons, Inc. Reprinted with permission.
Software Architecture: Foundations, Theory, and Practice
Implementing Pipe and Filter
Lunar Lander
31
Software Architecture: Foundations, Theory, and Practice; Richard N. Taylor, Nenad Medvidovic, and Eric M. Dashofy; (C) 2008 John Wiley & Sons, Inc. Reprinted with permission.
Software Architecture: Foundations, Theory, and Practice
Implementing Pipe and Filter
Lunar Lander
32
Software Architecture: Foundations, Theory, and Practice
Implementing Pipe and Filter
Lunar Lander
33
Software Architecture: Foundations, Theory, and Practice; Richard N. Taylor, Nenad Medvidovic, and Eric M. Dashofy; (C) 2008 John Wiley & Sons, Inc. Reprinted with permission.
Software Architecture: Foundations, Theory, and Practice
Implementing Pipe and Filter
Lunar Lander
34
Software Architecture: Foundations, Theory, and Practice
Takeaways
java.io provides a number of useful facilities
Stream objects (System.in, System.out)
Buffering wrappers
OS provides some of the facilities
Pipes
Concurrency support
Note that this version of the application would not work if it
operated in batch-sequential mode
We had other communication mechanisms available, but did not use
them to conform to the P&F style
We had to develop a new (albeit simple) protocol to get the correct
behavior
35
Software Architecture: Foundations, Theory, and Practice
Implementing Lunar Lander in C2
Framework: Lightweight
C2 framework
Each component has its
own thread of control
Components receive
requests or notifications
and respond with new
ones
Message routing follows
C2 rules
This is a real-time, clock-driven version of Lunar Lander
36
Software Architecture: Foundations, Theory, and Practice; Richard N. Taylor, Nenad Medvidovic, and Eric M. Dashofy; (C) 2008 John Wiley & Sons, Inc. Reprinted with permission.
Software Architecture: Foundations, Theory, and Practice
Implementing Lunar Lander in C2
(cont’d)
First: Clock component
Sends out a ‘tick’ notification
periodically
Does not respond to any
messages
37
Software Architecture: Foundations, Theory, and Practice; Richard N. Taylor, Nenad Medvidovic, and Eric M. Dashofy; (C) 2008 John Wiley & Sons, Inc. Reprinted with permission.
Software Architecture: Foundations, Theory, and Practice
import c2.framework.*;
Clock Component
public class Clock extends ComponentThread{
public Clock(){
super.create("clock", FIFOPort.class);
}
public void start(){
super.start();
Thread clockThread = new Thread(){
public void run(){
//Repeat while the application runs
while(true){
//Wait for five seconds
try{
Thread.sleep(5000);
}
catch(InterruptedException ie){}
//Send out a tick notification
Notification n = new Notification("clockTick");
send(n);
}
}
};
38
Software Architecture: Foundations, Theory, and Practice; Richard N. Taylor, Nenad Medvidovic, and Eric M. Dashofy; (C) 2008 John Wiley & Sons, Inc. Reprinted with permission.
Software Architecture: Foundations, Theory, and Practice
import c2.framework.*;
Clock Component
public class Clock extends ComponentThread{
public Clock(){
super.create("clock", FIFOPort.class);
}
public void start(){
clockThread.start();
super.start();
}
Thread clockThread = new Thread(){
void handle(Notification n){
publicprotected
void run(){
//This
component
does not runs
handle notifications
//Repeat
while
the application
}
while(true){
//Wait for five seconds
protected void handle(Request r){
try{
//This component does not handle requests
Thread.sleep(5000);
}}
}catch(InterruptedException ie){}
//Send out a tick notification
Notification n = new Notification("clockTick");
send(n);
}
}
};
39
Software Architecture: Foundations, Theory, and Practice; Richard N. Taylor, Nenad Medvidovic, and Eric M. Dashofy; (C) 2008 John Wiley & Sons, Inc. Reprinted with permission.
Software Architecture: Foundations, Theory, and Practice
Implementing Lunar Lander in C2
Second: GameState
Component
Receives request to update
internal state
Emits notifications of new
game state on request
or when state changes
Does NOT compute new
state
Just a data store
40
Software Architecture: Foundations, Theory, and Practice; Richard N. Taylor, Nenad Medvidovic, and Eric M. Dashofy; (C) 2008 John Wiley & Sons, Inc. Reprinted with permission.
Software Architecture: Foundations, Theory, and Practice
GameState Component
import c2.framework.*;
public class GameState extends ComponentThread{
public GameState(){
super.create("gameState", FIFOPort.class);
}
//Internal game state and initial values
int altitude = 1000;
int fuel = 500;
int velocity = 70;
int time = 0;
int burnRate = 0;
boolean landedSafely = false;
41
Software Architecture: Foundations, Theory, and Practice; Richard N. Taylor, Nenad Medvidovic, and Eric M. Dashofy; (C) 2008 John Wiley & Sons, Inc. Reprinted with permission.
Software Architecture: Foundations, Theory, and Practice
protected void handle(Request r){
GameState
Component
if(r.name().equals("updateGameState")){
//Update the internal game state
if(r.hasParameter("altitude")){
import c2.framework.*;
this.altitude = ((Integer)r.getParameter("altitude")).intValue();
}
public class
GameState extends ComponentThread{
if(r.hasParameter("fuel")){
this.fuel = ((Integer)r.getParameter("fuel")).intValue();
public GameState(){
}
super.create("gameState",
FIFOPort.class);
if(r.hasParameter("velocity")){
}
this.velocity = ((Integer)r.getParameter("velocity")).intValue();
}
//Internal
game state and initial values
if(r.hasParameter("time")){
int altitude = 1000;
= ((Integer)r.getParameter("time")).intValue();
int fuel this.time
= 500;
}
int velocity
= 70;
if(r.hasParameter("burnRate")){
int time
= 0;
this.burnRate
= ((Integer)r.getParameter("burnRate")).intValue();
int burnRate
= 0;
boolean} landedSafely = false;
if(r.hasParameter("landedSafely")){
this.landedSafely = ((Boolean)r.getParameter("landedSafely"))
.booleanValue();
}
//Send out the updated game state
Notification n = createStateNotification();
send(n);
42
}
Software Architecture: Foundations, Theory, and Practice; Richard N. Taylor, Nenad Medvidovic, and Eric M. Dashofy; (C) 2008 John Wiley & Sons, Inc. Reprinted with permission.
Software Architecture: Foundations, Theory, and Practice
GameState Component
protected else
void if(r.name().equals("getGameState")){
handle(Request r){
//If
a component requests the game state
if(r.name().equals("updateGameState")){
//without
updating
send out the state
//Update
the internal
gameit,
state
if(r.hasParameter("altitude")){
import c2.framework.*;
Notification
n = createStateNotification();
this.altitude
= ((Integer)r.getParameter("altitude")).intValue();
send(n);
}
public class
GameState extends ComponentThread{
}
if(r.hasParameter("fuel")){
}
this.fuel
= ((Integer)r.getParameter("fuel")).intValue();
public GameState(){
}
super.create("gameState",
FIFOPort.class);
protected Notification createStateNotification(){
if(r.hasParameter("velocity")){
}
//Create a new
notification comprising the
this.velocity
= ((Integer)r.getParameter("velocity")).intValue();
//current game state
}
//Internal
game state and initial values
if(r.hasParameter("time")){
int altitude
= 1000;
Notification
n = new Notification("gameState");
this.time
= ((Integer)r.getParameter("time")).intValue();
int fuel = 500;
n.addParameter("altitude", altitude);
}
int velocity
= 70;
n.addParameter("fuel",
fuel);
if(r.hasParameter("burnRate")){
int time
= 0;
n.addParameter("velocity",
velocity);
this.burnRate
= ((Integer)r.getParameter("burnRate")).intValue();
int burnRate
= 0;
n.addParameter("time", time);
boolean} landedSafely = false;
n.addParameter("burnRate", burnRate);
if(r.hasParameter("landedSafely")){
n.addParameter("landedSafely",
landedSafely);
this.landedSafely
= ((Boolean)r.getParameter("landedSafely"))
return n;
.booleanValue();
} }
protected
void
handle(Notification
n){
//Send
out the
updated
game state
//This component
does not handle notifications
Notification
n = createStateNotification();
}
send(n);
43
} }
Software Architecture: Foundations, Theory, and Practice; Richard N. Taylor, Nenad Medvidovic, and Eric M. Dashofy; (C) 2008 John Wiley & Sons, Inc. Reprinted with permission.
Software Architecture: Foundations, Theory, and Practice
Implementing Lunar Lander in C2
Third: GameLogic
Component
Receives notifications of
game state changes
Receives clock ticks
On clock tick notification,
calculates new state
and sends request up
44
Software Architecture: Foundations, Theory, and Practice; Richard N. Taylor, Nenad Medvidovic, and Eric M. Dashofy; (C) 2008 John Wiley & Sons, Inc. Reprinted with permission.
Software Architecture: Foundations, Theory, and Practice
GameLogic Component
import c2.framework.*;
public class GameLogic extends ComponentThread{
public GameLogic(){
super.create("gameLogic", FIFOPort.class);
}
//Game constants
final int GRAVITY = 2;
//Internal state values for computation
int altitude = 0;
int fuel = 0;
int velocity = 0;
int time = 0;
int burnRate = 0;
public void start(){
super.start();
Request r = new Request("getGameState");
send(r);
}
45
Software Architecture: Foundations, Theory, and Practice; Richard N. Taylor, Nenad Medvidovic, and Eric M. Dashofy; (C) 2008 John Wiley & Sons, Inc. Reprinted with permission.
Software Architecture: Foundations, Theory, and Practice
GameLogic
Component
protected void handle(Notification
n){
if(n.name().equals("gameState")){
import c2.framework.*;
if(n.hasParameter("altitude")){
this.altitude =
public class GameLogic
extends ComponentThread{
((Integer)n.getParameter("altitude")).intValue();
public GameLogic(){
}
super.create("gameLogic",
FIFOPort.class);
if(n.hasParameter("fuel")){
}
this.fuel =
((Integer)n.getParameter("fuel")).intValue();
//Game constants
}
final int GRAVITY
= 2;
if(n.hasParameter("velocity")){
this.velocity =
//Internal state
values for computation
((Integer)n.getParameter("velocity")).intValue();
int altitude
} = 0;
int fuel = if(n.hasParameter("time")){
0;
int velocity this.time
= 0;
=
int time = 0; ((Integer)n.getParameter("time")).intValue();
int burnRate
} = 0;
if(n.hasParameter("burnRate")){
public void start(){
this.burnRate =
super.start();
((Integer)n.getParameter("burnRate")).intValue();
Request r} = new Request("getGameState");
send(r);
}
}
46
Software Architecture: Foundations, Theory, and Practice; Richard N. Taylor, Nenad Medvidovic, and Eric M. Dashofy; (C) 2008 John Wiley & Sons, Inc. Reprinted with permission.
Software Architecture: Foundations, Theory, and Practice
GameLogic
Component
protected void handle(Notification
n){
if(n.name().equals("gameState")){
else
if(n.name().equals("clockTick")){
if(n.hasParameter("altitude")){
import
c2.framework.*;
//Calculate
new lander= state values
this.altitude
actualBurnRate
= burnRate;
((Integer)n.getParameter("altitude")).intValue();
public int
class
GameLogic
extends
ComponentThread{
if(actualBurnRate
>
fuel){
}
public GameLogic(){
//Ensure
we don’t burnFIFOPort.class);
more fuel than we have
if(n.hasParameter("fuel")){
super.create("gameLogic",
actualBurnRate
this.fuel == fuel;
}
}
((Integer)n.getParameter("fuel")).intValue();
}
//Game constants
time + =1;2;
if(n.hasParameter("velocity")){
finaltime
int =GRAVITY
altitudethis.velocity
= altitude - =velocity;
velocity
=((Integer)n.getParameter("velocity")).intValue();
((velocity
GRAVITY) * 10 –
//Internal
state
values for+ computation
actualBurnRate
* 2) / 10;
} = 0;
int altitude
fuel ==if(n.hasParameter("time")){
fuel - actualBurnRate;
int fuel
0;
=
int velocity this.time
= 0;
//Determine
if we landed (safely)
int time
= 0; ((Integer)n.getParameter("time")).intValue();
boolean
= false;
} landedSafely
int burnRate
= 0;
if(altitude
<= 0){
if(n.hasParameter("burnRate")){
= 0;
this.burnRate
=
public altitude
void start(){
if(velocity
<= 5){
((Integer)n.getParameter("burnRate")).intValue();
super.start();
= true;
RequestlandedSafely
r} = new Request("getGameState");
} }
send(r);
}
}
47
Software Architecture: Foundations, Theory, and Practice; Richard N. Taylor, Nenad Medvidovic, and Eric M. Dashofy; (C) 2008 John Wiley & Sons, Inc. Reprinted with permission.
Software Architecture: Foundations, Theory, and Practice
GameLogic
Component
protected void handle(Notification
n){
if(n.name().equals("gameState")){
else if(n.name().equals("clockTick")){
if(n.hasParameter("altitude")){
import //Calculate
c2.framework.*;
new lander= state values
this.altitude
int actualBurnRate
= burnRate;
((Integer)n.getParameter("altitude")).intValue();
public if(actualBurnRate
class }GameLogic extends
ComponentThread{
> fuel){
public //Ensure
GameLogic(){
Request
= newburn
Request("updateGameState");
werdon’t
more fuel than we have
if(n.hasParameter("fuel")){
super.create("gameLogic",
FIFOPort.class);
r.addParameter("time",
time);
actualBurnRate
this.fuel == fuel;
}
r.addParameter("altitude",
altitude);
}
((Integer)n.getParameter("fuel")).intValue();
r.addParameter("velocity",
velocity);
}
//Game
constants
r.addParameter("fuel",
fuel);
time =
time + 1;
if(n.hasParameter("velocity")){
finalaltitude
int r.addParameter("landedSafely",
GRAVITY
= 2;
landedSafely);
= altitude
- =velocity;
this.velocity
send(r);
velocity
=((Integer)n.getParameter("velocity")).intValue();
((velocity + GRAVITY) * 10 –
//Internal
state
values
for/ computation
} }
actualBurnRate
* 2)
10;
int altitude
=
0;
}
fuel
=if(n.hasParameter("time")){
fuel - actualBurnRate;
int fuel = 0;this.time =
int velocity
= ((Integer)n.getParameter("time")).intValue();
0;
protected
void
handle(Request
r){
//Determine
if we
landed (safely)
int time
= }0;landedSafely
//This
component does
not handle requests
boolean
= false;
int burnRate
= 0;<= 0){
}
if(altitude
if(n.hasParameter("burnRate")){
} altitude
= 0;
this.burnRate
=
public if(velocity
void start(){
<= 5){
((Integer)n.getParameter("burnRate")).intValue();
super.start();
landedSafely
= true;
}
Request
r
=
new
Request("getGameState");
} }
send(r);
}
}
48
Software Architecture: Foundations, Theory, and Practice; Richard N. Taylor, Nenad Medvidovic, and Eric M. Dashofy; (C) 2008 John Wiley & Sons, Inc. Reprinted with permission.
Software Architecture: Foundations, Theory, and Practice
Implementing Lunar Lander in C2
Fourth: GUI Component
Reads burn rates from
user and sends them
up as requests
Receives notifications of
game state changes and
formats them to console
49
Software Architecture: Foundations, Theory, and Practice; Richard N. Taylor, Nenad Medvidovic, and Eric M. Dashofy; (C) 2008 John Wiley & Sons, Inc. Reprinted with permission.
Software Architecture: Foundations, Theory, and Practice
GUI Component
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import c2.framework.*;
public class GUI extends ComponentThread{
public GUI(){
super.create("gui", FIFOPort.class);
}
public void start(){
super.start();
Thread t = new Thread(){
public void run(){
processInput();
}
};
t.start();
}
50
Software Architecture: Foundations, Theory, and Practice; Richard N. Taylor, Nenad Medvidovic, and Eric M. Dashofy; (C) 2008 John Wiley & Sons, Inc. Reprinted with permission.
Software Architecture: Foundations, Theory, and Practice
public void processInput(){
System.out.println("Welcome to Lunar Lander");
try{
BufferedReader inputReader = new BufferedReader(
new InputStreamReader(System.in));
import java.io.BufferedReader;
import java.io.IOException;
int burnRate = 0;
import java.io.InputStreamReader;
do{
System.out.println("Enter burn rate or <0 to quit:");
import c2.framework.*;
try{
= inputReader.readLine();
public class GUI String
extendsburnRateString
ComponentThread{
public GUI(){ burnRate = Integer.parseInt(burnRateString);
GUI Component
super.create("gui", FIFOPort.class);
Request r = new Request("updateGameState");
}
r.addParameter("burnRate", burnRate);
send(r);
public void start(){
}
super.start();
nfe){
Thread t = catch(NumberFormatException
new Thread(){
burn rate.");
public voidSystem.out.println("Invalid
run(){
}
processInput();
}while(burnRate >= 0);
}
inputReader.close();
};
}
t.start();
catch(IOException ioe){
}
ioe.printStackTrace();
}
}
51
Software Architecture: Foundations, Theory, and Practice; Richard N. Taylor, Nenad Medvidovic, and Eric M. Dashofy; (C) 2008 John Wiley & Sons, Inc. Reprinted with permission.
Software Architecture: Foundations, Theory, and Practice
public void processInput(){
System.out.println("Welcome to Lunar Lander");
try{
protected void handle(Notification n){
BufferedReader inputReader = new BufferedReader(
if(n.name().equals("gameState")){
import java.io.BufferedReader;
new InputStreamReader(System.in));
System.out.println();
import java.io.IOException;
game state:");
importSystem.out.println("New
java.io.InputStreamReader;
int burnRate = 0;
do{
if(n.hasParameter("altitude")){
import c2.framework.*;
System.out.println("Enter burn rate or <0 to quit:");
System.out.println(" Altitude: " + n.getParameter("altitude"));
try{
}
public class GUI String
extendsburnRateString
ComponentThread{
= inputReader.readLine();
if(n.hasParameter("fuel")){
public GUI(){ burnRate = Integer.parseInt(burnRateString);
System.out.println("
Fuel: " + n.getParameter("fuel"));
super.create("gui",
FIFOPort.class);
}
}
Request r = new Request("updateGameState");
if(n.hasParameter("velocity")){
r.addParameter("burnRate", burnRate);
System.out.println("
Velocity: " + n.getParameter("velocity"));
public void start(){
send(r);
}
super.start();
}
if(n.hasParameter("time")){
Thread t = catch(NumberFormatException
new Thread(){
nfe){
System.out.println("
Time:
"
+
n.getParameter("time"));
public voidSystem.out.println("Invalid
run(){
burn rate.");
} processInput();
}
if(n.hasParameter("burnRate")){
}
}while(burnRate >= 0);
Burn rate: " + n.getParameter("burnRate"));
}; System.out.println("
inputReader.close();
}
t.start();
}
}
catch(IOException ioe){
ioe.printStackTrace();
}
}
GUI Component
52
Software Architecture: Foundations, Theory, and Practice; Richard N. Taylor, Nenad Medvidovic, and Eric M. Dashofy; (C) 2008 John Wiley & Sons, Inc. Reprinted with permission.
Software Architecture: Foundations, Theory, and Practice
public void processInput(){
System.out.println("Welcome to Lunar Lander");
try{
protectedif(n.hasParameter("altitude")){
void handle(Notification n){
BufferedReader inputReader = new BufferedReader(
if(n.name().equals("gameState")){
int
altitude
=
import java.io.BufferedReader;
new
InputStreamReader(System.in));
System.out.println();
((Integer)n.getParameter("altitude")).intValue();
import java.io.IOException;
System.out.println("New
game state:");
if(altitude
import java.io.InputStreamReader;
int burnRate<=
= 0){
0;
boolean landedSafely =
do{
if(n.hasParameter("altitude")){
((Boolean)n.getParameter("landedSafely"))
import c2.framework.*;
System.out.println("Enter
burn rate or <0 to quit:");
System.out.println("
Altitude: " + n.getParameter("altitude"));
.booleanValue();
try{
}
if(landedSafely){
public class GUI
extendsburnRateString
ComponentThread{
String
= inputReader.readLine();
if(n.hasParameter("fuel")){
have landed safely.");
public GUI(){ System.out.println("You
burnRate = Integer.parseInt(burnRateString);
System.out.println("
Fuel:
"
+
n.getParameter("fuel"));
}
super.create("gui",
FIFOPort.class);
}
else{
}
Request r = new Request("updateGameState");
if(n.hasParameter("velocity")){
System.out.println("You
have
crashed.");
r.addParameter("burnRate",
burnRate);
System.out.println("
Velocity:
"
+
n.getParameter("velocity"));
} send(r);
public void start(){
}
System.exit(0);
super.start();
}
if(n.hasParameter("time")){
}
Thread t = catch(NumberFormatException
new Thread(){
nfe){
System.out.println("
Time:
"
+
n.getParameter("time"));
}
public voidSystem.out.println("Invalid
run(){
burn rate.");
} processInput();
}
}
if(n.hasParameter("burnRate")){
}}
}while(burnRate >= 0);
Burn rate: " + n.getParameter("burnRate"));
}; System.out.println("
inputReader.close();
}protected void handle(Request r){
t.start();
}
//This
component does
not handle requests
}
catch(IOException
ioe){
}
ioe.printStackTrace();
}
}
}
GUI Component
53
Software Architecture: Foundations, Theory, and Practice; Richard N. Taylor, Nenad Medvidovic, and Eric M. Dashofy; (C) 2008 John Wiley & Sons, Inc. Reprinted with permission.
Software Architecture: Foundations, Theory, and Practice
Implementing Lunar Lander in C2
Lastly, main program
Instantiates and connects
all elements of the system
54
Software Architecture: Foundations, Theory, and Practice; Richard N. Taylor, Nenad Medvidovic, and Eric M. Dashofy; (C) 2008 John Wiley & Sons, Inc. Reprinted with permission.
Software Architecture: Foundations, Theory, and Practice
import c2.framework.*;
Main Program
public class LunarLander{
public static void main(String[] args){
//Create the Lunar Lander architecture
Architecture lunarLander = new
SimpleArchitecture("LunarLander");
//Create the components
Component clock = new Clock();
Component gameState = new GameState();
Component gameLogic = new GameLogic();
Component gui = new GUI();
//Create the connectors
Connector bus = new ConnectorThread("bus");
//Add the components and connectors to the architecture
lunarLander.addComponent(clock);
lunarLander.addComponent(gameState);
lunarLander.addComponent(gameLogic);
lunarLander.addComponent(gui);
lunarLander.addConnector(bus);
55
Software Architecture: Foundations, Theory, and Practice; Richard N. Taylor, Nenad Medvidovic, and Eric M. Dashofy; (C) 2008 John Wiley & Sons, Inc. Reprinted with permission.
Software Architecture: Foundations, Theory, and Practice
import c2.framework.*;
Main Program
public class LunarLander{
public static void main(String[] args){
//Create the Lunar Lander architecture
Architecture lunarLander = new
SimpleArchitecture("LunarLander");
//Create the welds (links) between components and
//connectors
//Create
the components
lunarLander.weld(clock,
bus);
Component
clock = new Clock();
lunarLander.weld(gameState,
bus);
Component
gameState = new GameState();
lunarLander.weld(bus,
gameLogic);
Component
gameLogic = new GameLogic();
lunarLander.weld(bus,
gui);
Component gui = new GUI();
//Start the application
//Create
the connectors
lunarLander.start();
Connector
bus = new ConnectorThread("bus");
}
}
//Add the components and connectors to the architecture
lunarLander.addComponent(clock);
lunarLander.addComponent(gameState);
lunarLander.addComponent(gameLogic);
lunarLander.addComponent(gui);
lunarLander.addConnector(bus);
56
Software Architecture: Foundations, Theory, and Practice; Richard N. Taylor, Nenad Medvidovic, and Eric M. Dashofy; (C) 2008 John Wiley & Sons, Inc. Reprinted with permission.
Software Architecture: Foundations, Theory, and Practice
Takeaways
Here, the C2 framework provides most all of the scaffolding we
need
Message routing and buffering
How to format a message
Threading for components
Startup and instantiation
We provide the component behavior
Including a couple new threads of our own
We still must work to obey the style guidelines
Not everything is optimal: state is duplicated in Game Logic, for
example
57