A Refactoring-based Tool for Software Component Adaptation

advertisement
A Refactoring-based Tool for Software Component Adaptation
Gautier Bastide
Ecole de Mines de Douai
941 rue Charles Bourseul
59508 Douai, France
bastide@ensm-douai.fr
Abstract
Adapting software components usable by a particular
application is a crucial issue in software component based
technology. In fact, software components can be used in
contexts that can be different from the context assumptions
made by the component designers. We present in this paper a tool aiming at adapting software component structure.
Among the motivations of this kind of adaptation, we note
its possible application to prepare a flexible deployment of
software components according to the available resources
(CPU, memory). Our adaptation process is based on refactoring and fragmentation of component source code. To
support this structural adaptation technique, we developed
an adaptation process which we have experimented using
the Java framework of the Fractal component model.
1 Introduction
Component-Based Software Engineering (CBSE) aims at
building applications by assembling reusable components
[12]. However, experiments show that direct component
reuse is extremely hard and a component usually has to
be adapted in order to be integrated into an application.
This difficulty is due to the available large variety of infrastructures and software environments, going from the simple mobile phone equipped with minimal capacities to the
cluster of several multi-processor computers. Moreover, the
development of networks and wireless technology imposes
the application designers to take into account all characteristics of the available infrastructure like the type and the size
of the available hosts (i.e. how many hosts are available and
what are the properties of each one in term of resources as
memory or energy) and the Quality of Service considered
for this infrastructure, for example, in terms of load balancing, performance and security policy allowed on each host.
However, in many cases, software components in general
and COTS (i.e. Commercial-Off-The-Shelf) in particular
are designed as a monolithic unit to be deployed in a centralized way. Furthermore, in other cases, when components
are designed to be distributed, the deployment infrastructure configuration is specified since the design time. Thus,
it is not possible to specify at deployment time what services are to be deployed and executed on a particular host.
To illustrate this, let us consider an example of a monolithic
COTS shared-diary component which provides shareddiary services (e.g. personal diary management, meeting
management and absence management). The application
administrator may want to distribute some component services on various hosts. For example, services related to
database management may be deployed on a secure server
whereas other services may be transferred onto different
sites in order to increase performances (i.e. parallelism).
Due to the monolithic implementation of this component it
is not possible to obtain the needed deployment configuration of the component services.
While being based on the above considerations, our objective in this paper is to propose a tool allowing the software component restructuring. In fact, our approach permits to restructure existent software component implementations using slicing and refactoring techniques. We focus
on components based on an object-oriented implementation
and we experiment this approach using Fractal component
model [3] and its Java implementation named Julia [2].
We discuss the proposed approach in the rest of this paper as follows. Section 2 presents the general mean of the
structural adaptation of a software component. Section 3
describes the adaptation process. In section 4, some related
works are briefly mentioned. Finally, conclusion and future
works are outlined in section 5.
2 Software component refactoring
Software component refactoring modifies the structure of a
component while preserving its behaviour and its services.
In fact, the structural adaptation is interested in modifying
neither the behaviour of the component nor its services, but
Proceedings of the Conference on Software Maintenance and Reengineering (CSMR’06)
0-7695-2536-9/06 $20.00 © 2006
IEEE
rather to reorganize its structure. Indeed, the structure of
the component which has to be adapted consists of the list
of the structural elements, defined in this component, as
well as their links. For example, a component can be seen
as collections of ports, interfaces, sub-components, classes,
etc. Thus, the structural adaptation can consist of updating
the list of a component interfaces by modifying the content
of each of these interfaces or restructuring the content of
the component ports (i.e. external adaptation). Also, the
structural adaptation can consist in the decomposition of a
software component in some sub-components where the set
of provided services must be the same as the one provided
by the initial component before its adaptation (i.e. internal
adaptation).
Adapting the structure of a software component can be useful in many cases. For example, external structural adaptation can be used in order to increase component reuse and
internal structural adaptation for a flexible component deployment.
First, component restructuring can be used in order to match
heterogeneous component external structures. In fact, the
assembly of two components or the integration of a component into an existing application needs to restructure their
provided and required interfaces (or/and ports) if it proposes
all required services but when these ones are not structured
in interfaces permitting to match them. For example, Figure 1 shows that the C1 and C2 components cannot be assembled because C1 required ports do not match with those
provided by C2 although C2 provides all required services.
So, using our approach for restructuring ports, matching between C1 and C2 becomes possible.
Moreover, the component structure adaptation by its fragmentation in some generated components can be used to
prepare a flexible deployment strategy. Indeed, this adaptation permits to organize component services in separate
sub-sets and defining each sub-set in a new component generated by fragmenting the original one. Then, the generated components can be deployed on one machine or separately on different ones which can be distributed or not.
These possibilities are very useful for load balancing and
increased performance (Figure 1).
Figure 1. Structural adaptation
3 Software component restructuring process
As we announced previously, the restructuring of a component aims at generating new components by the fragmentation of a component based on an object-oriented implementation. This operation is realized without generating any
change on the services provided by the component nor on
its assembly with the other components of the application.
To resolve these constraints, we defined a restructuring process made up of four stages (Figure 2).
Figure 2. Structural adaptation process
3.1
This first step aims at indicating which components are generated as a result of the component fragmentation. This
specification is realized using an ADL (Architecture Description Language) defining components to be generated
and for each component its interfaces. We consider that initial interfaces are unbroken units1 . Each interface defines a
sub-set from services provided by the initial component.
3.2
IEEE
Component fragmentation and generation of the needed structures
Specification done during the previous step is used in order to generate the implementation of each new component
created by adaptation. In fact, the component fragmentation aims at splitting component service collection and consequently the corresponding component internal implementation in some sub-collections of services where each subcollection will be provided by a corresponding component.
The definition of these components requires the generation
of their external implementation in term of interfaces and
services and the corresponding object-oriented internal implementation. Two conditions need be checked: the first
condition is the construction of each new component so
as to guarantee its integrity. In fact, the generated components must function correctly without syntactic and semantic bugs. The second condition consists in ensuring the
coherence of the new generated component. We proposed
1 In order to simplify, we consider interfaces like unbreakable entities.
So, specification and restructuring may be realized at the provided service
scale.
Proceedings of the Conference on Software Maintenance and Reengineering (CSMR’06)
0-7695-2536-9/06 $20.00 © 2006
Specification of the new structure
to guarantee this condition by operating at the componentinterface scale and at the object-implementation scale.
In order to ensure the first condition, we propose a bottomup construction of components to be generated. Starting
from ports and interfaces specified as provided by a component to be generated, we form, by analyzing component
source-code, a graph which we called SBDG (Structural
and Behavioural Dependence Graph). Nodes of the SBDG
are structural elements which must be accessible from the
component space-name and arcs are dependence links between these structural elements. Dependence links are of
two types: structural and behavioural links. For example, a
port P1 composed of an interface I1 is structurally dependent of this last. However, if a method M1 calls a method
M2 then M1 depends on M2 through a behavioural link.
3.3
Assembly of the new components
Once the new components are generated, they have to be
assembled. This assembly reflects two types of dependence
links between these components.
Behavioural dependences: The first type of dependence
relates to the behavioural dependence links between these
components. A behavioural link reflects the use, by a generated component, of a given service defined by another
generated component. Behavioural dependences are set up
through the implementation of services provided by specific
interfaces added to the generated component structures:
• A required interface implemented for each component
and which include all needed services implemented by
other components.
• A provided interface implementing all services implemented by this component and required by other components.
Resource sharing dependences: The second type of link
reflects the resource sharing between two generated components. A resource is defined as being a structural entity
which has a state that can be updated and whose persistence
is more important than that of the method in which it is used.
A resource can be internal (e.g. attributes, etc.) or external
(i.e. persistent elements as files and databases).
As we proposed to duplicate internal structural entities, we
need to ensure coherence and synchronisation of the resource states. The shared-resource dependences are translated in the form of interfaces added to the structure of each
component. Connection of these interfaces allows the sharing and the communication of a common state of the sharedresources. To materialize shared-resource dependences, we
defined, for each generated component defining a sharedresource, two interfaces:
• The first interface is defined as required and synchronous. It allows the component to notify to all components sharing a resource with it, its state modification. This interface is synchronous because the component which updates the resource state can continue its
execution only after that the other components which
share this resource take into account this state modification. It allows to guarantee that components have a
coherent state and consequently their services.
• The second interface, defined as provided, allows
a component to receive the notifications of sharedresource updates.
In addition to the notification problem, we need to ensure
that shared resources cannot be handled simultaneously. To
prohibit simultaneous handling of these resources, we defined two additional interfaces:
• The first interface, defined as required and synchronous, allows it to get a resource access right. This
interface guarantees that only one access to the resource is possible for the given time.
• The second interface defined as provided and synchronous allows a component to notify the availability
of a resource to requester components.
3.4
The last step of the adaptation process is the integration, in
the subjacent application, of the structural adaptation result,
which was obtained during the previous steps. It consists
in connecting the new created components with the other
application components and to guarantee that the component adaptation is achieved in a transparent way compared
to the application components. In fact, the application must
continue to be executed without any change compared to its
initial configuration (i.e. configuration including the component before its adaptation). For that, it is necessary to
satisfy security and flexibility properties.
Concerning security conditions, application components
should not be able to access, after the adaptation, other
services than those which are provided by the component
before its adaptation. This means that all new interfaces
defined to guarantee the new generated components must
be accessible only by these components. The other components of the application will not be able to use services
available through these interfaces. For example, it would
be forbidden to be able to access, by the application components except those created by adaptation, to the state of a
shared resource.
The flexibility condition means that the new generated components can be accessed and be handled as separate entities,
Proceedings of the Conference on Software Maintenance and Reengineering (CSMR’06)
0-7695-2536-9/06 $20.00 © 2006
IEEE
Integration of the adaptation result
one of the others. For example, it would be possible to deploy separately these sub-components.
Our solution to guarantee these properties consists in encapsulating the new structure resulting from the adaptation
in a new composite-component. This new component allows to mask access to ”non functional” services. It wraps
all the generated components and thus filters all accesses to
them. This composite-component provides only interfaces
which were available by the adapted component before its
adaptation. Moreover, it provides some interfaces which allow to manipulate the generated components. For example,
these interfaces aim at permitting independent deployment
of each sub-component.
4 Related works
We classify related works according to two criteria. First,
we present works related to software component adaptation.
The other criterion focuses on works whose topic is restructuring program codes.
If we consider the first criterion related to the goal, many
adaptation approaches have been discussed in the literature.
Broadly speaking, adaptation techniques can be categorized
as either white-box or black-box [7]. White-box techniques
typically require understanding of the internal implementation of the reused component, whereas black-box techniques only require knowledge about the component’s interfaces. To our knowledge, no approach among those quoted,
is interested in the adaptation of component structures. All
are interested in the adaptation of services. This adaptation
can be carried out in a static [8] or dynamic [4], [9] way.
Concerning the second criterion related to restructuring approaches, we can quote refactoring techniques [10], [11]
whose aim is to restructure an existing body of an objectoriented code, altering its internal structure without changing its external behaviour [10]. Generally, refactoring is
used to make code simpler in order to include or understand
it more easily [5].
Another technique of program analysis is slicing [13]. It is
generally used for the code debugging and testing [1], for
maintaining [6] or for transforming source code.
5 Conclusion and future works
We presented an approach to deal with the adaptation of
software components. This approach is based on the consideration of a new adaptation facet: the structure of a software
component. This approach has been implemented. The prototype has been developed using the Julia [2] software component framework which is a Java implementation of the
Fractal component model [3]. We have developed, in addition to the structural adaptation process presented here, a
component model supporting this process. This model was
not presented here due to space limitation.
Our approach needs source code and it does not consider run-time adaptation problems. However, it is generic
enough to be applicable for a static or dynamic adaptation.
Nevertheless, concerning the dynamic adaptation, it is necessary to define, in addition to the already defined process,
mechanisms for the management of the dynamicity (e.g.
disconnection, service recovery, etc.). Thus, the dynamicity
management constitutes one direction of our future work.
As we explain, many applications of the structural adaptation approach are possible. Thus, for example, we want
to develop our approach for context-awareness system (i.e.
ubiquitous applications) in order to load or unload component services according to the available resources.
References
[1] H. Agrawal, R. A. DeMillo, and E. H. Spafford. Debugging
with dynamic slicing and backtracking. Software - Practice
and Experience, 23(6):589–616, 1993.
[2] E. Bruneton. Julia tutorial:
http://fractal.objectweb.org/tutorials/julia/.
[3] E. Bruneton, T. Coupaye, and J. Stefani. Recursive and dynamic software composition with sharing. In Proceedings
of the 7th ECOOP International Workshop on ComponentOriented Programming (WCOP’02), Malaga, Spain, 2002.
[4] P.-C. David and T. Ledoux. Dynamic adaptability of services in enterprise javabeans architecture. In Proceedings
of ECOOP’02 Workshop on Component-Oriented Programming, Malaga, Spain, 2002.
[5] M. Fowler, K. Beck, J. Brant, W. Opdyke, and D. Roberts.
Refactoring: Improving the Design of Existing Code.
Addison-Wesley Object Technology Series, 1999.
[6] K. B. Gallagher and J. R. Lyle. Using program slicing in
software maintenance. IEEE Transactions on Software Engineering, 17(8):751–761, 1991.
[7] G. Heineman and H. Ohlenbusch. An evaluation of component adaptation techniques. Technical Report WPI-CS-TR98-20, Department of Computer Science, Worcester Polytechnic Institute, February 1999.
[8] R. Keller and U. Hölzle. Binary component adaptation. Lecture Notes in Computer Science, 1445:307–??, 1998.
[9] A. Ketfi, N. Belkhatir, and P. Cunin. Automatic adaptation
of component-based software: Issues and experiences. In
PDPTA’02, 2002.
[10] T. Mens and T. Tourwe. A survey of software refactoring. In
IEEE Transactions on Software Engineering, volume V. 30
of 2, pages 126–139, 2004.
[11] W. F. Opdyke. Refactoring Object-Oriented Frameworks.
PhD thesis, Urbana-Champaign, IL, USA, 1992.
[12] C. Szyperski. Component software: beyond object-oriented
programming. ACM Press/Addison-Wesley Publishing Co.,
New York, NY, USA, 1998.
[13] M. Weiser. Program slicing. In Proceedings of the 5th international conference on Software engineering, pages 439–
449, Piscataway, NJ, USA, 1981. IEEE Press.
Proceedings of the Conference on Software Maintenance and Reengineering (CSMR’06)
0-7695-2536-9/06 $20.00 © 2006
IEEE
Download