π-ADL: A Formal Description Language for - ConSiste

π -ADL:
A Formal Description Language for
Software Architectures
E. Cavalcante, F. Oquendo, T. Batista
Technical Report
-
UFRN-DIMAp-2014-102-RT
September
-
2014
-
-
Relatório Técnico
Setembro
The contents of this document are the sole responsibility of the authors.
O conteúdo do presente documento é de única responsabilidade dos autores.
Departamento de Informática e Matemática Aplicada
Universidade Federal do Rio Grande do Norte
www.dimap.ufrn.br
π-ADL: A Formal Description Language for
Software Architectures
Everton Cavalcante1,2 , Flavio Oquendo2 , Thais Batista1
1 DIMAp,
Federal University of Rio Grande do Norte, Natal, Brazil
CNRS/Université de Bretagne-Sud, Vannes, France
2 IRISA-UMR
[email protected], [email protected], [email protected]
Abstract. Software architectures have played a central role in the development of software systems due to their potential for contributing with the achievement of functional and quality requirements. The specification of these architectures is an important
activity in this context as it can document anticipated important design decisions, generates artifacts that pervade throughout the software development lifecycle, enables
a better understanding and communication about the system, and is able to guide the
evolution of the system. For this purposes, architecture description languages (ADLs)
have been used as notations for representing and analyzing software architectures,
thus producing models that can be used at design time and/or runtime. However, most
existing ADLs: (i) are focused on structural, topological aspects of the architecture;
(ii) do not provide an adequate support for representing behavioral aspects of the
system; (iii) do not support an expressive description of dynamic aspects of the architectures; (iv) have limitations in terms of automated verification of constraints and
properties, and; (v) are disconnected from the runtime level, thus entailing architectural mismatches and inconsistencies between architecture and implementation. In response to some of these challenges, this report introduces π-ADL, a formal language
based on the π-calculus process algebra for specifying dynamic software architectures
under structural and behavioral viewpoints and supporting their automated analysis
with respect to functional and non-functional properties. Furthermore, π-ADL is integrated with the Go programming language (also based on π-calculus), thus enabling
to automatically generate implementation code from architecture descriptions while
benefiting from the capabilities provided by this language for constructing scalable
distributed systems and handling multicore and networked computer architectures, as
required by new generation software systems. Finally, π-ADL is endowed with a tool
support for assisting software architects in the description of architectures and the generation of implementation code. In this report, a real-world flood monitoring system
is used as an example of how to describe software architectures in π-ADL and then
automatically generate source code in Go.
Keywords: Software architectures, architecture description languages, π-ADL, Go.
1
π-ADL: A Formal Description Language for Software Architectures
1
2
Introduction
The Software Architecture has attracted much attention from researchers and practitioners
since the 1990’s [46]. The increasing complexity in software development and the demand for
quality software systems are some of the most important issues that have increased the interest
on this sub-discipline of Software Engineering. Due to their size and complexity and the frequent involvement of large teams of developers, rigorous and systematic approaches have been
required to engineer software systems. Among the existing approaches, the architecture-driven
engineering has been regarded as useful to successfully build software systems by considering
software architectures as the central element in the development process. In this perspective,
a software architecture is the main artifact for activities such as system design and analysis,
model refinement towards implementation, and code generation.
According to the ISO/IEC/IEEE 42010 International Standard [30], a software architecture can be defined as the fundamental conception of a system in terms of its constituent elements and their relationships with each other and the environment, as well as the principles that
will guide the system design and evolution. Furthermore, software architectures have been recognized as a significant element for determining quality of software systems as decisions taken
at the architectural level in an early stage can directly affect the realization of business goals
and the achievement of functional and quality requirements [14, 45, 49].
Applied throughout the software lifecycle, good architectural practice has the potential to
increase the understandability of a software system and the development process used to create
it, to ensure that qualities of particular relevance are fulfilled, and to reduce the overall cost
of software engineering [23]. Therefore, as a tool for improving design practices, architecture
offers an effective way of modeling software systems while supporting reasoning and analyses
about behavior before development is completed. While primarily a design-related discipline
and artifact, architecture also has the potential to grant substantial benefits to the entire software
development process including runtime evolution and adaptation.
The specification of a software architecture is one of the main activities of an architecturedriven software development process as it enables to anticipate important decisions regarding
the system design [46]. Good architectural models provide a basis for architectural analysis, understanding and communicating about a system’s design, and guiding a system’s evolution. For
this purpose, formal, semi-formal, and even informal notations have been proposed to support
such a specification at a high abstraction level and the communication among stakeholders (e.g.,
architects, developers, etc.). Among these notations, architecture description languages (ADLs)
[18, 34] have become well-accepted approaches for representing and analyzing software architectures. ADLs are able to provide a systematic and disciplined way for describing architectures
by using both a conceptual framework and concrete notation, thus producing models that can
be used at design time and/or runtime.
From a runtime perspective, software architectures are often characterized by two viewpoints, namely structural and behavioral viewpoints. The structural viewpoint is concerned
with the structure of the system in terms of: (i) components, which represent functional elements of the system; (ii) connectors, which represent the interconnections among components
supporting their interactions, and; (iii) configurations of components connected by connectors
determining how they are composed together. In turn, the behavioral viewpoint is related to the
internal operation (actions) of components and connectors and to the interaction among these
elements. Most existing ADLs are focused on the structural viewpoint by providing means of
describing the topological aspects of the architectures and few ADLs support the representation
of behavioral aspects of the system, but such a support is rather limited. This is the case of
π-ADL: A Formal Description Language for Software Architectures
3
well-known ADLs such as Wright [12], xADL [20], and ACME [22].
Dynamism is another important concern for the today’s software systems, which operate
in environments that are highly dynamic and are subjected to changes. Therefore, a major challenge for ADLs is the ability of describing dynamic software architectures from both structural
and behavioral viewpoints, thus including changes on structures and behaviors of the architecture itself and its components and connectors at runtime. Most of the proposed ADLs assume
that architectures are static and few ADLs support an expressive description of dynamic aspects
of architectures, such as Dynamic Wright [11], Rapide [31], and Darwin [32].
In software engineering, formal methods refer to mathematically based techniques for
specifying, analyzing, and developing software systems. The complex and critical nature of
software call for formal ADLs as means of supporting the automated verification and enforcement of constraints and properties. Furthermore, the verification of such properties becomes
more important mainly when evolving software systems in order to ensure their correctness
before, during, and after the evolution processes. However, to accomplish these requirements,
ADLs are challenged to make a trade-off between expressiveness, user-friendship, and automated analysis capabilities enabled by the adoption of formal concerns.
In response to the abovementioned challenges, the π-ADL description language [38] was
proposed in early 2000’s as a formal, well-founded theoretically language for specifying software architectures under structural and behavioral viewpoints, unlike most existing ADLs. πADL is based on the π-calculus process algebra [36] and it was designed to support a comprehensive description of dynamic architectures and their automated rigorous analysis with
respect to functional and non-functional properties. Therefore, the adequate support to these
features as provided by π-ADL makes such a language prevail over other existing ADLs. In
the last decade, the π-ADL language has been applied in several real-world scenarios and pilot
projects for critical and large-scale systems.
A recurrent problem of almost all ADLs (including π-ADL) is the decoupling between
architecture descriptions and their respective implementations. As software architectures are
typically defined independently from implementation, ADLs are often disconnected from the
runtime level, thus entailing architectural mismatches and inconsistencies between architecture
and implementation mainly as the architecture evolves. Therefore, even if a system is initially
built to conform to its intended architecture, its implementation may become inconsistent with
the original architecture over time. This problem becomes worse with the emergence of new
generation programming languages because most existing ADLs do not properly address the
features of this type of languages, which are characterized by their purpose of taking advantage
of the modern multicore and networked computer architectures, as well providing concurrency
capabilities. These features are not well supported by existing mainstream programming languages (such as C++ and Java), thus increasing the required complexity for constructing large-scale
and dynamic systems, which are becoming typical in several application domains.
In this context, the main goal of this report is to present an evolution of π-ADL in order
to tackle some of the abovementioned issues related to the specification of software architectures and their relationship with the implementation level. The π-ADL language has undergone
some modifications in its elements and syntax in order to meet the role of a deterministic implementation language while maintaining its formal features. In order to support this transition
from architecture description to implementation, π-ADL was integrated with the Go programming language [7], an easy general-purpose language designed to address the construction of
scalable distributed systems and to handle multicore and networked computer architectures. Go
was chosen to serve as implementation language due to its basis on the π-calculus process algebra (the same of π-ADL), so that the straightforward relationship between elements of the
π-ADL: A Formal Description Language for Software Architectures
4
languages has fostered such an integration. Finally, π-ADL was endowed with a tool support
for assisting software architects in the description of architectures by using the π-ADL language
and for automatically generating implementation code in Go.
The remainder of this report is organized as follows. Section 2 introduces the π-ADL description language and its main elements. Section 3 presents the technologies used for supporting
π-ADL architecture descriptions, as well as the mapping process from such descriptions to the
implementation in Go. Section 4 details the π-ADL architecture description of a real-world
flood monitoring system and how to generate the corresponding implementation of this system in Go. Section 5 contains final remarks and directions to future work. Finally, Appendix A
presents the grammar specification of the π-ADL language.
2
The π-ADL architecture description language
Process algebras (or process calculi) represent a mathematical theory for formally modeling concurrent systems and describing their communications/interactions at a high abstraction
level [43]. As algebras are defined as mathematical structures composed of a set of values and
a set of operations and properties on these values (such as commutativity, associativity, idempotency, and distributivity), processes in typical process algebras are values and the parallel
composition of process can defined to be a commutative and associative operation on processes. Process algebras have played a role of formal underpinnings for describing software architectures as they provide a concurrency model, which expresses the existence of concurrent
processes, and a communication model, which specifies how such processes can communicate
with each other. By making a correspondence with software architectures and their formal specification, the concurrency model serves as a basis for specifying components that coexist in
order to compose the architecture of the system. In turn, the communication model serves as a
basis for specifying connectors representing the interactions between components (processes).
In this perspective, π-ADL [38] was proposed as a formal language for describing dynamic software architectures under both structural and behavioral viewpoints, i.e., in terms of the
elements that compose such architectures and their operation at runtime. This language has as
theoretical foundation the higher-order typed π-calculus [36] (hence the name), a computationally complete (Turing-complete) process algebra that is able to provide an universal model of
computation. As the classical π-calculus is not suitable to be used as an ADL because it does
not provide constructs that enable architects to easily express architectures, the π-ADL language
extends π-calculus by providing these constructs while achieving computational completeness
and high expressiveness with a simple formal notation.
In the π-calculus process algebra, communications/interactions between concurrent processes take place through channels, which are abstractions that enable the synchronization
between such processes by sending and receiving values and/or names. Despite adopting the
same notions of communicating process, the main feature that distinguishes π-calculus from
previous process calculi such as CSP (Communicating Sequential Processes) [25] and CCS
(Calculus of Communicating Systems) [35] is the name mobility, i.e., the ability of passing
names over channels that can refer to processes or even channels, so that it is possible to send
channels as data over other channels, for example. Therefore, it is possible to express changes in
process configurations during computation, thus making π-calculus a suitable underlying model
for describing dynamic software architectures, as envisioned by the π-ADL language.
The following subsections present the main elements of the π-ADL description language,
as well as a comprehensive example that illustrates how to make an architectural description
by using this language. A complete description about the syntax of architecture descriptions in
π-ADL: A Formal Description Language for Software Architectures
5
π-ADL and its main elements, as well as the operation semantics of the language can be found
in [39, 41] and in Appendix A.
2.1
Architectural abstractions
From the structural viewpoint, an architecture is described in π-ADL in terms of components, connectors, and their composition to form the system, i.e., the architecture itself as a
configuration of components and connectors. Components represent the functional elements of
the system, whereas connectors manage interactions among components as a component cannot
be directly connected to another component. Components and connectors can be also composed
to construct composite elements, which may themselves be components or connectors. In turn,
from the behavioral viewpoint, components and connectors comprise a behavior, which expresses the interaction of an architectural element and its internal computation and uses connections
to connect and transmit values.
Analogously to π-calculus, π-ADL provides connections, which are abstractions that represent communication channels between architectural elements (components and connectors).
By using typed connections, components and connectors can send (output connections) and receive (input connections) any value of the existing types, as well as connections themselves. In
order to attach a component to a connector, at least a connection of the former must be attached
to a connection of the latter. Such an attachment takes place by means of unification or value
passing, so that attached connections can transport values, connections or even architectural
elements.
Figure 1 depicts the main architectural concepts of π-ADL. From a black-box perspective, only connections of components and connectors and values passing through connections
are observable. From a white-box perspective, internal behaviors of such elements are also observable.
Figure 1: Main architectural concepts of the π-ADL language.
2.2
Type system
π-ADL is formally defined by a transition and type system [38, 41]. As depicted in Figure
2, the formal type system of π-ADL is structured upon three main layers, namely:
• π-ADLB (base π-ADL), which provides the connection and behavior constructs;
• π-ADLFO (first-order π-ADL), which extends π-ADLB with base and constructed data
types, and;
• π-ADLHO (higher-order π-ADL), which provides full first-class citizenship to the elements of the language.
π-ADL: A Formal Description Language for Software Architectures
6
p-ADLHO
higher-order p-ADL
p-ADLFO-CT
collection types
p-ADLFO
p-ADLFO-CV
first-order p-ADL
constructed value types
p-ADLB
base value types
p-ADLFO-BV
base p-ADL
Figure 2: Layered π-ADL type system.
Sections 2.2.1 to 2.2.3 present the atomic and composite data types defined in π-ADLFO .
In turn, Section 2.2.4 presents the behavior types defined in π-ADLB .
2.2.1
Basic types
The basic value types are used to express atomic values. Table 1 shows the base value
types defined in the π-ADLFO−BV layer.
Table 1: Base types defined in π-ADLFO−BV .
Type
Syntactic representation
Definition
Natural
Integer
Real
Boolean
String
Natural
Integer
Real
Boolean
String
Natural numbers (non-negative integers)
Integer numbers (signed)
Real numbers (floating-point)
Boolean logical values
Character strings
In addition to these primitive types, π-ADL defines a type called Any that works as a
generic type in the language, so that it can admit values of any type (basic or constructed ones).
Therefore, an any type can be seen as a union type with no constraint on the type of value that
it can hold.
2.2.2
Constructed types
The π-ADLFO−CV layer provides constructors for defining composite types by using the
base types from π-ADLFO−BV . Table 2 summarizes these constructed value types, each one
described as follows.
Tuple. Values of a tuple type tuple[T1 , T2 , . . . , Tn ] are n-uples (v1 , v2 , . . . , vn ) (n ≥ 2) in which
each value vi is of type Ti . For example, the declaration
t is tuple[Integer, String]
refers to the declaration of a tuple t associated to pairs in which the first value is an integer value
and the second one is a string value.
The individual values within a tuple can be projected into other variables by using the
project instruction. Therefore, for the tuple t exemplified above, the instruction
π-ADL: A Formal Description Language for Software Architectures
7
Table 2: Constructed value types defined in π-ADLFO−CV .
Type
Syntactic representation
Definition
Tuple
tuple[T1 , T2 , . . . , Tn ]
Tuple (v1 , v2 , . . . , vn ) in which each vi is of type
Ti
View
view[l1 : T1 , l2 : T2 , . . . , ln : Tn ] Labeled form of a tuple (v1 , v2 , . . . , vn ) in which
each vi has a label li and is of type Ti
Location location[T ]
Variable of type T in which values can be stored
(write) and retrieved (read)
project t as a : Integer, b : String
sequentially assigns the values within t to the variables a and b, which respectively receive an
integer value and a string value.
View. A view value can be understood as a labeled form of a tuple value. Values of a view
type view[l1 : T1 , l2 : T2 , . . . , ln : Tn ] are views (l1 : v1 , l2 : v2 , . . . , ln : vn ) (n ≥ 2) in which each
value vi is labeled as li and is of type Ti . For example, the declaration
v is view[x : Integer, y : String]
refers to the declaration of a view v associated to pairs in which the first value (x) is an integer
value and the second one (y) is a string value. The individual values of a view can be projected
into other variables by using the same project instruction used for tuples.
Location. The location construct is used for declaring variables in order to store (write) and
retrieve (read) values in these locations. For example, the instruction
x is location[Integer]
declares an integer variable named as x. Values stored in such a variable can be read by using
its identifier (x) and values can be written to it by using assignment expressions very similar to
their counterparts in programming languages.
2.2.3
Collection types
The π-ADLFO−CT layer provides constructors for defining collection types by using the
base and constructed value types from π-ADLFO−BV and π-ADLFO−CV . Table 3 summarizes
these collection types, each one described as follows.
Map. As in some programming languages, a map (a.k.a. associative array or hash table) is an
unordered, non-sequential collection of pairs that are used to search for a value through a key,
which works as an index that enables to access the value related to it. In π-ADL, values of a
map type map[T1 , T2 ] are pairs < key, value > in which keys of type T1 are associated to values
of type T2 . For example, the declaration
m is map[String, Integer]
π-ADL: A Formal Description Language for Software Architectures
8
Table 3: Collection types defined in π-ADLFO−CT .
Type
Syntactic representation Definition
Map
map[T1 , T2 ]
Map of elements associating a key of type T1 with values of type T2
Set
set[T ]
Unordered collection of elements of type T with no
duplicates
Sequence sequence[T ]
Ordered collection of elements of type T that can have
duplicates
refers to the declaration of a map m whose keys are string values associated to integer values.
New values can be stored under keys of a map by using the add operation. For the map m
exemplified above, the instruction
m add [“A”, 1]
stores the integer value 1 in m under the string key A.
An element stored under a given key can be removed from a map by using the remove
operation. For the map m exemplified above, the instruction
m remove @(“A”)
removes the respective element stored in m under the string key A.
Set. In π-ADL, a set is an unordered collection of elements of the same type T and with
no duplicates. Values within a set type set[T ] are values v1 , v2 , ..., vn in which each value vi
pertaining to such a set is of type T . For example, the declaration
s is set[Integer]
refers to the declaration of a set s of integer values.
New values can be added to a set by using the add operation. For the set s exemplified
above, the instruction
s add [1]
adds the integer value 1 to s.
A given element can be removed from a set by using the remove operation. For the set s
exemplified above, the instruction
s remove [1]
removes the integer value 1 from s.
Sequence. In π-ADL, a sequence is an ordered collection of elements of the same type T
that can have duplicates. Values within a sequence type sequence[T ] are values v1 , v2 , ..., vn
in which each value vi pertaining to such a sequence is of type T . For example, the declaration
q is sequence[Integer]
π-ADL: A Formal Description Language for Software Architectures
9
refers to the declaration of a sequence q of integer values.
New values can be added to a sequence by using the add operation. For the sequence q
exemplified above, the instruction
q add #[1]
adds the integer value 1 to q, sequentially to the already existing elements.
A given element can be removed from a sequence by using the remove operation. For the
sequence q exemplified above, the instruction
q remove #0
removes the first integer value (indexed as 0) from q. As the elements of a sequence are disposed in a given order, an integer index the can be used to access the elements of the sequence.
Therefore, the index 0 refers to the first element, 1 to second one, and so on.
2.2.4
Behavior types
Besides the connection abstraction, the π-ADLB layer provides behavior constructs to
represent the internal behavior of architectural elements, which make use of connections to
send/receive values (see Section 2.1). Behaviors defined in π-ADL come from existing constructs provided by π-calculus, in which channels (connections in π-ADL) are used to transmit
values between interacting processes (behaviors of architectural elements in π-ADL). In this
perspective, considering P and Q as processes, c as a channel, and x as a value or name, πcalculus formally defines the following constructs:
• c(x).P denotes an input prefix, a process waiting to read x from c; after receiving x via c,
this process sequentially behaves as P;
• c̄(x).P denotes an output prefix, the inverse operation of the input prefix denoting a process
that waits to write x (previously accepted by some input process) in c; after sending x via
c, this process sequentially behaves as P;
• P | Q denotes a process composition of P and Q, which run in parallel;
• P + Q denotes a process choice, thus behaving as P or Q, and;
• 0 denotes an inert (nil) process, which does nothing (i.e., it has no remaining computation).
Similarly to these basic π-calculus constructs, π-ADL provides the behavior types summarized in Table 4, each one described as follows.
Type declarations. In π-ADL, it is possible to define an alias to an existing type (base or
constructed one) within the scope of a given behavior. As an example, consider the following
instructions:
type Latitude is Real
type Longitude is Real
type GeoCoordinate is tuple[Latitude, Longitude]
10
π-ADL: A Formal Description Language for Software Architectures
Table 4: Summary of the behavior types defined in π-ADLB .
Behavior
Syntactic representation
Action
Type
type s is T
Create an alias s for type T
Output prefix
via c send v
Send value v via connection c
Input prefix
via c receive s : T
Receive value s of type T via
connection c
Conditional prefix
if b do p
Enact prefix p if condition b
is true
Silent prefix
unobservable
Internal action
Choice behavior
choose B1 or B2 . . . or Bn
Choose to execute behavior
B1 or behavior B2 . . . Bn
Composition behavior compose B1 and B2 . . . and Bn Execute behaviors B1 . . . Bn in
parallel
Inaction
done
Nothing to do
The two first instructions create the Latitude and Longitude types1 , which are both defined
by a real value (represented by the Real basic type). In turn, the third instruction creates the
GeoCoordinate type as a tuple composed of values of the Latitude and Longitude types for
representing a geographical coordinate.
Prefixes. Behaviors enact (i.e., run) by performing actions, which are expressed by prefixes.
As shown in Table 4, there are four types of prefixes, namely:
(i) output prefix, which expresses the ability of sending a value v via a connection c;
(ii) input prefix, which expresses the ability of receiving a value v via a connection c;
(iii) conditional prefix, which expresses the ability of enacting a prefix if a given condition is
true (doing nothing otherwise), and;
(iv) silent prefix (expressed as unobservable), which represents an internal, invisible action.
Choice behavior. In π-ADL, a choice behavior expresses the ability of a behavior to execute
alternative sub-behaviors. When one of such sub-behaviors is enacted, the others are no longer
available, i.e., only one of the choice sub-behaviors is executed.
As an example, consider the following instructions:
choose {
via input receive v : Integer
via output send (v+1)
} or {
via alt receive s : Integer
db add [s]
}
1 Conventionally,
names, for example.
alias names for types shall start with capital letters in order to differentiate them from variable
π-ADL: A Formal Description Language for Software Architectures
11
This choice behavior is expressed by two alternative options: (i) receiving an integer value v
via the input connection and then sending the increment of v via the output connection, or; (ii)
receiving an integer value s via the alt connection and then adding it to the db set.
It is noteworthy mentioning that when more than one sub-behavior is eligible to be enacted at the same time, the selection criteria for choosing the block that will be executed is nondeterministic. These criteria are not defined in the language, but at the underlying implementation of the behavior.
Composition behavior. A composition behavior expresses the ability of a behavior to parallel compose sub-behaviors, each one independently proceeding from the others. In addition,
the sub-behaviors within a composition behavior can interact among each other via shared connections, e.g., when a behavior sends a value to another executing behavior via an attached
connection. The composition behavior of π-ADL corresponds to the concurrent constructions
in π-calculus and each sub-behavior will be executed in a separate execution thread, in parallel.
As an example, consider the following instructions:
compose
via
via
} and {
via
}
{
input receive v : Integer
output send (v+1)
signal send true
In this composition behavior, an integer value v is received via the input connection and its
increment is sent via the output connection, simultaneously to the sending of the Boolean value
true via the signal output connection.
As another example, consider the following instructions:
compose {
via x send v
} and {
via x receive y
}
The sub-behaviors of this composition behavior interact with each other via the connection x;
the first one sends a value v which is received by the second sub-behavior as the value y.
Inaction. Finally, the inaction behavior (expressed by the done keyword) represents a behavior that does not execute any action.
2.3
Specifying architectural elements in π-ADL
A software architecture is described in π-ADL in terms of components, connectors, and
their composition in order to form the architecture of the system. These elements are the abstractions that are part of an architecture description in π-ADL, which is composed of a set of
components and connectors and exactly one architecture declaration (see Appendix A).
As detailed in Appendix A, components and connectors are specified exactly in the same
way except for the keyword used to specify the type of the architectural element (component
or connector). These elements have an identifier as an unique name for them and they can
optionally take a list of parameters (in the form name : type) as input, separated by commas and
between parentheses. Moreover, they can have a sequence of the following instructions.
π-ADL: A Formal Description Language for Software Architectures
12
Type declarations. Zero or more types constrained to the scope of the architectural element can be declared in the form type s is T , in which s is an identifier2 and T is an existing
type (base, constructed or declared one). For example, the type declaration
type Key is String
creates a type named Key having the string type as the underlying type.
Connection declarations. Zero or more typed connections constrained to the scope of
the architectural element can be declared in the form connection c is d(T ), in which c is
an identifier, d is the direction of the connection, and T is an existing type (base, constructed
or declared one). Two directions are available for declaring a connection, namely in, for input
connections, and out, for output connections. For example, the instructions
connection x is in(String)
connection y is out(Boolean)
declare an input connection x for receiving string values and an output connection y for sending
Boolean values.
Variable declarations. Zero or more typed variables constrained to the scope of the architectural element can be declared in the form s is location[T ], in which s is an identifier
and T an existing type (base, constructed or declared one). For example, the instruction
a is location[Real]
declares a variable a of real type.
Protocol declaration. Protocols are used within the specification of architectural elements in order to enforce the value types that must be transmitted via a connection (in accordance to its declaration) and the order in which the sending/receiving operations must be
performed. A protocol (whose declaration is optional) is declared as a set of connection actions,
which specify the action to be performed by the connection (send or receive) and the type
of the values that will be transmitted via the connection. Furthermore, protocol declarations
can make use of multiplicity symbols to specify how many times the connection actions can
be performed: an asterisk character (*) is used to specify that a given action (or set of actions)
is performed zero or more times, whereas the plus character (+) is used to specify that a given
action (or set of actions) is performed at least once. Finally, it is also possible to specify alternative actions by using the pipe character (|), so that A | B indicates that either action (or group
of actions) A or action (or group of actions) B can be performed. As an example, consider the
following protocol declaration:
protocol is {
((via a receive Integer | via b receive Integer)
via c send Integer)*
}
This protocol enforces receiving an integer value via connection a or via connection b and
then sending an integer value via connection c. The asterisk character after the surrounding
parentheses specifies that all of these actions (receiving via a or via b then sending via c) can
be performed multiple times. When declaring a protocol, the specification of the multiplicity of
the actions (by using the asterisk or the plus characters) is mandatory.
2 Conventionally,
names, for example.
alias names for types shall start with capital letters in order to differentiate them from variable
π-ADL: A Formal Description Language for Software Architectures
13
Behavior declaration. Exactly one behavior must be mandatorily declared in order to
specify the behavior of the architectural element. Such a behavior comprises a set of instructions, as defined in previous sections:
• type declaration;
• variable declaration;
• collection projection;
• assignment, which can be an assignment of an expression to a variable or addition/removal of elements of a collection variable;
• function declaration with respective identifier, parameters, and return type;
• function call, with respective identifier and parameters;
• prefix (input, output, conditional or silent prefix);
• choice behavior;
• composition behavior;
• recursive behavior call, or;
• inaction.
Similarly to components and connector abstractions, the specification of the architecture
of the system itself is declared with its respective keyword (architecture), an unique identifier, and an optional list of parameters to be taken as input (separated by commas and between
parentheses). However, such a specification is different as it comprises two basic elements, namely a set of element instances and a set of unifications. The element instances are contained
within a composition behavior and are of the form i is E, in which i is the instance identifier
and E is the identifier of an architectural element (component or connector)3 . In turn, the unifications are the means of passing values from an output connection of an element to an input
connection of another. These unifications are of the form co ::E1 unifies ci ::E2 , in which
co is an output connection of the element E1 and ci is an input connection of the element E2 .
Therefore, values can be transmitted from E1 to E2 (their behaviors) via such connections.
2.4
An illustrative example
In order to didactically illustrate how to make an architectural description in π-ADL, consider the simple client-server architecture depicted in Figure 3. This architecture is composed
of two components (one client and one server) linked through one connector (link). The client
component sends a message to the server component, which receives and processes the request.
Next, the server component sends a message back to the client component, which in turn receives and processes the response. All of these interactions take place via the link connector
between the client and server components.
Figure 4 shows the π-ADL description of the Client component, which is declared with
two connections, namely call, an output connection for sending requests (line 2), and wait,
3 If
an architectural element requires input parameters (according to its declaration as an abstraction), the respective parameters must be provided when declaring an instance of such an element.
14
π-ADL: A Formal Description Language for Software Architectures
call
toServer
fromClient
request
Server
Link
Client
wait
toClient
fromServer
reply
Legend:
Component
Output connection (outwards)
Connector
Input connection (inwards)
Uni cation
Figure 3: Graphical representation of a simple client-server architecture.
an input connection for receiving responses (line 3). The protocol of this component (lines 4
to 7) enforces sending integer values via the call connection or receiving integer values via
the wait connection, operations that can be performed multiple times. Besides the declaration
of the integer variable i for storing values (line 9), the behavior of the Client component
encompasses a choice behavior (line 10) with two sub-behaviors available as choices. In the
first option, the value of the variable i is sent via the call connection (output prefix, line 11).
In the second behavior option: (i) a function called storeValue is declared as receiving an
integer as input parameter and assigning it to i (lines 14 to 16); (ii) an integer r is received via
the wait connection (input prefix, line 17), and; (iii) the storeValue function is called passing
such a received value as input, in order to store it internally to the component (line 18). After
executing their respective instructions, each sub-behavior recurses (what is expressed by the
behavior call behavior() in lines 12 and 19), i.e., it continues being executed.
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
component Client is abstraction() {
connection call is out(Integer)
connection wait is in(Integer)
protocol is {
(via call send Integer |
via wait receive Integer)*
}
behavior is {
i is location[Integer]
choose {
via call send i
behavior()
} or {
storeValue is function(v : Integer) {
i = v
}
via wait receive r : Integer
storeValue(r)
behavior()
}
}
}
Figure 4: π-ADL description of the Client component.
Similarly, Figure 5 shows the π-ADL description of the Server component, which is
declared with two connections, namely request, an input connection for receiving requests
(line 2), and reply, an output connection for sending responses (line 3). The protocol of this
π-ADL: A Formal Description Language for Software Architectures
15
component (lines 4 to 7) enforces receiving an integer value via the request connection and
then sending an integer value via the reply connection, so that these actions are sequentially
performed and they can be performed multiple times. Next, the behavior of the Server component encompasses: (i) the declaration of the increment function, which receives an integer as
input parameter and returns its increment by 1 (lines 9 to 11); (ii) receiving an integer i via the
request connection (line 12), and; (iii) sending the result of the call to the increment function
(with i as input parameter) via the reply connection (line 13). After executing these respective
instructions, the behavior continues being executed (behavior call, line 14).
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
component Server is abstraction() {
connection request is in(Integer)
connection reply is out(Integer)
protocol is {
(via request receive Integer
via reply send Integer)*
}
behavior is {
increment is function(v : Integer) : Integer {
return (v+1)
}
via request receive i : Integer
via reply send increment(i)
behavior()
}
}
Figure 5: π-ADL description of the Server component.
Figure 6 shows the π-ADL description of the Link connector, which is declared with
four connections: (i) fromClient, an input connection for receiving requests from the client
(line 2); (ii) toServer, an output connection for sending requests to the server (line 3); (iii)
fromServer, an input connection for receiving responses from the server (line 4), and; (iv)
toClient, an output connection for sending responses to the client (line 5). The protocol of
this connector specifies two alternative groups of actions: (i) receiving an integer value via the
fromClient connection and then sending an integer value via the toServer connection (lines
7 and 8), or; (ii) receiving an integer value via the fromServer connection and then sending
an integer value via the toClient connection (lines 9 and 10). The behavior of this connector
comprises a choice behavior (line 12) with two sub-behaviors available as choices. In the first
option, an integer value x is received via the fromClient connection and sent via the toServer
connection (lines 14 and 15), thus indicating a message flow from the client to the server; in turn,
the second option specifies that an integer value y is received via the fromServer connection
and is sent via the toClient connection (lines 18 and 19), thus indicating a message flow from
the server to the client. After executing their respective instructions, each sub-behavior recurses
(lines 16 and 20).
Finally, Figure 7 shows the π-ADL description of the ClientServer architecture. This
architecture is specified as a composition with one instance of the Client component (line 4),
one instance of the Link connector (line 5), and one instance of the Server component (line
6). The attachments of these architectural elements take place through four unifications:
(i) the call output connection of the component c is bound to the fromClient input connection of the l connector (line 8), thus representing a message flow from the client to the
link;
π-ADL: A Formal Description Language for Software Architectures
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
16
connector Link is abstraction() {
connection fromClient is in(Integer)
connection toServer is out(Integer)
connection fromServer is in(Integer)
connection toClient is out(Integer)
protocol is {
((via fromClient receive Integer
via toServer send Integer) |
(via fromServer receive Integer
via toClient send Integer))*
}
behavior is {
choose {
via fromClient receive x : Integer
via toServer send x
behavior()
} or {
via fromServer receive y : Integer
via toClient send y
behavior()
}
}
}
Figure 6: π-ADL description of the Link connector.
(ii) the toServer output connection of the connector l is bound to the request input connection of the s component (line 9), thus representing a message flow from the link to the
server;
(iii) the reply output connection of the component s is bound to the fromServer input connection of the l connector (line 10), thus representing a message flow from the server to
the link, and;
(iv) the toClient output connection of the connector l is bound to the wait input connection
of the c component (line 11), thus representing a message flow from the link to the client.
Therefore, these unifications between connections of the architectural elements enable to transmit data from client to server and vice-versa via the connector.
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
architecture ClientServer is abstraction() {
behavior is {
compose {
c is Client()
and l is Link()
and s is Server()
} where {
c::call unifies l::fromClient
l::toServer unifies s::request
s::reply unifies l::fromServer
l::toClient unifies c::wait
}
}
}
Figure 7: π-ADL description of the ClientServer architecture.
π-ADL: A Formal Description Language for Software Architectures
3
17
Tool support for π-ADL architecture descriptions
One of the concerns regarding the usefulness of an ADL is directly related to the tools
that it provides for supporting the activities encompassed by an architecture-driven software
development approach, i.e., architectural description, analysis, code generation, and evolution
[34, 42]. In fact, Dashofy et al. [21] point out that tool support is especially vital for the successful use of any ADL since architecture descriptions persist throughout the development lifecycle
and evolve along with the described software system, so that ADL tools play an important
role for creating, analyzing, and maintaining these documents over time. Furthermore, a recent
survey about ADLs in the industry context [33] has revealed the importance of ADL tools in
this scenario, although few description languages for software architectures are supported by
satisfactory tools. Among the interesting findings, some requirements for such tools were identified in this survey, such as provisioning both textual and graphical comprehensive notations,
aligning software architecture descriptions with their respective implementation, supporting architectural analysis, meaningful communication/documentation, simplicity, intuitiveness, and
usability.
In the context of the ArchWare European Project (in which the π-ADL language was
initially conceived), an open-source toolset was developed in order to support formal description, analysis, refinement, code generation, and evolution of software architectures [40, 42]. All
together, these tools enable the compilation of architectural models into their executable representations as well as the formal analysis and evolution of such models. However, by taking into
account evolutions in the π-ADL language itself, as well as requirements of new generation
software systems (such as large-scale, distribution, concurrency, and dynamicity), a new tool
support for π-ADL started to be developed. In a first step, a textual editor based on the Eclipse
platform [2] was developed for assisting architects in software architecture descriptions by using
the π-ADL language. Furthermore, such a new tool support enables to automatically generate
implementation code in Go [7], a general-purpose programming language that has shown to be
suited for addressing the construction of scalable distributed systems.
This section presents the developed π-ADL textual editor (Sections 3.1) and the facilities
for generating implementation code in the Go programming language (Section 3.2), publicly
available for download in [6].
3.1
3.1.1
The π-ADL textual editor
Background
The choice of using an Eclipse-based development environment to construct the new πADL tools was motivated by its widespread use for developing software and good support in
terms of open-source tools and frameworks. Moreover, as Eclipse is based on the Java programming language, it takes advantage of the portability capabilities provided by such a language,
thus enabling it to be used in multiple operating systems and hardware platforms.
Among the most relevant Eclipse frameworks, the Eclipse Modeling Framework (EMF)
[3] is an open-source framework used for model-driven software development and it has been
the cornerstone of related technologies and other frameworks. EMF provides facilities for generating code and building tools and applications based on structured models. The typical workflow for these tasks by using the EMF facilities encompasses the construction of the models,
code generation and customization, and the implementation of the application itself. Therefore,
EMF can be seen as the the middle ground between abstract models and concrete programming
artifacts.
π-ADL: A Formal Description Language for Software Architectures
18
The (meta)model used for representing models in EMF is Ecore. In an Ecore model, classes are model entities with attributes (each one with a name and a data type) and relationships
(references) among each other. From these elements, EMF enables to use instances of the classes
defined in Ecore for describing a model of the system and then generating its respective code.
In this perspective, all frameworks, tools, and applications built upon EMF have an underlying
model based on the Ecore (meta)model.
In the last years, EMF has been the basis for the construction of several tools and frameworks for developing software. Among them, Xtext [10] is an open-source, highly customizable, sophisticated framework for developing domain-specific languages (DSLs), i.e., programming or specification languages that target a specific domain problem or purpose. Xtext
covers all aspects of a complete language structure by encompassing parsing the textual model
written in such a language, possibly interpreting it and/or generating code from it in another
language. Moreover, this infrastructure is fully integrated with the Eclipse environment, thus
taking advantage of typical, useful IDE features such as editor with syntax highlighting, code
completion, error markers, automatic building infrastructure, etc. Therefore, as π-ADL can be
broadly understood as a DSL designed to describe software architectures, it can take advantage
of the facilities provided by Xtext to develop an infrastructure for assisting software architects
in the use of the language, as further described in next sections.
3.1.2
Xtext-based textual editor for π-ADL
The π-ADL grammar. The main artifact used as input by Xtext for generating the π-ADL
infrastructure is a grammar specification in the Extended Backus-Naur Form (EBNF) [29]. This
grammar is a set of production rules (or simply rules) that describe the form of the elements that
are valid according to the language syntax. When compiling this grammar specification, Xtext
generates the respective Ecore metamodel and a Java class corresponding to each production
rule.
Figure 8 shows an excerpt of the π-ADL grammar4 that was specified based on
the π-ADL EBNF production rules described in Appendix A. Rules start with their respective name followed by a colon and end with a semicolon. In Figure 8, line 1 indicates that the current grammar reuses an Xtext grammar with common terminal symbols
(org.eclipse.xtext.common.Terminals), such as identifiers (ID) and integer numbers. The
ArchitectureDescription rule (lines 5 to 8) corresponds to an architecture description itself, which is composed of a set with zero or more architectural elements (represented by the
ArchitecturalElement rule) and exactly one architecture declaration (represented by the
Architecture rule). In turn, the ArchitecturalElement rule (lines 10 to 12) define that
an architectural element can be either a component or a connector, respectively defined by the
Component and Connector rules. Finally, the syntax of the specification of a component is defined by the Component rule (lines 14 to 24). A component is declared by using the component
keyword and it comprises the name attribute, which is represented by the ID terminal defined in
the Xtext terminals grammar. Optionally, it can also take a list of parameters (each one defined
by the Parameter rule and separated by commas) as input, between parentheses. Within the
definition of this architectural element (delimited by braces), one can have in sequence:
• declaration of zero or more types defined by the TypeDeclaration rule (line 18);
• declaration of zero or more connections defined by the ConnectionDeclaration rule
(line 19);
4 The
complete π-ADL grammar specification is publicly available in [6].
π-ADL: A Formal Description Language for Software Architectures
19
• declaration of zero or more variables defined by the VariableDeclaration rule (line
20);
• optional declaration of a protocol defined by the ProtocolDeclaration rule (line 21),
and;
• declaration of exactly one behavior defined by the BehaviorDeclaration rule (line 22).
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
grammar fr.irisa.archware.PiADL with org.eclipse.xtext.common.Terminals
generate piADL “http://www.irisa.fr/archware/PiADL”
ArchitectureDescription:
archElements+=ArchitecturalElement*
architecture=Architecture
;
ArchitecturalElement:
Component | Connector
;
Component:
‘component’ name=ID ‘is’
(‘abstraction()’ | ‘abstraction(’
(parameters+=Parameter (‘, ’ parameters+=Parameter)*)? ‘)’) ‘{’
typeDecl+=TypeDeclaration*
connections+=ConnectionDeclaration*
varDecl+=VariableDeclaration*
protDecl=ProtocolDeclaration?
behavior=BehaviorDeclaration
‘}’
;
Figure 8: Excerpt of the π-ADL grammar specified in the Xtext framework.
Figure 9 shows a partial diagram of the π-ADL metamodel representing the elements
syntactically defined in Figure 8. This Ecore-based metamodel is automatically generated from
the grammar specification5 .
It is interesting to highlight how models are related to each other in this context. An
architecture description in π-ADL is a model of a concrete software architecture. This model
conforms to the π-ADL metamodel (Figure 9), so that each element that composes the structure
of the described architecture is an instance of the abstract entities (classes) defined in such
a metamodel. In turn, the π-ADL metamodel itself conforms to the Ecore metamodel, i.e.,
Ecore is hereby a metametamodel (metamodel of a metamodel). Therefore, each class defined
in the π-ADL metamodel is an instance of the abstract entities (EClasses) defined in the Ecore
metamodel.
5 Although
it is possible to generate an Ecore metamodel of the language from its grammar specification, some
people do not regard this practice as a good one since metamodels are at a higher abstraction level than the concrete
syntax model. In the case of π-ADL, it was opted starting from the grammar specification and then generating the
metamodel because such a specification was almost complete from previous versions of the language, so that it
was reused.
π-ADL: A Formal Description Language for Software Architectures
20
Figure 9: Partial diagram of the generated π-ADL Ecore-based metamodel.
Automatic generation of the π-ADL infrastructure. In order to generate the π-ADL language infrastructure, Xtext uses a script written in the Modeling Workflow Engine (MWE2)
DSL to configure the generation of its artifacts. In particular, this script (also automatically
created by Xtext) is used by the framework to derive a specification from the grammar that is
compatible with the parser generator that will be used for generating the parser of the language.
When running it, Xtext automatically generates the following artifacts depicted in Figure 10:
(i) a Java implementation of a parser, which is automatically generated by the ANTRL parser
generator [1] and will be responsible for the syntactic analysis of the architecture textual
description;
(ii) an Ecore metamodel with the abstract entities of the language and the relationships among
them;
(iii) a code generator, which is used to generate code from the architecture textual description,
and;
(iv) an Eclipse-based code editor for assisting the textual description.
In addition, Xtext creates an abstract syntax tree (AST) from the input textual model for representing the structure of the parsed model, as well as it generates the respective Java classes to
persist such an AST.
It is noteworthy mentioning that although the Java programming language can be used for
customizing the generated artifacts, Xtext fosters the use of Xtend [9], a fully Java-interoperable
programming language that features a more compact, easier to use syntax, as well as advanced
features such as type inference and lambda expressions. As the AST model will need to be continuously traversed throughout the implementation of a DSL, Xtend provides useful mechanisms
for straightforwardly doing this while being easy to use and enabling to write better readable
code. Moreover, as Xtend programs are translated into Java code, Xtend code can access all of
the Java libraries, thus enabling these languages to seamlessly coexist.
21
π-ADL: A Formal Description Language for Software Architectures
Language project
Ecore metamodel
(.ecore)
p-ADL Grammar
Xtext generator
(.xtext)
(.mwe2)
ANTRL-based parser
(.java)
Legend:
manual, required
generated, required
generated, optional
Code generator
(.xtend)
Validator
(.xtend)
Unit test
Editor
Testing classes (.java)
Navigation
Outline
Code completion
Syntax highlighting
Error marking
Automatic building
Testing project
Editor (UI) project
Figure 10: Artifacts generated by Xtext from the π-ADL grammar specification.
Validations. Once the architecture description is checked as correct by the parser, it might still
have errors as its overall correctness cannot always be determined during the parsing procedure,
i.e., a semantic analysis must be performed over the current model. For this purpose, Xtext
provides means of constructing validators. In the Xtext framework, validators are classes that
contain methods (validation rules) implementing additional constraint checks over the abstract
elements of the current model. Xtext provides some default validators (e.g., for checking that
two entities have the same name), but it enables developers to implement custom validators by
extending the base validation classes that come with the framework.
Xtext performs validation by invoking each Xtend method annotated with the @Check
directive and passing all instances that have a compatible runtime type to each method. In
the body of such methods, the semantic checks are implemented for the element passed as
parameter. If a semantic check fails, it is possible to trigger warning or error messages that will
appear in the textual editor while making the architecture description. Table 5 summarizes the
main error/warning conditions checked by the implemented validation methods.
Interpreting expressions. In order to describe the behavior of components and connectors, a
software architect can make use of expressions that are similar to the ones used in programming
languages, such as logical, relational, equality, and arithmetic expressions. Determining the data
types handled by such expressions is important for ensuring that an expression value sent via a
connection is the one expected, i.e., its type is equal to the type specified when declaring such
a connection. However, type checking cannot be performed during parsing (thus requiring a
semantic analysis) and expressions are resolved at runtime, i.e., their value is calculated while
they are described. As Xtext is mainly concerned with syntactic analysis and does not support
expression resolution, an interpreter and a validator were developed for handling expressions
in π-ADL architecture descriptions.
As the first step, a type provider implemented as an Xtend class was developed aiming
at providing the type of a given expression. This class contains a set of typeOf methods that
22
π-ADL: A Formal Description Language for Software Architectures
Table 5: Error/warning conditions checked by the implemented validation methods.
Target element
Warning/error condition
Severity
Architecture
description
Architecture name is equal to the name of a component or
connector
Warning
Architectural
element
Architectural element with no specified protocol
Warning
Architectural
element
Inconsistencies between connection declarations and protocol specifications (data type and/or direction)
Error
Architectural
element
Protocol with undeclared connections
Error
Architectural
element
Empty behavior
Warning
Architectural
element
Names of declared types starting lower cased
Warning
Architectural
element
Inconsistencies between prefixes within behaviors and
connection declarations (data type and/or direction)
Error
Assignment
Assignment to undeclared variable
Error
Function call
Call to undeclared functions
Error
Function
declaration
Function declared with a return type and with no return
statement in its body
Warning
Architecture
Architectural element instances with equal names
Error
Architecture
Instance of undeclared architectural element
Error
Architecture
Architecture with no unifications between architectural
elements
Warning
Architecture
Connection elements in unification are both components
or connectors
Error
Architecture
Unification is not from an output connection to an input
connection
Error
Architecture
Unification must encompass connections of the same data
type
Error
Architecture
Unification accessing undeclared connection
Error
return the type of a given expression received as input. Four basic situations are possible when
determining the type of an expression:
(i) when the type of the expression does not depend upon the types of its sub-expressions –
negation, logical, equality, and relational expressions will always return a Boolean value,
whereas atomic values have their types directly determined by their literals;
π-ADL: A Formal Description Language for Software Architectures
23
(ii) when the type of the expression depends upon the operation and its operands – in this
case, other situations are possible:
• the division operation will always return a real value, independently of the operands;
• the multiplication, modulus, and subtraction operations will return a real value if one
of the operands is of this type or an integer value otherwise;
• the sum operation will return a string value if one of the operands is a string, a real
value if one of them is real, or an integer value otherwise.
(iii) when the expression is an assignment expression – the type of the expression is determined
by the declared type of the variable to which the value will be assigned;
(iv) when the expression is a function call – the type of the expression is determined by the
return type specified when declaring the function.
Next, the expression interpreter of π-ADL was implemented as another auxiliary Xtend
class. This interpreter contains a method called interpret that receives an expression as input
and determines its type by using the typeOf methods implemented in the type provider class.
Therefore, after identifying the atomic values of the operands and converting them to conventional Java primitive types, the interpretation method performs the respective operations given
by the operands, similarly to what is done when evaluating an expression by using a typical
programming language.
Finally, the expression validator of π-ADL was implemented as another Xtend class in
order to perform the semantic type checking for expressions. The methods of this class were
annotated with the @Check directive and then called at runtime in conjunction with the validation methods that check the conditions shown in Table 5. Table 6 summarizes the main error
conditions checked by the implemented expression validation methods. All of these methods
trigger error messages when their respective semantic checks fail.
Features of the π-ADL text editor. Some interesting features provided by Xtext to the generated π-ADL text editor (see Figure 11) are:
• error and warning alerts while describing the architecture, an useful feature that enables
architects to early detect and fix errors and potential problems on such a description, thus
saving time and mental effort to correct them;
• syntax highlighting, which is useful for distinguishing keywords (reserved words) of the
language from identifiers that are allowed to be used, for example;
• content assist (accessed with the Ctrl + Space bar keyboard shortcut), which provides
suggestions on how to complete a given statement/expression based on the syntactic rules,
and;
• automatic build on save, which enables to automatically generate code from the architecture description (if it is correct according to the syntactic and validation rules) when it is
saved in the language editor.
π-ADL: A Formal Description Language for Software Architectures
24
Table 6: Error conditions checked by the implemented expression validation methods.
Target expression
Error condition
Negation expression
Operand is not a Boolean value
Logical expression
Both operands are not Boolean values
Equality expression
Both operands are not Boolean values
Relational expression
Both operands are not of the same type or they are Boolean
values
Multiplication, division,
and modulus operations
Both operands are not numeric values
Minus operation
Both operands are not numeric values
Sum operation
Both operands are neither numeric nor string values
Variable assignment
Type of the value to be assigned is not equal to the type of the
variable (defined when declaring it)
Conditional prefix
Type of the guard is not Boolean
Conditional statement
(if/then/else)
Type of the guard is not Boolean
While loop
Type of the condition is not Boolean
For loop
Type of the stop condition is not Boolean
3.2
Generation of implementation code from architecture descriptions
According to Medvidovic and Taylor [34], the ultimate goal of any software design and
modeling endeavor is to produce the executable system. An elegant architectural model is of
limited value unless it can be converted into a running application, and doing this manually
might result in many problems in terms of consistency and traceability between an architecture
and its implementation. Therefore, the provision of ADL tools able to assist the production
of source code is highly desirable, if not imperative. Moreover, the automatic instantiation of
a software system from its respective architecture description fosters the management of the
transition from system design to implementation [19].
Georgas et al. [23] point out that a good, well-analyzed architectural design is useless
unless there is a clear mapping between this architecture and its implementation. The less complete or automated this mapping, the more opportunity there is for an architectural drift, a phenomenon in which the system’s implementation gradually diverges from its intended design.
Furthermore, as software architectures are typically defined independently from implementation, most existing ADLs are disconnected from the runtime level, thus entailing mismatches
and inconsistencies between architecture and implementation mainly as the architecture evolves.
Specifically with respect to the π-ADL description language, the π-ADL.NET Project
[44] was proposed few years ago as the result of the integration of π-ADL with the Microsoft
.NET Framework [5]. In π-ADL.NET, formal architecture descriptions in π-ADL are compiled to CIL (Common Intermediate Language), thus resulting in a code that is able to access
the existing resources provided by the .NET platform. By enabling the execution of the architecture description, π-ADL.NET supports runtime analysis of the concrete architecture and it
π-ADL: A Formal Description Language for Software Architectures
25
Figure 11: Screenshot of the Eclipse-based π-ADL textual editor.
seeks to preserve architectural integrity of the system at the implementation level. However,
despite its intention of bringing a formally founded ADL to an implementation platform, the
main limitation of π-ADL.NET that makes it not well suited for new generation software systems regards the lack of counterparts when performing the mappings from π-ADL to CIL or
the .NET platform. For instance, in π-ADL, behaviors and abstractions communicate through
connections, which have no corresponding elements in CIL, so that a .NET class was developed by hand to emulate π-ADL connections, with requisite threading and synchronization
functionality. Furthermore, π-ADL.NET also lacks of support for distribution, thus becoming
a constraint when implementing distributed systems, a typical feature of the today’s software
systems.
Considering these limitations faced by π-ADL.NET, a new support for generating implementation code from π-ADL architecture descriptions had to be provided. In this context,
Go [7] was chosen as the target programming language because it is an easy general-purpose
language designed to address the construction of scalable distributed systems and handle multicore and networked computer architectures, as required by new generation software systems.
Furthermore, the integration of π-ADL with Go is mainly fostered by their common basis on the
π-calculus process algebra and the straightforward relationship between elements of the languages, such as the use of connections in π-ADL and channels in Go as means of communication
between concurrent processes.
This section addresses how generating source code in the Go programming language from
π-ADL architecture descriptions. Section 3.2.1 presents a brief overview about the Go programming language. In turn, Section 3.2.2 defines the correspondences between the elements
of π-ADL to Go, whereas Section 3.2.3 presents the technical elements used to perform such a
π-ADL: A Formal Description Language for Software Architectures
26
mapping between the languages, as introduced in [16].
3.2.1
The Go programming language
Go is a new general-purpose language that was launched as an internal project at Google,
Inc. in 2007 and became a public open-source project on November 2009. In 2012, Go was
stably released as Go 1 by including a language specification [8], standard libraries and custom
tools, and it is currently in version 1.3, which was released by mid-2014. In the last years, Go
has been used by Google and a variety of commercial and noncommercial organizations. It is
also integrated to the Google App Engine [4], the Google’s cloud-based development platform.
Go was designed to address the construction of new generation large-scale software systems, which are to be efficient, dynamic, and deployed on multicore and networked computer
architectures. In order to achieve these purposes, the language aims to combine the lightweight,
ease of use, and expressiveness of interpreted and dynamically typed languages, such as JavaScript and Python, with the efficiency and safety of traditional statically typed, compiled
languages such as Java. Moreover, it is possible to directly compile even a large Go program
to native code in few seconds. Such a lightning fast compilation is made possible to a small
extent because the language is easy to parse, but mostly due to its dependence management. For
example, consider a source code A depending on another source code B, which in turn depends
upon a third source code C. In a traditional compiled language, A would require the object files
generated from both B and C. However, in Go, everything that C exports is cached in the object file generated from B, so that just the object file generated from B is sufficient to build the
source code A. This management results in considerable speedups for large software systems
with several dependencies.
One of the main features of Go is its lightweight support for concurrent communication
and execution through high-level operations, in contrast to the considerable effort required to
develop, maintain, and debug concurrent programs in mainstream languages such as C++ and
Java. In this perspective, the solution provided by Go is threefold. First, the high-level support
for concurrent programming enables programmers to easily develop concurrent programs. Second, concurrent processing is performed through goroutines, which are lightweight processes
(similar to threads, but lighter), which can be created and automatically load-balanced across the
available processors and cores. Finally, the automatic and efficient garbage collection relieves
programmers of the memory management typically required by concurrent programs.
In Go, goroutines communicate by using typed channels, which are used as means for
sending and receiving values of any type. When a channel communication takes place, the
sending and/or receiving channels (and their respective goroutines) are synchronized at the
moment of the communication [25]. Therefore, explicit locking and other low-level details are
abstracted away, thus simplifying the development of concurrent programs. Furthermore, due
to its theoretical foundations on π-calculus, Go also supports the mobility of channels, i.e.,
channels are seen as first-class objects that can be transported via other channels.
For sake of space, next sections introduce just some elements of Go used in the implementation code generated from architecture descriptions in π-ADL. The interested reader is invited
to refer to [8, 13, 17, 47] in order to check the complete specification of the language, its main
elements, and details about its syntax.
3.2.2
Correspondences between π-ADL and Go
Table 7 summarizes the relationships between the architectural elements of π-ADL and
the elements of Go. Next paragraphs detail only the main correspondences between these lan-
π-ADL: A Formal Description Language for Software Architectures
27
guages as some of them (e.g., conditional statements, control loops, expressions, etc.) are identical and then straightforward.
Table 7: Summary of the correspondences between architectural elements of π-ADL and elements of Go.
π-ADL
Component
Connector
Behavior
Connection
Architecture
Declaration of connections
Unification of connections
Go
Function (goroutine)
Function (goroutine)
Body of function (goroutine)
Channel
Main function
Maps of channels
Channels as parameters to goroutines
Components, connectors, and their behavior. In a π-ADL architecture description, components and connectors are created as abstractions that can be instantiated within the specification
of the architecture. In Go, components and connectors are represented as functions that will
be called as goroutines, thus being equivalent to the notion of communicating processes in πcalculus. Such functions are signed with the respective names of the components and connectors
that they represent and the body of these functions comprises the behavior of such architectural
elements.
Connections. As introduced in Section 2.1, one of the main elements of the π-calculus process algebra are channels, which are used as means of communication and synchronization
between concurrent processes. In π-ADL, connections are used to send and/or receive values
between architectural abstractions (components and connectors) and their behaviors. Similarly
(and then straightforwardly to π-calculus), the typed channels in Go are used to send and/or receive values between processes (goroutines to be synchronized), so that connections in π-ADL
are mapped to channels in Go. The data type of the values transmitted through a channel is the
one specified in the declaration of the connection.
Declaration of connections. In the main function, maps of channels are created in order
to represent the set of connections associated to a component or connector. These <string,
channel> maps use as keys the names of the connections declared in the architecture description
and such keys map to the respective channel object representing the connection. These maps are
used in order to enable rastreability of the connection names when performing the translation
from the architectural description π-ADL to the respective code in Go.
As an example, consider the following excerpts of the π-ADL description of the Client
and Server components and of the Link connector (see Figures 4 to 7) (left), and the respective
Go code regarding these elements (right). The instantiation of the Client and Server components within the ClientServer architecture is codified in Go as the creation of a map of channels
representing the set of connections of these architectural elements. For example, the map representing the instance of the Client component (c) is created with two integer typed channels and
using the names of the connections (call and wait) as keys of this map. The same applies to the
instance of the Server component (s) and to the instance of the Link connector (l).
π-ADL: A Formal Description Language for Software Architectures
component Client is abstraction() {
connection call is out(Integer)
connection wait is in(Integer)
// ...
}
connector Link is abstraction() {
connection fromClient is in(Integer)
connection toServer is out(Integer)
connection fromServer is in(Integer)
connection toClient is out(Integer)
// ...
}
component Server is abstraction() {
connection request is in(Integer)
connection reply is out(Integer)
// ...
}
architecture ClientServer is abstraction() {
behavior is {
compose {
c is Client()
and l is Link()
and s is Server()
}
28
func main() {
c := map[string]interface{}{
“call” : make(chan int64),
“wait” : make(chan int64),
}
l := map[string]interface{}{
“fromClient” : make(chan int64),
“toServer”
: make(chan int64),
“fromServer” : make(chan int64),
“toClient”
: make(chan int64),
}
s := map[string]interface{}{
“request” : make(chan int64),
“reply”
: make(chan int64),
}
}
Unification of connections. In π-ADL, a connection of a component can be attached to
a connection of a connector in order to enable these elements to communicate. In Go, this
unification process takes place by: (i) passing the channels regarding the connections to be
unified as parameters of the functions (goroutines) that represent behaviors of components and
connectors, and then; (ii) passing the contents of the sending channel (output connection) to
the receiving channel (input connection). As an example, consider the following excerpt of Go
code generated from the π-ADL description of the Server component (see Figure 5):
1:
2:
3:
4:
5:
6:
7:
func Server(conn map[string]interface{}, fromc, toc interface{}) {
go func(fromc, toc interface{}) {
if (fromc != nil && toc != nil) {
v, _ := reflect.ValueOf(fromc).Recv()
reflect.ValueOf(toc).Send(v)
}
}(fromc, toc)
In line 1, the Server function receives as parameters (i) a map of channels (conn) representing
the connections declared in the Server component and (ii) the channels representing connections
to be unified with this component (fromc and toc). Next, an internal, anonymous goroutine is
called in order to perform the unification process itself by receiving the value contained into the
fromc output connection (line 4) and then sending this value via the toc input connection (line
5). Therefore, the following call to Server goroutine in the main function
go Server(s, l[“toServer”], s[“request”])
takes as parameters (i) the map of channels regarding the Server instance (s), (ii) the output channel of the l connector (toServer), and (iii) the input channel of the s component
(request), thus meaning that data are being trasmitted from the Link connector to the Server
component. This data transmission is effectively performed by the internal goroutine within the
Server function.
Architecture. The main element of an architectural description is the architecture itself. In
π-ADL, an architecture is specified as a composition of component and connector instances. In
π-ADL: A Formal Description Language for Software Architectures
29
Go, it is represented by the main function (func main), which stands for the entry-point of a
Go program (thus being the first function called when the program executes) and has no parameters and type. In order to create the instances of components and connectors, the goroutines
that represent these architectural elements are called within the main function. As already mentioned, three parameters are provided in such calls, namely the respective map of channels that
represent the connections of the component/connector and the output/input channels associated
to the connections that will be unified to this component/connector.
It is important to highlight that when any input connection of a component/connector is
not being unified with any output connection of another component/connector, a nil unification
takes place, i.e., null values are passed as second and third parameters in the goroutine call. For
instance, the following goroutine call in the main function
go A(c, nil, nil)
means that an input connection of the A element (third parameter) is not being unified with any
output connection of another element (second parameter). As the values of these parameters
are null, the internal goroutine within the A function (responsible for the unification operation
itself) is not executed since it checks whether both channels given as parameters are not null.
Basic, constructed, and collection types. As presented in Sections 2.2.1 to 2.2.3, π-ADL
provides three data types: (i) basic types, which are used to express atomic values; (ii) constructed types, which are composite types constructed upon the basic types, and; (iii) collection
types, which are types representing collections based on the previous basic and constructed value types. Table 8 summarizes the mappings from these types defined in π-ADL to data types
in Go.
As also introduced in Section 2.2.1, π-ADL also provides a special basic type named Any,
which works as a generic type in the language, thus admitting values of any type. For similar
purposes, this type is mapped to empty interfaces (interface{}), which are means of generic
typing in Go. As empty interfaces do not have defined methods, any type is able to satisfy these
interfaces.
Behavior types. Table 9 summarizes the mappings from the behavior types defined in π-ADL
(see Section 2.2.4) to Go.
3.2.3
Code generation procedure
As described in Section 3.1, the Xtext framework uses the π-ADL grammar specification
to automatically generate the entry point for implementing a code generator. The implementation of this code generation consists of an Xtend class whose methods are used for translating the abstract elements defined in the π-ADL metamodel to their respective implementation.
Therefore, each method in the code generator class receives an abstract element of the language
(defined in the abstract syntax tree and according to the π-ADL Ecore-based metamodel) and
generates the respective Go instruction(s) regarding this element based on the correspondences
defined in Section 3.2.2. The code generator Xtend class is publicly available for download in
[6].
Figure 12 depicts the technical elements involved in the generation of source code in the
Go programming language from architecture descriptions in π-ADL. A π-ADL architecture
description is syntactically verified against its grammar specification and it serves as input to
30
π-ADL: A Formal Description Language for Software Architectures
Table 8: Summary of the mappings from data types defined in π-ADL to types in Go.
Type
π-ADL
Syntax representation in Go
Semantics in Go
Basic types
Natural
Integer
Real
Boolean
String
uint64
int64
float64
bool
string
Unsigned integer numbers)
Signed integer numbers
Floating-point numbers
Boolean logical values
Character strings)
Tuple
[x]interface{}
Empty interface array of
length n (n is the number of
composing types)
View
map[string]interface{}
Map whose keys are the labels for the values
Location
var x T
Variable declaration (x is
the variable name and T the
variable type)
Map
map[T1 ]T2
Map with keys of type T1
and values of type T2
Set
map[T ]bool
Map with keys of type T of
the set
Constructed types
Collection types
Sequence []T
Slice (dynamic array) with
elements of type T
the code generator. In turn, the code generator makes use of the implemented validators in order
to semantically check the π-ADL architecture description. Therefore, if such an architecture
description is correct according to the syntactic and validation rules of the language, then the
respective source code in Go is automatically generated with the automatic build capability
provided by the π-ADL textual editor.
4
Application: A flood monitoring system
Wireless sensor networks (WSNs) are composed of motes, which are tiny hardware/software platforms equipped with an embedded CPU, low power wireless networking
capabilities, and simple sensors [48]. Among the large number of real-world applications in
which WSNs have been increasingly employed, an interesting and promising scenario is the
flood monitoring in urban areas. During rainy seasons, floods are challenging to urban centers
traversed by large rivers due to material, human, and economic losses in flooded areas. In order
to minimize such problems, a flood monitoring system can support the monitoring of urban
rivers and create alert messages to notify authorities and citizens about the risks in case of an
imminent flood.
Successful examples of WSN-based flood monitoring systems are the ones used to monitor the River Ribble near Preston, United Kingdom [27], and the one used to monitor the
River Monjolinho in São Carlos, Brazil [28, 48]. These systems are mainly composed of mul-
31
π-ADL: A Formal Description Language for Software Architectures
Table 9: Summary of the mappings from behavior types defined in π-ADL to Go.
π-ADL behavior type
Syntax representation in Go
Semantics in Go
Type
type s T
Declaration of a type s as an alias
for type T
Output prefix
conn[“c”].(chan T ) <- v
Send value v of type T via channel (connection) c
Input prefix
s := <- conn[“c”].(chan T ) Receive value s of type T from
channel (connection) c
Silent prefix
// Unobservable
Comment
Choice behavior
Selection of a block (corresponding to a sub-behavior Bi ) to execute based on receiving/sending
operations over channels (pi )
select {
case p1 :
B1
case p2 :
B2
}
Composition behavior go func() {
B
}()
Inaction
return
Creation and invocation of a goroutine for each sub-behavior B
Empty return
is input of
generates
generates
Code generator
uses
is veri ed with
p-ADL architectural
description
Go source code
generates
p-ADL grammar
Xtext MWE2
generator
generates
p-ADL validator
uses
uses
uses
p-ADL metamodel
conforms to
uses
Expression validator
uses
conforms to
Expression interpreter
Ecore metametamodel
Figure 12: Elements for generating source code in Go from π-ADL architecture descriptions.
tiple motes, which are spread in the proximities of the river and monitor the water level as a
flood risk indicator, and a gateway station, which analyzes such data and then triggers alerts
when a flood condition is detected. As these motes typically use pressure sensors, measured
raw data need to undergo some processing in order to provide the height reached by the water
level (centimeters of water). Moreover, depending on the monitored river area, sensed data are
π-ADL: A Formal Description Language for Software Architectures
32
transmitted in a multihop communication. As a sensor node is typically a resource-constrained
device in terms of power and networking capabilities, the gateway station responsible for receiving data provided by such a sensor may be far and then out of its network coverage area.
Therefore, data sensed by some motes in their respective sites are successively sent to neighbor
sensors that will forward such data to other neighbor sensors until reaching the gateway station,
which will process them. The communications among these elements can take place by using
wireless network connections such as GPRS, IEEE 802.15.4 (ZigBee), Bluetooth, etc. Figure
13 illustrates this flood monitoring system scenario.
Figure 13: Flood monitoring system scenario.
Figure 14 depicts a simplified architecture of a WSN-based flood monitoring system that
is composed of three sensor nodes (S1, S2 and S3), one gateway component (G), and three
connectors linking these components (L1, L2 and L3). In this architecture, water level data are
measured by sensors S1 and S2 and sent to sensor S3 by using the links L1 and L2. In turn, sensor
S3 receive these data and forward them (without any additional processing) to the gateway G
via the link L3. Next paragraphs detail the π-ADL specification of these architectural elements
and their generated implementation in Go.
Sensor component. Figure 15(a) shows the specification of the Sensor component in πADL, which is composed of three connections: (i) the sense input connection is used for receiving raw data measured by the sensor; (ii) the pass input connection is used for receiving data
from a neighbor sensor, and; (iii) the measure output connection is used for sending data.
The behavior of this component encompasses the definition of the convertRawData function, which is responsible for preprocessing sensed raw data by making a unit conversion from
millivolts (as measured by the pressure sensors) to centimeters of water, types declared as ha-
33
π-ADL: A Formal Description Language for Software Architectures
sense
pass
S1
from
measure
L1
to
sense
pass
S3
pass
S2
from
measure
L2
from
L3
measure
to
to
data
sense
G
Legend:
Component
Output connection (outwards)
Connector
Input connection (inwards)
alert
Uni cation
Figure 14: Architecture of the WSN-based flood monitoring system.
ving the Real basic type defined in π-ADL as underlying type. As the implementation of the
convertRawData function may change according to the sensor specifications provided by the
respective manufacturers, it was set as unobservable in this example. Furthermore, such a behavior can proceed through two alternative options, as specified by the choice behavior (choose):
(i) data received via the sense input connection are processed by the convertRawData function and then sent via the measure output connection, or; (ii) data received via the pass input
connection are directly sent (i.e., without any processing) via the measure output connection.
As partially shown in Figure 15(b), this component is implemented in Go by the Sensor
function, which receives as parameters the map of channels representing the set of named connections of this component (conn) and the channels representing the connections to be unified
when calling this goroutine within the main function. The Sensor function also comprises the
declaration of a local function (closure) corresponding to the convertRawData function specified in the behavior of this component. In order to represent the choice behavior for alternative
behavior options, the select instruction is used for selecting the pair of channels according to
the reception of the messages. Therefore, the value to be written to the measure output channel
can be the one received via the sense input channel (sensed data) or the one received via the
pass input channel (data from another sensor).
ZigBee connector. Figure 16(a) shows the description of the ZigBee connector in π-ADL,
which encompasses the input connection for receiving data and the output connection for
sending data. In turn, as shown in Figure 16(b), this connector is implemented in Go by the
ZigBee function, which receives as parameters the map of channels representing the set of
named connections of this connector (conn) and the channels representing the connections to
be unified when calling this goroutine within the main function. In the ZigBee function, the
value received via the input channel is assigned to a variable (m) to be sent via the output
channel.
Gateway component. Figure 17(a) shows the specification of the Gateway component in πADL, which is composed of two connections: (i) the data input connection is used for receiving
34
π-ADL: A Formal Description Language for Software Architectures
component Sensor is abstraction() {
type MV is Real
type CmH2O is Real
connection sense is in(MV)
connection pass is in(CmH2O)
connection measure is out(CmH2O)
protocol is {
((via sense
receive MV | via pass receive CmH2O)
via measure send CmH2O)*
}
behavior is {
convertRawData is function(measure : MV) : CmH2O {
unobservable
}
choose {
via sense receive d : MV
via measure send convertRawData(d)
type CmH2O float64
behavior()
type MV float64
} or {
via pass receive m : CmH2O
func Sensor(conn map[string]interface{},
via measure send m
fromc, toc interface{}) {
behavior()
go func(fromc, toc interface{}) {
}
if (fromc != nil && toc != nil) {
}
v, _ := reflect.ValueOf(fromc).Recv()
}
reflect.ValueOf(toc).Send(v)
(a)
}
}(fromc, toc)
var convertRawData func(measure MV) CmH2O
convertRawData = func(measure MV) CmH2O {
// Empty body (unobservable)
}
select {
case d := <- conn[“sense”].(chan MV):
conn[“measure”].(chan CmH2O) <- convertRawData(d)
Sensor(conn, fromc, toc)
case m := <- conn[“pass”].(chan CmH2O):
conn[“measure”].(chan CmH2O) <- m
Sensor(conn, fromc, toc)
}
}
func main() {
S1 := map[string]interface{}{
“sense”
: make(chan MV),
“pass”
: make(chan CmH2O),
“measure” : make(chan CmH2O),
}
// ...
}
(b)
Figure 15: Description of the Sensor component in π-ADL (left) and its corresponding implementation in Go (right).
data collected by the sensor nodes, and; (ii) the alert output connection is used for sending
alert messages in case of risk of flood. The behavior of this component encompass the definition
of two functions. The calculateHI function calculates the hazard index (HI) [26], which is a
measure that indicates the potential of flood risk based on the water level measures gathered by
the sensors. The HI measure is used by the triggerAlert function in order to determine the
severity of the flood risk and then send a message accordingly. Therefore, data received via the
data input connection are provided as input to the triggerAlert function, which will analyze
the potential of flood risk according to the calculated HI, and then the corresponding message
is sent via the alert connection.
As partially shown in Figure 17(b), this component is implemented in Go by the Gateway
function, which receives as parameters the map of channels representing the set of named connections of this component (conn) and the channels representing the connections to be unified
when calling this goroutine within the main function. The Gateway function also comprises the
π-ADL: A Formal Description Language for Software Architectures
connector ZigBee is abstraction() {
type CmH2O is Real
connection input is in(CmH2O)
connection output is out(CmH2O)
protocol is {
(via input receive CmH2O
via output send
CmH2O)*
}
behavior is {
via input receive m : CmH2O
via output send m
behavior()
}
}
(a)
35
func ZigBee(conn map[string]interface{},
fromc, toc interface{}) {
go func(fromc, toc interface{}) {
if (fromc != nil && toc != nil) {
v, _ := reflect.ValueOf(fromc).Recv()
reflect.ValueOf(toc).Send(v)
}
}(fromc, toc)
m := <- conn[“input”].(chan CmH2O)
conn[“output”].(chan CmH2O) <- m
ZigBee(conn, fromc, toc)
}
func main() {
// ...
L1 := map[string]interface{}{
“input” : make(chan CmH2O),
“output” : make(chan CmH2O),
}
// ...
(b)
}
Figure 16: Description of the ZigBee connector in π-ADL (left) and its corresponding implementation in Go (right).
declaration of local functions (closures) corresponding to the calculateHI and triggerAlert
functions specified in the behavior of this component. Notice that the statements implementing
these functions are identical to the ones used in the description of this component in π-ADL.
WSNFloodMonitoring architecture. Finally, Figure 18 shows the specification of the
WSNFloodMonitoring architecture in π-ADL, which corresponds to the main executable function (main) in Go. In this function, instances of the Sensor and Gateway components (S1, S2,
S3 and G) and of the ZigBee connector (L1, L2 and L3) are created by calling the respective goroutines that represent such elements and their behavior with the respective maps of channels.
The unifications of connections specified within the composition behavior (compose) take place
by passing the channels as the parameters to the goroutines (second and third parameters). For
instance, first call to the ZigBee goroutine unifies the measure connection of the component S1
to the input connection of the connector L1, so that the contents of the output channel are sent
to the input channel. Similarly, the call to the Gateway goroutine unifies the output connection
of the connector L3 to the data connection of the component G.
Although the example system presented in this section is somewhat simple, it can be easily
scaled-up in order to highlight the distribution, concurrency, and dynamicity features addressed
by the ensemble composed of the π-ADL description language and the Go programming language as its underlying implementation:
• In the mapping process from π-ADL to Go, components and connectors are implemented
as goroutines, which are lightweight processes. In this perspective, increasing the number
of architectural elements to be considered in the architecture in order to have a largescale system does not promote a considerable impact mainly due to the efficient execution
π-ADL: A Formal Description Language for Software Architectures
component Gateway is abstraction() {
type CmH2O is Real
connection data is in(CmH2O)
connection alert is out(String)
protocol is {
(via data receive CmH2O
via alert send String)*
}
behavior is {
calculateHI is function(data : CmH2O) : Real {
unobservable
}
triggerAlert is function(measure : CmH2O) : String {
hi is location[Real]
hi = calculateHi(measure)
if (hi > 0 && hi < 0.5) then {
return "Low risk"
} else if (hi >= 0.5 && hi < 1.0) then {
return "Medium risk"
} else if (hi >= 1.0 && hi < 1.4) then {
return "High risk"
} else {
return "Very high risk"
}
}
via data receive d : CmH2O
via alert send triggerAlert(d)
behavior()
}
}
36
func Gateway(conn map[string]interface{},
fromc, toc interface{}) {
go func(fromc, toc interface{}) {
if (fromc != nil && toc != nil) {
v, _ := reflect.ValueOf(fromc).Recv()
reflect.ValueOf(toc).Send(v)
}
}(fromc, toc)
var calculateHI func(data CmH2O) float64
calculateHi = func(data CmH2O) float64 {
// Empty body (unobservable)
}
var triggerAlert func(measure CmH2O) string
triggerAlert = func(measure CmH2O) string {
var hi float64
hi = calculateHI(measure)
if (hi > 0 && hi < 0.5) {
return "Low risk"
} else if (hi >= 0.5 && hi < 1.0) {
return "Medium risk"
} else if (hi >= 1.0 && hi < 1.4) {
return "High risk"
} else {
return "Very high risk"
}
}
d := <- conn[“data”].(chan CmH2O)
conn[“alert”].(chan string) <- triggerAlert(d)
Gateway(conn, fromc, toc)
}
func main() {
// ...
G := map[string]interface{}{
“data” : make(chan CmH2O),
“alert” : make(chan string),
}
// ...
}
Figure 17: Description of the Gateway component in π-ADL (left) and its corresponding implementation in Go (right).
support provided by Go.
• Go natively offers an easy, lightweight support for the concurrent communication and
execution of distributed programs mainly by using goroutines. In this perspective, as the
architectural elements of the system are logically and physically distributed, such features
provided by Go enable their concurrent execution and then they foster an easy development and deployment of this type of system.
• There might be cases in which it is necessary to add, remove, or replace sensors or connections in the system. Components and connectors can be dynamically added to the system
as the creation of these elements is simply performed through new calls to the respective
goroutines that implement them. In case of replacing components and connectors, it is
necessary to make new calls to the goroutines that are to replace the elements and then
rearrange the communication channels in order to enable their synchronization. Finally,
when removing these elements, the goroutines associated with them are to be blocked by
closing the communication channels (connections) and the garbage collector of the Go
language will be in charge of dealing with their effective destruction.
37
π-ADL: A Formal Description Language for Software Architectures
architecture WSNFloodMonitoring is abstraction() {
behavior is {
compose {
S1 is Sensor()
and S2 is Sensor()
and S3 is Sensor()
and L1 is ZigBee()
and L2 is ZigBee()
and L3 is ZigBee()
and G is Gateway()
} where {
S1::measure unifies L1::input
S2::measure unifies L2::input
L1::output unifies S3::pass
L2::output unifies S3::pass
S3::measure unifies L3::input
L3::output unifies G::data
}
}
}
(a)
func main() {
S1 := map[string]interface{}{
“sense” : make(chan MV),
“pass”
: make(chan CmH2O),
“measure” : make(chan CmH2O),
}
S2 := map[string]interface{}{
“sense” : make(chan MV),
“pass”
: make(chan CmH2O),
“measure” : make(chan CmH2O),
}
S3 := map[string]interface{}{
“sense” : make(chan MV),
“pass”
: make(chan CmH2O),
“measure” : make(chan CmH2O),
}
L1 := map[string]interface{}{
“input” : make(chan CmH2O),
“output” : make(chan CmH2O),
}
L2 := map[string]interface{}{
“input” : make(chan CmH2O),
“output” : make(chan CmH2O),
}
L3 := map[string]interface{}{
“input” : make(chan CmH2O),
“output” : make(chan CmH2O),
}
G := map[string]interface{}{
“fromSensor” : make(chan CmH2O),
“alert”
: make(chan string),
}
go
go
go
go
go
Sensor(S1,
Sensor(S1,
Sensor(S2,
Sensor(S2,
Sensor(S3,
nil,
nil,
nil,
nil,
nil,
nil)
nil)
nil)
nil)
nil)
go
go
go
go
go
go
ZigBee(L1,
ZigBee(L2,
Sensor(S3,
Sensor(S3,
ZigBee(L3,
Gateway(G,
S1[“measure”],
S2[“measure”],
L1[“output”],
L2[“output”],
S3[“measure”],
L3[“output”],
L1[“input”])
L2[“input”])
S3[“pass”])
S3[“pass”])
L3[“input”])
G[“data”])
}
(b)
Figure 18: Description of the WSNFloodMonitoring architecture in π-ADL (left) and its corresponding implementation in Go (right).
5
Final remarks
This report introduced π-ADL, a formal language based on the π-calculus process algebra
for specifying dynamic software architectures under structural and behavioral viewpoints and
supporting their automated analysis with respect to functional and non-functional properties.
In order to tackle the existing gap between architecture descriptions and their implementations in the context of large-scale, dynamic, distributed software systems, π-ADL was integrated
with Go, a general-purpose programming language suitable for building large-scale distributed systems deployed in multicore and networked computer architectures. Go was chosen to
serve as implementation language due to its basis on π-calculus (the same of π-ADL), so that
the straightforward relationship between elements of the languages has fostered such an integration. Finally, π-ADL was endowed with a tool support for assisting software architects in
the description of architectures by using the π-ADL language and for automatically generating
implementation code in Go.
π-ADL: A Formal Description Language for Software Architectures
38
In future works, the mapping process from π-ADL to Go will be evaluated by using
existing model transformation metrics, as the ones discussed in [37] for text-to-text (T2T) transformations. Furthermore, future versions of the π-ADL language will include architectural elements for dynamic reconfiguration, also addressing how reconfiguration actions specified at the
architectural level take place at the implementation level and vice-versa [15, 24], as well as the
verification and enforcement of structural, behavioral, and quality properties before, during, and
after the reconfiguration process itself. Finally, the current tool support for π-ADL will be extended to be made available as an Eclipse IDE plug-in with corresponding graphical and textual
representations of software architectures.
Acknowledgements
This work was partially supported by the Brazilian National Agency of Petroleum, Natural
Gas and Biofuels through the PRH-22/ANP/MCTI Program, and by the following Brazilian
funding agencies: CAPES, under grant 11097/2013-2; CNPq, under grants 400449/2013-7 and
203194/2014-4, and; INES, under grant 573964/2008-4.
π-ADL: A Formal Description Language for Software Architectures
39
Appendix A – π-ADL Grammar
This appendix describes the concrete textual syntax of π-ADL by using the Extended
Backus-Naur Form (EBNF) meta-language [29]. EBNF is a notation for formally describing
the context-free grammar of a language, i.e., its syntax. Such a notation consists of terminal
symbols, which are a sequence of one or more characters forming an irreducible element of the
language, and non-terminal production rules, which governs how a particular syntactic element
can be legally formed in terms of terminal symbols. Syntactic elements have names that are
used in production rules and they are distinguished from names and reserved words (keywords)
in the language.
The EBNF meta-language uses the following meta-symbols:
• a right arrow (→) expresses the definition of a production rule, so that the rule A → B can
be read A is defined as B.;
• the pipe symbol (|) indicates a choice in a production rule;
• brackets surrounding a term denote that it is optional in the production rule;
• the asterisk character (∗) is used to express the occurrence of a term by zero or many
times;
• the plus character (+) is used to express the occurrence of a term by one or many times
(i.e., such a term occurs at least once);
• the ampersand character (&) indicates that the elements can occur in any order, so that
A & B indicates that both AB and BA sequences of the A and B elements are valid;
• ellipses (...) indicate a character range;
• parentheses are used to group elements.
In the EBNF specification of the π-ADL grammar, reserved words and terminal symbols
of the language are expressed in a typewriter font, whereas names of production rules are typed in the italic form and the abovementioned meta-symbols of the EBNF notation appear in
normal writing. It is important to highlight that names of production rules and attributes in this
specification seek to be representative and self-explanatory.
As an example, consider the three following production rules:
ArchitectureDescription →
ArchitecturalElement ∗
Architecture
ArchitecturalElement → Component | Connector
Component →
component Identi f ier is abstraction([Parameter (, Parameter)∗]) {
TypeDeclaration ∗
ConnectionDeclaration ∗
VariableDeclaration ∗
[ProtocolDeclaration]
BehaviorDeclaration
}
π-ADL: A Formal Description Language for Software Architectures
40
The ArchitectureDescription rule refers to an architecture description composed of a set of architectural elements (defined by the ArchitectureElement production rule) and an architecture
itself (defined by the Architecture production rule). An architectural element can be either a
component or a connector, respectively defined by the Component and Connector production
rules. A component is declared by using the component keyword and it comprises an identifier
(represented by the Identi f ier production rule). Optionally, it can also take a list of parameters (each one defined by the Parameter production rule and separated by commas) as input,
between parentheses. Within the definition of this architectural element (delimited by braces),
one can have in sequence:
• declaration of zero or more types defined by the TypeDeclaration production rule;
• declaration of zero or more connections defined by the ConnectionDeclaration production rule;
• declaration of zero or more variables defined by the VariableDeclaration production rule;
• optional declaration a protocol defined by the ProtocolDeclaration production rule, and;
• declaration of exactly one (as the multiplicity characters ∗ and + are not used) behavior
defined by the BehaviorDeclaration production rule.
π-ADL: A Formal Description Language for Software Architectures
π-ADL production rules
ArchitectureDescription →
ArchitecturalElement ∗
Architecture
ArchitecturalElement → Component | Connector
Component →
component Identi f ier is abstraction([Parameter (, Parameter)∗]) {
TypeDeclaration ∗
ConnectionDeclaration ∗
VariableDeclaration ∗
[ProtocolDeclaration]
BehaviorDeclaration
}
Connector →
connector Identi f ier is abstraction([Parameter (, Parameter)∗]) {
TypeDeclaration ∗
ConnectionDeclaration ∗
VariableDeclaration ∗
[ProtocolDeclaration]
BehaviorDeclaration
}
TypeDeclaration → type Identi f ier is ValueType
ConnectionDeclaration → connection Identi f ier is ConnectionMode (ValueType)
ConnectionMode → in | out
VariableDeclaration → Identi f ier is Location
ProtocolDeclaration →
protocol is {
( (ConnectionProtocol (| ConnectionProtocol)∗) & [ConnectionProtocol] )(* | +)
}
ConnectionProtocol → ( ∗ via Identi f ier ConnectionAction ValueType ) ∗
ConnectionAction → send | receive
BehaviorDeclaration →
behavior is {
Behavior ∗
}
Behavior →
TypeDeclaration
| VariableDeclaration
| ExplicitPro jection
| Assignment
| FunctionDeclaration
41
π-ADL: A Formal Description Language for Software Architectures
|
|
|
|
|
|
FunctionCall
Pre f ix
ChoiceBehavior
ComposeBehavior
Recurse
Inaction
ExplicitPro jection → project Identi f ier as Parameter (, Parameter) ∗
Assignment → VariableAssignment | CollectionAddition | CollectionRemoval
VariableAssignment → Identi f ier = AbstractExpression
CollectionAddition → Identi f ier add (AddToMap | AddToSet | AddToSequence)
AddToMap → [ AbstractExpression, AbstractExpression ]
AddToSet → [ AbstractExpression ]
AddToSequence → #[ AbstractExpression ]
CollectionRemoval →
Identi f ier remove (RemoveFromMap | RemoveFromSet | RemoveFromSequence)
RemoveFromMap → @( AbstractExpression )
RemoveFromSet → [ AbstractExpression ]
RemoveFromSequence → #IntegerNumber
FunctionDeclaration →
Identi f ier is function( [Parameter (, Parameter)∗] ) [: ValueType] {
Statement ∗
[Return]
}
Return → return AbstractExpression
Statement →
TypeDeclaration
| VariableDeclaration
| ExplicitPro jection
| Assignment
| FunctionCall
| I f T henElse
| W hile
| For
| Return
| Unobservable
I f T henElse →
if AbstractExpression then {
Statement ∗
} ElseI f ∗
42
π-ADL: A Formal Description Language for Software Architectures
[Else]
ElseI f →
else if AbstractExpression then {
Statement ∗
}
Else →
else {
Statement ∗
}
W hile →
while AbstractExpression do {
Statement ∗
}
For →
for ( VariableAssignment; LogicalExpression; VariableAssignment ) do {
Statement ∗
}
Unobservable → unobservable
Pre f ix → SilentPre f ix | InputPre f ix | Out putPre f ix | ConditionalPre f ix
SilentPre f ix → unobservable
InputPre f ix → via Identi f ier receive Parameter
Out putPre f ix → via Identi f ier send AbstractExpression
Parameter → Identi f ier : ValueType
ConditionalPre f ix →
if AbstractExpression then {
Pre f ix ∗
}
ChoiceBehavior →
choose {
Behavior +
} (or { Behavior + }) +
CompositionBehavior →
compose {
Behavior +
} (and { Behavior + }) +
Inaction → done
Recurse → behavior( [AbstractExpression (, AbstractExpression)∗] )
Architecture →
architecture Identi f ier is abstraction( [Parameter (, AbstractExpression)∗] ) {
43
π-ADL: A Formal Description Language for Software Architectures
44
behavior is {
compose {
ElementInstantiation
(and ElementInstantiation) ∗
} where {
Uni f ication ∗
}
}
}
ElementInstantiation → Identi f ier is Identi f ier ([Identi f ier (, Identi f ier )∗] )
Uni f ication → ConnectionAccess unifies ConnectionAccess
ConnectionAccess → Identi f ier :: Identi f ier
ValueType → BasicType | ConstructedType | Identi f ier
BasicType → NaturalType | IntegerType | RealType | BooleanType | StringType | AnyType
NaturalType → Natural
IntegerType → Integer
RealType → Real
BooleanType → Boolean
StringType → String
AnyType → Any
ConstructedType → Tuple | View | Map | Set | Sequence
Tuple → tuple[ ValueType (, ValueType) ∗ ]
View → view[ LabeledType (, LabeledType) ∗ ]
LabeledType → Identi f ier : ValueType
Location → location[ ValueType ]
Map → map[ ValueType, ValueType ]
Set → set[ ValueType ]
Sequence → sequence[ ValueType ]
AbstractExpression → Expression | ConstructedValue
Expression → LogicalExpression
LogicalExpression → EqualityExpression (|| | &&) EqualityExpression
EqualityExpression → RelationalExpression (== | !=) RelationalExpression
RelationalExpression → ArithmeticExpression (>= | <= | > | <) ArithmeticExpression
ArithmeticExpression → Term (+ | -) Term
π-ADL: A Formal Description Language for Software Architectures
45
Term → Factor (* | / | mod) Factor
Factor → ( Expression ) | UnaryExpression | AtomicElement
UnaryExpression → ! AtomicElement
AtomicExpression → LiteralElement | Identi f ier
LiteralElement → IntegerLiteral | RealLiteral | BooleanLiteral | StringLiteral
IntegerLiteral → Number
RealLiteral → RealNumber
StringLiteral → String
BooleanLiteral → true | false
ConstructedValue → FunctionCall | TupleValue | ViewValue
FunctionCall → Identi f ier ( [AbstractExpression (, AbstractExpression)∗] )
TupleValue → tuple[ AbstractExpression (, AbstractExpression) ∗ ]
ViewValue → view[Identi f ier : AbstractExpression (, Identi f ier : AbstractExpression)∗]
Identi f ier → (a...z | A...Z | _) (a...z | A...Z | _ | 0...9)
String → “ <any ASCII character> ”
RealNumber → Number . Number
Number → (0...9) +
46
π-ADL: A Formal Description Language for Software Architectures
References
[1] ANTRL. http://www.antlr.org/.
[2] Eclipse IDE. http://eclipse.org/.
[3] Eclipse Modeling Framework Project (EMF). http://www.eclipse.org/modeling/emf/.
[4] Go Runtime Environment – Google App Engine.
appengine/docs/go/.
http://developers.google.com/
[5] Microsoft .NET Framework. http://www.microsoft.com/net.
[6] PiADL2Go: Mapping π-ADL architectural descriptions to implementations in the
Go language. http://consiste.dimap.ufrn.br/projects/piadl2go/.
[7] The Go Programming Language. http://golang.org.
[8] The Go Programming Language Specification. http://golang.org/ref/spec.
[9] Xtend. https://www.eclipse.org/xtend/.
[10] Xtext. http://www.eclipse.org/Xtext/.
[11] ALLEN, R; DOUENCE, R; GARLAN, D. Specifying and analyzing dynamic software
architectures. In: Astesiano, E, editor, PROCEEDINGS OF THE FIRST INTERNATIONAL CONFERENCE ON FUNDAMENTAL APPROACHES TO SOFTWARE ENGINEERING (FASE’98), volume 1382 de Lecture Notes in Computer Science, p. 21–37.
Springer Berlin Heidelberg, Germany, 1998.
[12] ALLEN, R. J. A formal approach to software architecture. PhD thesis, Carnegie Mellon
University, Pittsburgh, PA, USA, 1997.
[13] BALBAERT, I. The way to Go: A thorough introduction to the Go programming
language. iUniverse, USA, 2012.
[14] BASS, L; CLEMENTS, P; KAZMAN, R. Software Architecture in practice. AddisonWesley, USA, 3rd edition, 2012.
[15] BATISTA, T; JOOLIA, A; COULSON, G. Managing dynamic reconfiguration in
component-based systems. In: Morrison, R; Oquendo, F, editors, PROCEEDINGS
OF THE 2ND EUROPEAN WORKSHOP ON SOFTWARE ARCHITECTURE (EWSA
2005), volume 3527 de Lecture Notes in Computer Science, p. 1–17. Springer-Verlag
Berlin Heidelberg, Germany, 2005.
[16] CAVALCANTE, E; OQUENDO, F; BATISTA, T. Architecture-based code generation:
From π-ADL architecture descriptions to implementations in the Go language. In:
Avgeriou, P; Zdun, U, editors, PROCEEDINGS OF THE 8TH EUROPEAN CONFERENCE ON SOFTWARE ARCHITECTURE (ECSA 2014), volume 8627 de Lecture
Notes in Computer Science, p. 130–145. Springer International Publishing, Switzerland,
2014.
[17] CHISNALL, D. The Go programming language phrasebook. Addision-Wesley / Pearson Educational, Inc, USA, 2012.
π-ADL: A Formal Description Language for Software Architectures
47
[18] CLEMENTS, P. A survey of architecture description languages. In: PROCEEDINGS
OF THE 8TH INTERNATIONAL WORKSHOP ON SOFTWARE SPECIFICATION
AND DESIGN (IWSSD 1996), p. 16–25, USA, 1996. IEEE Computer Society.
[19] DASHOFY, E. M. Supporting stakeholder-driven, multi-view software architecture
modeling. Phd dissertation, University of California, Irvine, USA, 2007.
[20] DASHOFY, E. M; VAN DER HOEK, A; TAYLOR, R. N. A highly-extensible, XMLbased architecture description language. In: PROCEEDINGS OF THE 2001 WORKING IEEE/IFIP CONFERENCE ON SOFTWARE ARCHITECTURE (WICSA 2001),
p. 103–112, Piscataway, NJ, USA, 2001. IEEE Computer Society.
[21] DASHOFY, E. M; VAN DER HOEK, A; TAYLOR, R. N. An infrastructure for the
rapid development of XML-based architecture description languages. In: PROCEEDINGS OF THE 24TH INTERNATIONAL CONFERENCE ON SOFTWARE ENGINEERING (ICSE 2002), p. 266–276, New York, NY, USA, 2002. ACM.
[22] GARLAN, D; MONROE, R; WILE, D. ACME: An architecture description interchange language. In: PROCEEDINGS OF THE 1997 CONFERENCE OF THE
CENTRE FOR ADVANCED STUDIES ON COLLABORATIVE RESEARCH (CASCON’97), p. 169–189, USA, 1997. IBM Press.
[23] GEORGAS, J. C; DASHOFY, E. M; TAYLOR, R. N. Architecture-centric development: A different approach to Software Engineering. Crossroads Magazine, 12(4),
Aug. 2006.
[24] GOMES, A. T. A; BATISTA, T. V; JOOLIA, A; COULSON, G. Architecting dynamic reconfiguration in dependable systems. In: de Lemos, R; Gacek, C; Romanovsky,
A, editors, ARCHITECTING DEPENDABLE SYSTEMS IV, volume 4615 de Lecture
Notes in Computer Science, p. 237–261. Springer-Verlag Berlin Heidelberg, Germany,
2007.
[25] HOARE, C. A. Communicating sequential processes. Communications of the ACM,
21(8):666–677, Aug. 1978.
[26] HORITA, F. E. A; FAVA, M. C; MENDIONDO, E. M; ROTAVA, J; SOUZA, V. C;
UEYAMA, J; AO PORTO DE ALBUQUERQUE, J. AGORA-GeoDash: A geosensor
dashboard for real-time flood risk monitoring. In: Hiltz, S. R; Pfaff, M. S; Plotnick, L;
Shih, P. C, editors, PROCEEDINGS OF THE 11TH INTERNATIONAL CONFERENCE
ON INFORMATION SYSTEMS FOR CRISIS RESPONSE AND MANAGEMENT (ISCRAM 2014), p. 309–318, USA, 2014. The Pennsylvania State University.
[27] HUGHES, D; GREENWOOD, P; BLAIR, G; COULSON, G; GRACE, P; PAPPENBERGER, F; SMITH, P; BEVEN, K. An experiment with reflective middleware to support
grid-based flood monitoring. Concurrency and Computation: Practice & Experience,
20(11):1303–1316, Aug. 2008.
[28] HUGHES, D; UEYAMA, J; MENDIONDO, E; MATTHYS, N; HORRÉ, W; MICHIELS,
S; HUYGENS, C; JOOSEN, W; MAN, K. L; GUAN, S.-U. A middleware platform
to support river monitoring using wireless sensor networks. Journal of the Brazilian
Computer Society, 17(2):85–102, Jun. 2011.
π-ADL: A Formal Description Language for Software Architectures
48
[29] ISO/IEC 14977:1996(E). ISO/IEC International Standard for Information Technology – Syntactic metalanguage, Extended BNF. ISO/IEC, Geneva, Switzerland, 1996.
[30] ISO/IEC/IEEE 42010:2011(E). ISO/IEC/IEEE International Standard for Systems
and Software Engineering – Architectural Description. ISO, Geneva, Switzerland,
2011.
[31] LUCKHAM, D. C; KENNEY, J. J; AUGUSTIN, L. M; VERA, J; BRYAN, D; MANN, W.
Specification and analysis of software architecture using RAPIDE. IEEE Transactions
on Software Engineering, 21(4):336–355, Apr. 1995.
[32] MAGEE, J; DULAY, N; EISENBACH, S; KRAMER, J. Specifying distributed software
architectures. In: PROCEEDINGS OF THE 5TH EUROPEAN SOFTWARE ENGINEERING CONFERENCE (ESEC’95), p. 137–153, United Kingdom, 1995. Springer-Verlag
London.
[33] MALAVOLTA, I; LAGO, P; MUCCINI, H; PELLICCIONE, P; TANG, A. What industry needs from architectural languages: A survey. IEEE Transactions on Software
Engineering, 39(6):869–891, Jun. 2013.
[34] MEDVIDOVIC, N; TAYLOR, R. N. A classification and comparison framework for
software architecture description languages. IEEE Transactions on Software Engineering, 26(1):70–93, Jan. 2000.
[35] MILNER, R. A calculus for communicating systems, volume 92 de Lecture Notes in
Computer Science. Springer-Verlag Berlin Heidelberg, Germany, 1980.
[36] MILNER, R. Communicating and mobile systems: The π-calculus. Cambridge University Press, USA, 1999.
[37] NGUYEN, P. H. Quantitative analysis of model transformations. Master’s thesis,
Technische Universiteit Eindhoven, Eindhoven, The Netherlands, 2010.
[38] OQUENDO, F. π-ADL: An architecture description language based on the higherorder typed π-calculus for specifying dynamic and mobile software architectures.
ACM SIGSOFT Software Engineering Notes, 29(3):1–14, May 2004.
[39] OQUENDO, F. Tutorial on ArchWare ADL – Version 2. Technical report, ArchWare
Consortium, 2005.
[40] OQUENDO, F. π-Method: A model-driven formal method for architecture-centric
software engineering. ACM SIGSOFT Software Engineering Notes, 31(3):1–13, May
2006.
[41] OQUENDO, F; ALLOUI, I; CÎMPAN, S; VERJUS, H. The ArchWare ADL: Definition
of the abstract syntax and formal semantics. Technical report, ArchWare Consortium,
2002.
[42] OQUENDO, F; WARBOYS, B; MORRISON, R; DINDELEUX, R; GALLO, F; GARAVEL, H; OCCHIPINTI, C. ArchWare: Architecting evolvable software. In: Oquendo,
F; Warboys, B. C; Morrison, R, editors, PROCEEDINGS OF THE FIRST EUROPEAN
WORKSHOP ON SOFTWARE ARCHITECTURE (EWSA 2004), volume 3047 de Lecture Notes in Computer Science, p. 257–271. Springer-Verlag Berlin Heidelberg, Germany, 2004.
π-ADL: A Formal Description Language for Software Architectures
49
[43] PIERCE, B. C. Foundational calculi for programming languages. In: Tucker, A. B,
editor, HANDBOOK OF COMPUTER SCIENCE AND ENGINEERING. CRC Press,
USA, 1996.
[44] QAYYUM, Z. Realization of software architectures using a formal language:
Towards languages dedicated to formal development based on π-ADL6 . PhD thesis,
Université de Bretagne-Sud, Vannes, France, 2009.
[45] SHAW, M; CLEMENTS, P. The Golden Age of Software Architecture. IEEE Software,
23(2):31–39, Mar./Apr. 2006.
[46] SHAW, M; GARLAN, D. Software Architecture: Perspectives on an emerging discipline. Prentice Hall, USA, 1996.
[47] SUMMERFIELD, M. Programming in Go: Creating applications for the 21st Century. Addision-Wesley, USA, 2012.
[48] UEYAMA, J; HUGHES, D. R; MATTHYS, N; HORRÉ, W; JOOSEN, W; HUYGENS, C;
MICHIELS, S. An event-based component model for wireless sensor networks: A case
study for river monitoring. In: PROCEEDINGS OF THE 28TH BRAZILIAN SYMPOSIUM ON COMPUTER NETWORKS AND DISTRIBUTED SYSTEMS (SBRC 2010),
p. 997–1004, Porto Alegre, RS, Brazil, 2010. SBC.
[49] WASSERMAN, A. I. Toward a discipline of Software Engineering. IEEE Software,
13(6):23–31, Nov. 1996.
6 Original
title in French: Concrétisation des architectures logicielles à l’aide d’un langage formel: vers les
langages dediés au développement formel fondés sur π-ADL