Académique Documents
Professionnel Documents
Culture Documents
dk
Abstract
This report aims at providing software developers with an understanding of the as-
pect oriented paradigm as used in the JBoss 4 application server.
The aspect oriented framework in JBoss is presented in two stages: The first is how
to use the framework, the second how it has been implemented. A case study is
used to show how to design applications and aspect oriented services. A thorough
presentation of the implementation details of the framework is given and reflections
on the design choices are made.
We conclude that the complexity and flexibility is the strength and the weakness of
the framework. The cost of the flexibility is a major cognitive burden on the developer.
We further reflect on the communication of our findings.
Creative Commons Deed
Creative Commons
Attribution-ShareAlike 1.0
Share Alike. If you alter, transform, or build upon this work, you may
distribute the resulting work only under a license identical to this one.
For any reuse or distribution, you must make clear to others the license
terms of this work.
Any of these conditions can be waived if you get permission from the
author.
Your fair use and other rights are in no way affected by the above.
Disclaimer
1 Introduction 1
1.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.4.1 Prerequisites . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
2 JBoss 9
I
CONTENTS II
5.1.1 Pointcuts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
5.1.4 Metadata . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
7.4 Classloading . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
8 An Example AOP-service 59
8.2.1 ProductImpl . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
8.2.2 ClassUsingProduct . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
8.2.3 LoggingInterceptor . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
9 Deployment of AOP-applications 65
10 Instrumentation of Classes 69
11.1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
Bibliography 114
Appendix Contents
B.1 Advisor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
B.2 ClassAdvisor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
B.3 InstanceAdvisor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
B.4 ClassInstanceAdvisor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
B.5 InstanceAdvised . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
B.6 Advised . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
C.1 AspectManager . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
C.2 AspectXmlLoader . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
C.3 DeploymentInfo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
C.4 Instrumentor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
I
CONTENTS II
D Pointcut Classes 10
D.1 Advisable . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
D.2 InterceptorPointcut . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
D.3 ConstructorPointcut . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
D.4 FieldPointcut . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
D.5 MethodPointcut . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
D.6 CallerPointcut . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
D.7 IntroductionPointcut . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
E Interceptor Classes 12
E.1 Interceptor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
E.2 InterceptorFactory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
E.3 ConstructorTailInterceptor . . . . . . . . . . . . . . . . . . . . . . . . . . 13
E.4 FieldTailInterceptor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
E.5 MethodTailInterceptor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
E.6 CallerTailInterceptor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
F Invocation Classes 14
F.1 Invocation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
F.2 ConstructorInvocation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
F.3 FieldInvocation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
F.4 FieldReadInvocation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
F.5 FieldWriteInvocation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
F.6 MethodInvocation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
F.7 CallerInvocation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
F.8 InvocationType . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
G Javassist Classes 16
G.1 ClassPool . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
G.2 CtClass . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
CONTENTS III
G.3 CtConstructor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
G.4 CtField . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
G.5 CtMethod . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
III Diagrams 19
H Deployment Diagrams 20
J.1 Instance Creation, Field Access and Method Invocation Sequence Dia-
grams . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
V Source Code 49
L Deployment Descriptors 50
M.1 Customer.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
M.2 IdUtil.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
M.3 Order.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
M.4 OrderList.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
M.5 Product.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
M.6 ProductImpl.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
M.7 ProductComposite.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
M.8 Reservation.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
M.9 Type.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
N.1 CreationException.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
N.2 InventoryController.java . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
N.3 InventoryFactory.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
N.4 NoSuchOrderException.java . . . . . . . . . . . . . . . . . . . . . . . . . . 85
N.5 RemoteUtil.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86
O.1 DecrementReservationInterceptor.java . . . . . . . . . . . . . . . . . . . 88
O.2 IncrementReservationInterceptor.java . . . . . . . . . . . . . . . . . . . 90
O.3 MinimumStock.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
O.4 MinimumStockInterceptor.java . . . . . . . . . . . . . . . . . . . . . . . . 93
O.5 ProductCompositeMixin.java . . . . . . . . . . . . . . . . . . . . . . . . . . 95
CONTENTS V
O.6 ProductConstructionInterceptor.java . . . . . . . . . . . . . . . . . . . . 98
Introduction
1.1 Introduction
The main concerns of our thesis are the inclusion and usage of an aspect oriented
programming (AOP) framework in the JBoss 4.0 Java 2 Enterprise Edition (J2EE)
application server.
J2EE is the largest middleware platform for Java. Despite its wide usage, the devel-
opment of J2EE applications is complex with a multitude of rules to bear in mind.
The JBoss Group has recognized the need for easier development of complex mid-
dleware systems that offer the same functionality as J2EE. By extending the JBoss
application server with an aspect oriented framework the company aims at providing
an alternative or at least a supplement to J2EE.
In the last few years there has been a lot of interest in aspect oriented programming
and its applications. AOP is about separating crosscutting concerns.
By using the JBoss AOP framework to create applications, the development cycle can
be split up thus making development easier.
Basically the usage of AOP in JBoss allows developers to create applications with-
out implementing transactions, security, persistence and other services needed on a
distributed platform such as J2EE. Furthermore the AOP framework offers devel-
opers a way of creating an entire application without having to think complicated
functionality that spans many objects into the application.
More complicated functionality can be dealt with and added at a later time through
the use of AOP techniques.
In this report we take a close look at the JBoss AOP framework, how it is used, what
problems it solves and how it is designed.
1
CHAPTER 1. INTRODUCTION 2
Our first goal is to fully understand the AOP framework in JBoss 4, how it has
been constructed, why it has been constructed this way, and what the benefits
and drawbacks of the framework are.
Our second goal is to provide documentation for the AOP framework so that
other developers can use it to get a deeper understanding of the framework and
learn how to use it.
This master thesis is a communicative project that will provide a presentation and
critique of the JBoss AOP framework. This section describes what is needed in or-
der to reach the goals presented above. As the goals imply we approach the task of
communicating the framework on two levels:
1. How we as writers of this report can gain the required knowledge to communi-
cate the framework.
JBoss 4 and the AOP framework are still under development and at present suffer
from lack of documentation. In order to understand the framework in detail we have
done the following:
The above has not only given us a comprehensive knowledge of the framework, it has
also provided us with an insight into how the framework should be communicated
based on our own experiences. Our experiences have taught us that examples are
the best way to understand complex systems such as the JBoss AOP framework.
CHAPTER 1. INTRODUCTION 3
We have broken the communication of the AOP framework into four parts. From
part one through part three we will lower the level of abstraction progressively as we
delve deeper into the details of the framework. In part four we again raise the level
of abstraction, as we offer critique and conclusions on the framework.
Part 1
This thesis does not presuppose extensive knowledge of JBoss or any knowledge of
aspect oriented programming. The first part will focus on providing an introduction
to the JBoss server as well as basic knowledge of the theoretical concepts of aspect
oriented programming.
Throughout the report we will use an inventory management system case study as
an example application. AOP will be applied to the application. We find a concrete
example the best way to communicate details of the AOP framework. In a worst
case scenario a concrete example is the only thing that connects the reader with the
subject communicated. The first part will also be dedicated to a presentation of our
example application.
Part 2
In the second part we will lower the level of abstraction by presenting the features of
the JBoss AOP framework and how these features are used.
The presentation of features will also serve as a basis for understanding the AOP
that we apply on top of our example application. In the second part we describe and
illustrate the AOP extensions of our case.
Part 3
To fully understand the consequences of using the different features of the framework
it is necessary to have insight into the framework implementation.
In part three we go into the lowest level of abstraction when we offer a detailed
description of the implementation of the JBoss AOP framework. A low-level walk-
through will help the reader understand the more subtle consequences in choices
made while developing applications. Furthermore it will provide the reader with the
foundation required to fully comprehend the critique we offer in part four.
CHAPTER 1. INTRODUCTION 4
Part 4
Firstly part four will offer critique and conclusions on the JBoss AOP framework and
our experiences with it. Secondly it will offer conclusions on our communication of
the framework.
This report is for anyone interested in the JBoss AOP framework from a development
point of view.
Parts 1 and 2 should be sufficient for anyone interested in getting a head start to
using the JBoss 4 AOP framework. Part 3 is is for those who furthermore wants to
know about and learn from the design and implementation in detail.
Developers should benefit from this report by getting a thorough knowledge of using
the framework effectively. It should also be a supplementary help for decision makers
about to choose between different aspect oriented frameworks.
1.4.1 Prerequisites
To limit the scope and length of this report there are a number of prerequisites that
we expect readers to have knowledge about. These are:
Design patterns.
Basic knowledge of Java 2 Enterprise Edition (J2EE) and Enterprise Java Beans
(EJB). (A very short introduction to these is provided in appendix A.1)
As explained in section 1.3 this report is divided into four parts each covering a num-
ber of subjects. Here we give a short ouline of the parts and the chapters they contain:
Part I Part II Part III Part IV
A First Look at JBoss, Aspect Creating Your Own AOP-
Critique, Conclusions and
Oriented Programming and our Applications and AOP- JBoss AOP Framework Internals
Evaluation
Case Study services
Part 1: A First Look at JBoss, Aspect Oriented Programming and our Case
Study.
A short introduction to the JBoss application server.
An introduction to aspect oriented programming.
The example application is introduced.
7
Part Overview
The chapters in this part will lay the foundation for understanding the rest of the
report.
8
Chapter 2
JBoss
This short chapter will provide a short introduction to the JBoss application server
and the features for managing the server and its deployed applications.
The JBoss application server (currently version 3.x) is widely regarded as a J2EE
application server, even though it has not been certified as such. With the next re-
lease of the server JBoss 4 the server will be certified by Sun Microsystems as
a J2EE 1.4 application server. JBoss is open source and licensed under the GNU
Lesser General Public License (LGPL).
With JBoss 4 the JBoss Group (the organisation behind the JBoss server) has decided
to extend the functionality of the JBoss server, so it no longer is only a J2EE server.
With the emergence of aspect oriented programming techniques the JBoss group has
seen a way to ease the development cycle of applications that need services like those
provided by J2EE. Instead of developing cumbersome Enterprise Java Beans (EJBs)
it should be possible to develop ordinary Java classes free of restrictions such as
those of EJB and offer the same services that EJBs benefit from to these ordinary
classes. The services are added to the classes with aspect oriented techniques.
The server version we have used throughout this report is a checkout from the JBoss
CVS head branch from 16th of December 2003: JBoss 4.0.0DR3(200312161202), Ver-
sion Name: Zion
9
CHAPTER 2. JBOSS 10
We briefly describe Management Beans (MBeans) and the JBoss web-console here.
We will refer to both MBeans and the web-console from time to time in the rest of
the report. This section is not meant to be exhaustive for a longer explanation and
references to more information see appendix A.2, A.3 and A.4.
MBeans are a part of the Java Management Extensions (JMX) specification and can
be used to manage a manageable component. An MBean is a Java Bean with a few
more restrictions. MBeans are deployed in an MBean server in this case JBoss is
the MBean server and they have a management application that can be used to
configure and access them. In JBoss the web-console is the management application.
In the web-console the MBeans are listed and their methods can be invoked through
the web interface. When a method is invoked on an MBean, the MBean invokes an
appropriate method on the component it manages. The manageable component can
be a part of an application deployed on the JBoss server.
Generally in software development the design process is about breaking down the
system into units of behaviour or function. This is often referred to as functional
decomposition [10]. A reduction of the complexity in a system is achieved by splitting
a vast subject-domain into smaller intelligible units. Dijkstra talks about separation
of concerns in 1976:
The object oriented paradigm has brought into the picture a way to modularize con-
cerns by building hierarchies of classes through classification and specialization.
11
CHAPTER 3. ASPECT ORIENTED PROGRAMMING 12
But across these hierarchies concerns may exist that are not possible to generalize
through inheritance or polymorphism. Having decomposed the system into a class
hierarchy, some general issues cannot be dealt with in a modularized way. These
concerns are called crosscutting concerns.
The presence of crosscutting concerns basically shows in two ways: (1)By leaving
the actual functionality scattered across multiple classes as redundant code. This
condition is called scattering [15]. (2) When two or more collocated concerns overlap
each other the code is said to be tangled. With Kiczaless words,
Implementing the logging concern will result in logging statements scattered across
a wide range of classes and the symptoms will include:
Redundant code
Unclear structure
Maintainability problems to change something you would have to find all oc-
currences of a certain piece of logic, change it everywhere and be sure not to
introduce new errors
Code in a class that is irrelevant to the concern of the class (eg a logging mech-
anism)
Crosscutting concerns are often identified at early stages in the design process, but
there are no silver bullet solutions to the problems mentioned above. Object oriented
solutions to deal with crosscutting concerns can be found in the use of design pat-
terns. Design patterns are general solutions to common design problems and some
of them are used for separating crosscutting concerns [9]. Here are a couple of exam-
ples:
CHAPTER 3. ASPECT ORIENTED PROGRAMMING 13
The Visitor design pattern makes it possible to extend the functionality of classes
across the class hierarchy, but even if there is a separation of concerns in this
pattern, the coupling between the visited object and the visiting object is rather
tight.
The visited objects cannot be oblivious to the visiting object, and the visiting
object cannot treat the visited objects in a general way, but will have to know
the exact nature of each member of the visited family of objects. A complex vis-
itor implementation can be hard to maintain, as adding of visitor functionality
requires that new code is added to the visitor hierarchy and maybe also to the
methods in the visited object tree.
In the Observer pattern a number of Observer objects registers with a Subject. The
subject notifies the observers of changes to its state. The primary concern for
the subject is not necessarily the notification of observers and a subject can be
part of several observer patterns with different purposes. The observer pattern
separates the state of an object and the presentation of that state on changes,
The subject only has to implement the simple notification of attached observers
on updates.
Many design patterns are a good and very common solution to minimizing the tan-
gling of code, but as we shall see there are other ways to do it.
As we have tried to explain, it is not a trivial thing to separate concerns that inter-
twine. In aspect oriented programming the idea is that the existing way of modular-
izing traditional OOP concerns organized by classification and specialization should
be kept.
Concerns that are crosscutting should be modularized themselves and isolated from
the existing code. These isolated concerns are the aspects of aspect oriented program-
ming. In the logging example above the logging functionality can be identified as an
aspect that should be implemented by itself.
Class 1 Class2
+a() +uniqueMethod()
Log.print("doSomethingImportant();"); Log.print("powerMethod()");
Log.print("a()"); Log.print("uniqueMethod()");
AOP can be classified as a new layer on top of object oriented programming. It sup-
plies a new level of abstraction, both as a way of thinking software design and a way
of actually implementing it
In his introductory paper, Kiczales defined what the basic properties of an aspect
oriented implementation should consist of:
(a) a component language with which to program the components, (b) one
or more aspect languages with which to program the aspects, (c) an aspect
weaver for the combined languages, (d) a component program, that imple-
ments the components using the component language, and (e) one or more
aspect programs that implement the aspects using the aspect languages.
[10] p. 235
Here components corresponds to classes and packages from the vertical decomposi-
tion.
The aspect programs must be weaved into the components by the weaver. Looking
at figure 3.1 the points at which this weaving should be made is easily identified as
the places where there are logging statements. The places where the vertical and
horizontal structures intersect are called joinpoints or pointcuts and this is where
the component code and the aspect code is weaved together.
these pointcuts so the aspect weaver can merge the code. A pointcut will typically be
a field, a constructor or a method in a specified range of classes. The aspect code that
should be executed at that point will have access to the context of the pointcut that
is the arguments passed and local variables in the target class.
The implementations of AOP currently available on the market use quite different
approaches in that they vary in pointcut model, aspect language and aspect weaving.
AspectJ
AspectJ [3] is the oldest implementation and has been developed by Gregor Kicza-
les [10]. The aspect language in AspectJ is Java with some syntactical extensions.
Aspects are modularized into separate units not unlike classes. The weaver is a pre-
compiler that produces valid Java source code. AspectJ does not yet support runtime
bytecode weaving.
AspectWerkz
JAC
JBoss AOP
JBoss-AOP [14] is the Java AOP architecture used for the JBoss application server.
It uses runtime weaving, and Java and XML as the aspect languages. It comes with
a range of aspect components.
Nanning
Nanning [16] is another open source AOP project. It uses dynamic proxies for runtime
weaving. Dynamic proxies is part of Java 1.4.
If the result of the functional decomposition constitutes the core functionality of the
application, then the identified aspects can be seen as a service (or add-on) for the
core application. This is the case for the logging example in figure 3.1. The aspect
component can be called an aspect oriented service or AOP-service in short, which is
the naming convention we use in this report.
General services are loosely coupled to the underlying application and can be used,
ideally, on top of any application. A general service could be for logging, persistence,
remoting, security or something similar.
Specific or custom services are tightly coupled to the underlying application. Such a
service is not meant to be widely ported but is written to supply a specific functional-
ity to a specific target.
Integration of the aspect components in the design from the start is a third way to
approach AOP development. This might be one of the most interesting things about
AOP seeing it as a new paradigm in software development, not on top of program-
ming.
Choosing any of the three approaches to aspect oriented programming has conse-
quences:
In the rest of this report we will refer to both general and custom services with the
term AOP-service.
Aspect mining is the process of analyzing existing code with the purpose of identify-
ing crosscutting concerns that could be extracted and re-implemented as aspect
components [2]. Several tools such as the Aspect Mining Tool [11] have been
designed for facilitating this analysis process.
Abstraction is generalizing more things into one, throwing away details, forgetting
differences and reducing volume. Aspect oriented programming is not necessarily
an abstraction put on top of object oriented programming, as the untangling merely
relocates the scattered code. Modularizing aspects is of course an abstraction, but
it is an abstraction at the well known object oriented level. The braintwisting thing
about aspect oriented programming is not abstraction, it is dimension. Developers
will have to grasp two dimensions at the same time, switching between a vertical
and a horizontal perspective and this puts a cognitive burden on the developer. With
the words of Karl Lieberherr:
CHAPTER 3. ASPECT ORIENTED PROGRAMMING 18
This burden should not be on developers but on the tools and methodologies. As an
example AspectJ has provided a plugin for Eclipse that supports the construction and
the visual representation of crosscutting aspects.
After this theoretical section on AOP we will proceed to the presentation of the case
application developed for this project. This application will be extended with an AOP
layer in chapter 6.
Chapter 4
This chapter will present the core application developed for this project. This will be
the empirical foundation for the practical work on AOP-services in chapter 6 and the
examples in the presentation of the JBoss AOP internals in part III.
To demonstrate the usage the AOP framework in JBoss 4 we have created an appli-
cation that uses a large part of its features. We wanted the application to be more
than just a simple example, and large enough to use several features of the AOP
framework in a natural context.
To meet our own requirements we decided to create an application for a domain that
would give us plenty of potential features and room for expansion. We also wanted
to make sure that a great deal of the features of the application would inherently
be crosscutting, since these would be prime candidates for separation into aspect
components, that can be plugged in and out of the main application.
We have not made a fully functional application since this is beyond the scope of our
thesis. However we have implemented a small core, which is sufficient to accommo-
date a range of AOP-services.
An inventory management system has potential for many features and expansions.
It is already a field with many well-established requirements [5].
The core contains only what is absolutely necessary to implement a simple inventory
management system:
19
CHAPTER 4. INVENTORY MANAGEMENT CASE INTRODUCTION 20
Our application is simply called "Inventory Management". Its overall goal is to han-
dle stocks of goods. Once all the goods have been collected from stock an invoice can
be created.
Creating an invoice concludes the transaction and the stock level of goods is decre-
mented with the amount shipped out.
In this chapter we will not go into details about the AOP-services mounted on top of
the core application, but rather defer this to chapter 5, where a description of how to
create an AOP-service is provided.
Figure 4.1 gives an overview of all the classes and their packages in the core applica-
tion.
This package contains the data objects of the application. If the application had been
persistent (a feature we have left out) almost all of these objects would have had their
state saved in some way.
IdUtil: A utility class for generating unique IDs for several of the classes in this
package. This utility is needed due to AOP remoting1 which requires that
Objects be registered with unique IDs. If the core application had been persis-
tent, something similar to this class would have been needed to create primary
keys for the objects (appendix M.2).
OrderList: A list that contains all Orders made in the system regardless of who or-
dered them. This OrderList only exists because the application is not persistent.
It can be compared to a table in a database. We use the list for keeping track of
the orders and to enable us to search for specific Orders. It is implemented as a
Singleton (design pattern, see [9]) (appendix M.4).
the design conventions of the Composite design pattern [9] with the addition
that a ProductComposite does not allow cyclic references (appendix M.7).
Type: A generic type of product. This could for instance be CPU or HDD. The
difference between a CPU Product and a CPU Type is that a Product is a
specific kind of CPU such as Athlon 1,2Ghz and the Type is just CPU. In
other words the Type is meant to classify a Product. A Product has methods
that returns its name (eg. Athlon 500+ Mhz) as well as its Type (eg. CPU)
((appendix M.9).
The classes in this package define functionality of the Inventory Management system
that links together some of the classes in the jboss.thesis.inventory.model package.
There are also classes that exist solely to make the functionality of the application
possible via JBoss AOP remoting.
IdUtil OrderList
-orders : ArrayList
Order 0..*
1 -quantity : int
1 interface 1 Type
Product
0..*
ProductComposite ProductImpl
In figure 4.3 we show how most of the classes in the packages jboss.thesis.inven-
tory.model and jboss.thesis.inventory.controller fit together on a class level.
CHAPTER 4. INVENTORY MANAGEMENT CASE INTRODUCTION 24
IdUtil OrderList 1
-orders
Order 0..*
1 -quantity : int
InventoryController
0..* 0..*
We have made a graphical client application that we use with the inventory manage-
ment application. The client program is a simple Swing application that has suffi-
cient functionality to exercise all the features of the core application.
Finish orders by creating invoices. (No invoice is actually created. Instead the
core application is told that an order is completed and that the stock levels of
the products in the order should be decremented).
In figure 4.4 the main window lists all orders in the system. One order has already
been created, but not yet processed by creating an invoice.
In figure 4.5 the window for creating or editing existing orders is shown. Products
can be added to the order. An order can be saved for later use or deleted. Once all the
products have been added to the order an invoice can be created. When an invoice
is created the number of Products in the Order is subtracted from the stock in the
management system on the server.
CHAPTER 4. INVENTORY MANAGEMENT CASE INTRODUCTION 26
The graphical client application can be run standalone or as a Java Web Start ap-
plication. In the latter case it needs to be deployed on the JBoss server as a web
application (.war file).
Now the client application can talk to the management system remotely, and use the
Products to create Orders.
This was the the core case application the inventory management system.
Turning back to JBoss the next part will be about the use of the JBoss AOP frame-
work. Firstly an introduction to using it, and secondly a presentation of the AOP-
services put on top of the core application.
Part II
27
Part Overview
The chapters in this part explain how to use the JBoss AOP framework.
Chapter 5 Using the JBoss AOP Framework. This chapter explains the differ-
ent parts of the JBoss AOP framework and how to use them when creating
AOP-applications and AOP-services.
28
Chapter 5
This chapter is an overview of the AOP framework in JBoss 4. It will be a quick run-
down off the basic concepts in the framework. Chapter 3 on aspect oriented program-
ming have provided the theoretical background and the examples given are taken
from the preceding chapter 4 on the inventory management system.
An overview of some of the main classes of the AOP framework can be found in the
appendices in part II.
In JBoss AOP a pointcut is a specific point in the thread of execution of the applica-
tion, where the new functionality is added in the form of interceptors. One could say
that the pointcut is the where and when of aspect oriented programming. The inter-
ceptor is the what that is, what logic to execute at the time a pointcut is reached.
The aspect weaving in JBoss is done by modifying the bytecode of the existing com-
piled classes. This process is called the instrumentation process or you could say
that the classes are being instrumented with aspects. It is necessary to tell JBoss
which classes should be available for AOP instrumentation. This is done in the AOP
deployment descriptor, jboss-aop.xml:
29
CHAPTER 5. USING THE JBOSS AOP FRAMEWORK 30
5.1.1 Pointcuts
Field-pointcut: Matches direct field access both from the within the class and
from other objects.
7 < method - pointcut class =" jboss . thesis . inventory . model .*" methodName =" setName ">
8 < interceptors >
9 < interceptor - ref name =" MyInterceptor "/ >
CHAPTER 5. USING THE JBOSS AOP FRAMEWORK 31
13 < caller - pointcut class =" jboss . thesis . inventory . model . Order "
14 withinMethodName =" createInvoice "
15 calledClass =" jboss . thesis . inventory . model . Product "
16 calledMethod =" decreaseStockBy ">
17 < interceptors >
18 < interceptor - ref name =" MyInterceptor "/ >
19 </ interceptors >
20 </ caller - pointcut >
21
22 < method - pointcut class =" jboss . thesis . inventory . model .*" methodName =".*" >
23 < interceptors >
24 < interceptor - ref name =" MyInterceptor "/ >
25 </ interceptors >
26 </ method - pointcut >
The three pointcuts in Listing 5.2 represent three different granularities. They all
match field access.
The field-pointcut (line 1-5) will match any access to the denoted field from any class.
The method-pointcut (line 7-11) is a more narrow match here the direct field-access
is not matched, only the set-method on the field, which provides a more economic way
of monitoring field access.
The caller-pointcut (line 13-20) is the most fine grained pointcut, letting us match
very special cases of method invocations. What the XML in the caller-pointcut states
is that:
3. The class from which the decreaseStockBy method must be called before any
interception can occur is the jboss.thesis.inventory.model.Order class.
4. Furthermore the decreaseStockBy method must be called from within the method
createInvoice() in the Order class.
The last method-pointcut (line 22-26) demonstrates how regular expressions are used
for the matching. This can be applied to fields, classes and methods.
CHAPTER 5. USING THE JBOSS AOP FRAMEWORK 32
For intercepting the various types of access to class, constructor, method or field JBoss
uses an Interceptor. An interceptor contains the code that will be executed when a
given pointcut is reached. The interceptor is a Java class that must implement the
Interceptor interface:
The framework calls invoke() on the interceptor and this method performs what
needs to be done at the particular pointcut. The interceptor has access to the context
data in the Invocation object.
When there are more than one interceptor associated with a pointcut, the intercep-
tors are said to be in an interceptor stack or chain. Every intercepted invocation runs
through all the interceptors in the appointed chain, calling them subsequently by
calling invokeNext() on the invocation (Figure 5.1).
Interceptors are not forced to call invokeNext() it is perfectly legal to break the in-
terceptor chain by returning a new Object(). But in doing so caution is called for. Not
only is it possible to change behaviour in classes by adding new code in interceptors,
but by breaking the interceptor chain it is also possible to change behaviour for other
interceptors that have been added to a pointcut.
Interceptors can be used to add code both on the way in and on the way out of the
intercepted method call, constructor call or field access, and it is possible to modify
the arguments on the way in and the return values on the way out. The return
value from invoke() is returned to another interceptor or to the calling object. An
example of an aspect where the return value of a method would be changed could be
an aspect for translating the return values of getMessage() invocations into German
an approach that could be useful for localization of error handling.
Although it is possible to call invokeNext() more than once, only the first time will
result in a valid value as the Invocation object manages the interceptor chain.
At (A) we get hold of the MethodInvocation object, then at (B) we take the object on
which the method was called and at (C) print out a log entry with the results of the
getName() method of the target object along with (D) the supplied argument to the
method. Finally (E) we pass on the request to the next interceptor in the chain. Note
that in the above example the logging is done before entering the method.
The interceptors are also specified in the AOP deployment descriptor. An interceptor
can either be a specific class like the DecreaseLoggingInterceptor or it can be created
by an interceptor factory class and configured with custom elements in the XML file.
3 < interceptor name =" AnotherInterceptor " factory =" MyInterceptorFactory ">
4 < myCustomParameter value ="42"/ >
5 </ interceptor >
6
14 < method - pointcut class =" jboss . thesis . inventory . model .*" methodName =".*" >
15 < interceptors >
16 < interceptor - ref name =" MyInterceptor "/ >
17 < stack - ref name =" InterceptorStack "/ >
18 </ interceptors >
19 </ method - pointcut >
The result of this configuration: Any call to any method in any class in the package
jboss.thesis.inventory.model will be intercepted in this order:
MyInterceptor SimpleLoggingInterceptor AnotherInterceptor.
The examples so far have shown how adding pointcuts and interceptors is done dur-
ing development in the AOP deployment descriptor. This means that pointcuts and
interceptors are deployed when the application loads.
CHAPTER 5. USING THE JBOSS AOP FRAMEWORK 35
But interceptors can also be applied runtime so long as the target class is marked as
advisable in the AOP deployment descriptor.
18 am . addInterceptorPointcut ( ip );
The code from listing 5.7 would go into a class used for controlling aspect behaviour.
This class could be a controller or support class for the application containing AOP-
services.
The AspectManager is a singleton class that manages all pointcuts and metadata in
the JVM. By adding an InterceptorFactory that creates a DynamicInterceptor (an
arbitrary example interceptor), an InterceptorPointcut "DynMethodPointcut" (line
9) is made, matching the setName() method on Product.
Finally the pointcut is added to the AspectManager (line 18), and now all instances of
Product in the JVM have been instrumented with a new pointcut and an interceptor.
This happens instantly across the JVM and the code contained in the interceptor can
potentially be thread-unsafe.
Adding global interceptors runtime is not recommended unless you know exactly
what classes are matched by your pointcut and how your interceptors affect these
classes.
Another way to use interceptors dynamically is by adding them per instance. Each
instance of an advised class has an associated ClassInstanceAdvisor:
CHAPTER 5. USING THE JBOSS AOP FRAMEWORK 36
The code block in listing 5.8 would also go into a class used for controlling aspect
behaviour.
Note that in this case a pointcut is not used to mark the place of interception. Adding
interceptors directly like this corresponds to using a class-pointcut. The matching
granularity is very coarse as the interceptor is invoked for every constructor, method
or field access. If you want to intercept a certain method call you must first filter out
field and constructor access and then filter out the irrelevant methods.
5.1.4 Metadata
In JBoss AOP the attachment of metadata to classes is specified in the AOP deploy-
ment descriptor. It can be attached to a whole class, a method or to a field.
The attached metadata will be accessible from interceptors that handle the object,
like this:
CHAPTER 5. USING THE JBOSS AOP FRAMEWORK 37
The metadata facility in JBoss AOP attaches attributes to classes, making the in-
formation available to a deployed AOP service as in our logging example. As shown
above, the metadata is not attached directly to the class but is placed centrally in the
AOP deployment descriptor file. A code generation tool like XDoclet [21] can be used
to generate the deployment descriptor if special JBoss AOP JavaDoc-tags have been
written in the Java source file. This approach makes it somewhat easier to keep the
source file and the deployment descriptor constantly synchronized with each other.
We will not cover the use of XDoclet with JBoss AOP in this report.
Besides using JBoss metadata to do static tagging of classes it is also possible to dy-
namically attach metadata to various scopes: per invocation, per thread, per instance
and as the default: per class. This provides the developer with a very flexible way of
controlling services and applications. The different scopes will result in different be-
haviour and although it is flexible the application may become more complex, putting
a cognitive burden on the developers.
Metadata can be seen as a way to add dynamic fields to the class with different scopes
from invocation to cluster, but without any kind of encapsulation metadata can be
overwritten by anyone who gets hold of the appropriate context. It is impossible to
place restriction on the access to metadata-attributes on advised classes.
Having identified a crosscutting concern for a wide range of classes, it has previously
been shown how to extend the functionality of the classes by intercepting various
kinds of access to chosen objects through pointcuts and interceptors.
interface
ReservationCounter
+getNumberOfReservations()
+incrementReservations()
+decrementReservations()
Product ProductMixin
1 1
load time. This allows typecasting the objects that have crosscutting concerns to the
same reference type, because they now implement a common interface.
Figure 5.2 shows the result of introducing the interface ReservationCounter to Pro-
duct using the mixin class ProductMixin. A class CallerClass that calls the intro-
duced methods cannot do so directly on a Product reference or by casting the Product
reference to a ReservationCounter. This would result in a compile error when compil-
ing CallerClass, as the Product the compiler knows is not instrumented. There are
two ways to call introduced methods:
Or: Do a dirty cast by first casting the Product to an Object. Then cast the Object
to a ReservationCounter and finally call the method on this.
CHAPTER 5. USING THE JBOSS AOP FRAMEWORK 39
In this section we will explain the shortest path to implementing an AOP-service us-
ing our case application as an example. Note that the examples in this chapter are
simplified and therefore not the actual implementations of the inventory manage-
ment system.
Designing an AOP-service can be seen as a process that takes a number of steps [1]:
4. Specify aspects.
In the example of a very simple logging service the concern is easily identified as
the need to apply logging to a wide range of classes. It is needed to log both object
creation and decrementation of the stock of a product. Logging can be identified as
a candidate aspect as it is a concern that cuts across otherwise unrelated classes.
We will focus on this for now. Note that there might be other concerns that are not
CHAPTER 5. USING THE JBOSS AOP FRAMEWORK 40
crosscutting, but they will be dealt with by traditional design methods. This is yet
another challenge for AOP to be integrated with existing methodologies, but we will
not deal with this here.
Making the logging aspect more concrete it shows that two kinds of events need to be
monitored: object construction and invocation of decreaseStockBy(int i) on Product.
Thus, after the when and where of the aspect have been found, the pointcuts can be
defined: a constructor-pointcut and a method-pointcut that matches the appropri-
ate methods. Each pointcut will need its own interceptor, as the two events should
be logged in different ways. The constructor-interceptor will log info about the con-
structed object and the method-interceptor will log information about the product
that has been decremented in the inventory:
17 < constructor - pointcut class =" jboss . thesis . inventory . model .*" >
18 < interceptor - ref name =" ConstructionLoggerInterceptor"/ >
19 </ constructor - pointcut >
20 </aop >
independently of our AOP-service, but it would not make any sense and the idea of
a core application should be seen as an architectural decision. It would never be
relevant to use the core application alone as it is far too stripped down for real use.
Here we take the consequence of this tight coupling and deploy the application and
the AOP-service together.
In the rest of the report we shall refer to an application that contains classes that are
meant to be extended with AOP-services as an AOP-application. This distinguishes
AOP-applications from normal applications that have nothing to do with AOP. It also
conceptually at least separates the AOP-service from the AOP-application, thus
stressing the fact that an AOP-service can be deployed independently of the AOP-
application it depends on. Using these terms the core application of our inventory
management system would be the AOP-application. The interceptors etc. that extend
the functionality of the AOP-application constitute the AOP-service.
As we have done in chapter 4, it is possible to create a client that can access the AOP-
application or AOP-service via JBoss AOP remoting. But at the time of writing, JBoss
AOP remoting functionality is not properly implemented and it has been difficult to
use this for remote access.
We briefly describe here what is necessary to use MBeans as frontend to the AOP-
application or AOP-service.
The code in listing 5.13 demonstrates how to get hold of a fictive AOP-application
from the web-console. Methods from the AOP-application that should be available
through the web-console must be specified in the MBeanExampleMBean interface. The
callSomeAOPClassMethod() method returns a string that will be printed out in the
console. The console can print out Strings as well as primitive types, when they are
returned from a method. Objects will return the result of their toString() method.
25 }
26
31 return s;
32 }
33
MBeans are packaged into .sar-files that must contain a directory called META-INF.
This directory contains a deployment descriptor for the MBeans that ends with -ser-
vice.xml. In order to be able to run our AOP-application with the AOP-service on
top, we must deploy the MBean along with it.
The AOP-application should be packaged in a .aop file, which is just an ordinary .jar
archive with a .aop extension. In the .aop file the jboss-aop.xml as described above
is placed within the META-INF directory. The .aop file is then put in a .sar archive with
the MBean facade classes. Figure 5.3 shows how the files are packaged in the .sar
archive.
The process of compiling and packaging the application and service can be automated
with the build tool Ant. See appendix T.2 "Building and deploying with Ant" for the
complete build script we have used.
CHAPTER 5. USING THE JBOSS AOP FRAMEWORK 43
J2EE application servers should provide a range of services available to EJBs run-
ning in the container. As JBoss 4 aims to provide the same kind of services for ordi-
nary Java classes through the AOP framework, AOP-services corresponding to some
of the EJB-services are under development and available in the Developers Release 3:
Transactions
Security
Remoting
Clustered Remoting
This chapter will provide a technical walkthrough of the AOP-services that extend
the functionality of the Inventory Management AOP-application (the core applica-
tion) we presented in chapter 4. The AOP-services have been selected with three
things in mind.
They should:
1. Be crosscutting in nature.
2. Provide us with the possibility of using several features of the JBoss AOP frame-
work.
Set a watch on a Product: The ability to add a special watch (or monitor) to a par-
ticular product at runtime. The watch notices and writes to a log whenever the
45
CHAPTER 6. INVENTORY MANAGEMENT CASE AOP-SERVICES 46
stock level of the particular Product is decreased. This can be used for monitor-
ing how many products are sold over a period of time; if the product is hot and
requires a higher minimum stock level.
Because we wanted the watch to be able to be added runtime to particular Pro-
ducts, we use per instance dynamic interceptors, since every product in the
Inventory Management application is an instance of either Product or Product-
Composite (section 6.2).
Logging creation of Products: A logging mechanism that is used to log the cre-
ation of new orders and new reservations. This enables us to make use of
constructor-pointcuts (Section 6.3).
We have chosen to create custom AOP-services that are applied on top of a specific
application. We have not chosen to create AOP-services that are more general like
the ones JBoss AOP offers, eg remoting transactions etc. We find that custom services
are better for illustrating how to use the AOP-framework.
In the following we will go through the different AOP-services. For each service there
will be a short presentation of what the service does, and then a presentation of
the classes and interfaces in the service. Finally there will be a description of the
deployment information in the AOP deployment descriptor for the service.
The idea is that a given Product has a minimum stock level that is checked against
the actual stock level of the Product. When an Order is processed (createInvoice()
is called), its stock level in the Product instance is decremented with the amount
of products in the reservations. The AOP-service compares the stock level to the
minimum stock level. If the stock level is below minimum a notification is created.
In order to implement the handling of minimum stock levels we need to fulfill the
following requirements:
The stock levels must be compared to the minimum stock when a product is
reserved. The minimum stock must also be compared to the total number of
reservations made of a particular product.
The Product interface must be extended so it is possible to get and set a total
number of reservations on a Product. The core application has no total number
CHAPTER 6. INVENTORY MANAGEMENT CASE AOP-SERVICES 47
MinimumStock: An interface that defines get and set methods for a minimum stock
integer.
Since the Unified Modelling Language (UML) does not have a way of modelling as-
pects and crosscutting concerns in a class diagram, we have invented one ourselves.
Figure 6.1 depicts a class diagram with our added syntax for modelling aspects and
crosscutting concerns. It shows introduced interfaces, method-pointcuts, and the in-
terceptors used to take care of minimum stock level control. It also includes the
classes from the core application that are instrumented with the changes from the
mixin class.
A box with round edges around a method, field or constructor illustrates a point-
cut. A text in the box describes the pointcut type.
Interceptor chains are illustrated with a heavy frame surrounding the intercep-
tor classes. An arrow connects a pointcut to an interceptor chain.
1 Note that the AOP deployment descriptor file must be renamed to jboss-aop.xml (see appendix
L.1)before deployment.
CHAPTER 6. INVENTORY MANAGEMENT CASE AOP-SERVICES 49
Interceptor chain
ProductConstructionInterceptor
interface
Product
Interceptor chain
ProductComposite ProductImpl MinimumStockInterceptor
Processing order
+decreaseStockBy(in i : int) +decreaseStockBy(in i : int) method-pointcut
+setType(in type : Type) method-pointcut
IncrementReservationInterceptor
Reservation
The only requirement in the AOP deployment descriptor for this service was to mark
the ProductImpl and ProductComposite classes as advisable.
The diagram in figure 6.2 illustrates the relationship between ProductImpl, Product-
Composite and the WatchListInterceptor.
CHAPTER 6. INVENTORY MANAGEMENT CASE AOP-SERVICES 51
WatchListInterceptor
ProductComposite ProductImpl Class-pointcut
+invoke() : object
+decreaseStockBy(in i : int) +decreaseStockBy(in i : int)
To implement a logging mechanism for the creation of new orders and reservations,
an interceptor was created:
To setup a logging service for new orders and reservations the following is added to
the AOP deployment descriptor:
The ModelConstructorLoggingInterceptor
Figure 6.3 illustrates the relationship between Order, Reservation and the ModelCon-
structorLoggingInterceptor.
CHAPTER 6. INVENTORY MANAGEMENT CASE AOP-SERVICES 52
To easily access the AOP-services described above, we have created an MBean called
AOPService. As all other MBeans deployed in JBoss it has an interface, AOPService-
MBean, that dictates the methods available in the web-console (see listing 6.3). Both
the AOPService class and the AOPServiceMBean interface are part of the package:
jboss.thesis.inventory.model.jmx.
At this point we have shown how it is possible to use JBoss-AOP for designing and
implementing AOP-applications. In order to use a framework like this effectively it
is good to know how it works. In other words: it is not sufficient to know how to sit
behind the wheel, you will need to look under the hood as well.
53
Part Overview
The chapters in this part aim at providing a description of the inner workings of the
JBoss AOP framework. The chapters are for those who want to understand how the
framework has been implemented.
54
Chapter 7
This chapter will provide a fundamental introduction to the relevant parts of the
JBoss server before we descend into the bowels of the AOP framework.
We will examine:
The main deployment sequence which services that are relevant to the AOP
framework are deployed at startup and how they are deployed.
Before explaining about the main deployment sequence, we would like to make a
distinction between two terms:
In the chapters below we talk about system-services (or simply services), which
are not to be confused with AOP-services. The system-services in JBoss are usu-
ally in the form of MBeans and can be anything from the services required by the
J2EE specification, such as transaction support for EJBs (see appendix A.1), to func-
tionality used by JBoss, such as a service that scans the file system for new applica-
tions to deploy. AOP-services are the aspect oriented layer put on top of an existing
AOP-application.
55
CHAPTER 7. BASIC JBOSS FUNCTIONALITY 56
instrumentation. The actual instrumentation of the classes occurs when the classes
are loaded. To get a better understanding of the instrumentation it is necessary to
explain the deployment. We start out by providing a quick overview of what happens
in the main deployment sequence.
In JBoss a deployer is a class that takes care of deploying services and applications
on the server. There are different kinds of deployers for different kind of services
and applications such as MBeans, web applications, EJB applications, and AOP-
applications. Firstly the MainDeployer is set up. The MainDeployer initiates the de-
ployment of all applications and services by finding the right deployer for the given
deployment. Apart from the MainDeployer two other deployers are initially set up
by the server the SARDeployer and the JARDeployer. The SARDeployer takes care
of deploying .sar files and -service.xml files. A -service.xml file is a deployment
descriptor used in .sar files that describes the services contained in the .sar file. A
-service.xml file can also be deployed alone, if the classes it describes are available
on the JBoss servers classpath. The SAR- and JARDeployer need to be initialized
before any other system services, since they are used to deploy other system services.
The main deployment sequence is initiated during the startup of the server, based
on the jboss-service.xml configuration file that specifies which MBeans should be
configured and deployed during startup. Among these services (MBeans) are some
that are essential to the deployment of AOP-services and AOP-applications. The
MainDeployer starts deploying the system services by deploying all the services in
jboss-service.xml.
The first thing the MainDeployer does is to find an appropriate deployer it can delegate
the deployment to. In this case it will be the SARDeployer. This is why the SARDeploy-
er must be started before the MainDeployer starts finding an appropriate deployer for
the XML file. The SARDeployer will parse the XML deployment descriptor and set up
and start all the MBeans specified in the descriptor. Among the MBeans are two that
are relevant to the AOP framework and our description of JBoss below:
We will explain the scanning process below. The above is a simplified description
of the main deployment process. For a more detailed look at this, see figure H.1 in
appendix H.
CHAPTER 7. BASIC JBOSS FUNCTIONALITY 57
As previously explained JBoss AOP modifies the bytecode of the classes that are
enhanced via AOP. These changes to the bytecode happen when a class is loaded by
the JVM. In other words the classes are changed to handle pointcuts, interceptors,
introduced interfaces etc. stated in the AOP deployment descriptor.
JBoss uses the open source framework Javassist [13] for bytecode manipulation.
Javassist is a class library for editing bytecode in an easy programmatic way and
provides a mechanism for getting the bytecode of a class and altering it before the
bytecode is loaded by the Java Virtual Machine.
The Javassist library contains abstractions of Java classes, methods, fields and con-
structors that can be used to alter the bytecode and it provides a source level abstrac-
tion for adding bytecode to a class, which means that one does not have to understand
or even see the bytecode of the class. A method can simply added by providing a valid
String of Java source code that Javassist then compiles and inserts into the class.
Without going into details about Javassist there are two core classes that should be
introduced:
CtClass: Represents a .class that is being manipulated. With this you can add
methods, change methods, add fields, change constructors etc. The changes
will not take effect before you write the CtClass either to bytecode in memory,
or in a .class file.
ClassPool: Can read bytecode from a .class file and provide a CtClass object. The
ClassPool can be considered a container for CtClass objects. It provides the
CHAPTER 7. BASIC JBOSS FUNCTIONALITY 58
7.4 Classloading
At the time of writing there are certain caveats to the way JBoss uses bytecode ma-
nipulation.
JBoss can only make bytecode changes to classes loaded by JBosss own class loader.
Classes loaded by a different class loader cannot be changed. In effect this means
that all classes loaded by the Tomcat Servlet/JSP container in JBoss (Servlets and
JSP pages) cannot be extended with JBoss AOP functionality. This is because Tom-
cat (and other thirdparty Servlet/JSP containers) uses its own class loaders that are
independent of the JBoss class loader. These independent class loaders do not have
the capabilities of starting the instrumentation process.
There has been talk about changing this behaviour in Jboss, so perhaps this is an
issue that will be resolved before the final release of JBoss 4.
This chapter has provided an introduction to subjects that are needed to understand
the description of the implementation of the AOP framework. The next chapter
presents a small two-class application that will be used as an example through chap-
ters 9-12.
Chapter 8
An Example AOP-service
E()
Uninstrumented
Caller
Class
return
Before we go into details with example, we would like to present a model of what
happens to an instrumented class. The model focuses on the interaction between a
calling class and a called class. This interaction will change when a class has been
instrumented. A normal interaction between two classes will appear as in figure
8.1. An event E will be initiated from a calling class to an uninstrumented class,
59
CHAPTER 8. AN EXAMPLE AOP-SERVICE 60
and a result will be returned. In this case the concept of an event refers to either a
constructor call, a field access or a method call.
If a class has been instrumented the interaction between classes will appear as in
figure 8.2. Every event E will be delegated to an advisor. An advisor is a class that
acts as a placeholder for interceptor chains for a particular class. The advisor will
initiate the process of going through the interceptor chain as described in section
5.1.2. The last interceptor in the chain will make sure that E is processed (the code
from the uninstrumented original class is run) and that it returns the result back
to the advisor. The advisor will return the result to the instrumented class which
will return it to the calling class. The instrumentation process will make changes to
a class so it can support the process outlined in the model. We will use this model
throughout the description of the instrumentation process.
Instrumented invokeNext()
Caller Advisor
Class invokeNext()
invokeNext()
invokeNext()
return return invokeNext()
retu
rn
The example is inspired by our inventory management case, however it will not be
used in full, as this would be too comprehensive. The example consists of only two
classes, an AOP deployment descriptor and a simple logging interceptor. In addi-
tion the example will use the introduced MinimumStock interface and corresponding
ProductMixin from the Inventory Management application.
8.2.1 ProductImpl
8.2.2 ClassUsingProduct
This simple class is created for the purpose of this example, and it is used to illustrate
changes made to a class using an advisable class, but the class itself is not marked as
advisable in the AOP deployment descriptor. The source code in listing 8.2 illustrates
the use of a ProductImpl inside this class. The ClassUsingProduct source can also be
found in appendix K.3.
6 public ClassUsingProduct () {
7 product = new ProductImpl (); // call constructor
8 product . name = " TestProduct "; // access field directly
9 }
10
17 }
18 }
8.2.3 LoggingInterceptor
This LoggingInterceptor is a simple interceptor that writes the name of the opera-
tion performed to a log-file. No source code is provided for this as it is only here to
illustrate how an interceptor is used by the framework and not how it is implemented.
This is the XML-file that describes the pointcuts and interceptors added to the exam-
ple ProductImpl. The AOP deployment descriptor contains the LoggingInterceptor, a
method-pointcut and a caller-pointcut that has the interceptor and an introduction of
the MinimumStock interface (listing 8.3). The deployment descriptor can also be found
in appendix K.5.
4 < interceptor name =" Logger " singleton =" true "
5 class =" jboss . thesis . inventory . service . logging . LoggingInterceptor ">
6 </ interceptor >
7
8 <method - pointcut class =" jboss . thesis . inventory . model . ProductImpl "
9 methodName =" getID ">
10 < interceptors >
11 < interceptor - ref name =" Logger "/ >
12 </ interceptors >
13 </ method - pointcut >
14
15 < introduction - pointcut class =" jboss . thesis . inventory . model . ProductImpl ">
16 < mixin >
17 < interfaces > jboss . thesis . inventory . service . MinimumStock </ interfaces >
18 <class > jboss . thesis . inventory . service . ProductMixin </ class >
19 < construction >
20 new jboss . thesis . inventory . service . ProductMixin ( this , 20 , 0 )
21 </ construction >
22 </ mixin >
23 </ introduction - pointcut >
24
25 <caller - pointcut
26 class =" jboss . thesis . inventory . model . ClassUsingProduct "
CHAPTER 8. AN EXAMPLE AOP-SERVICE 63
4 Loading
3. The class is waiting to be loaded by the JVM.
7 Loaded
Create an advisor for the current Class.
Move information on current class from the
8 Initialising Instrumented Class
AspectManager to the advisor.
Add generic methods to delegate field access, con-
9 Creating Class Instance
structor calls and method calls to the advisor.
Make changes to accommodate delegation to the
advisor.
6. Instrumentation is finished.
8. Information from tables in the Advisor is put into more specific tables in the
Advisor that represent each field, method and constructor.
Deployment of AOP-applications
This chapter will go through the deploying of an AOP-application, covering the two
highlighted boxes in the figure on the right.
Deploying
When an AOP-application is deployed a number of things happen:
Deployed
The server must activate the correct deployer for the applica- Loading
When the MainDeployer finds an .aop or -aop.xml file to deploy, it will delegate the de-
ployment to the AspectDeployer. The AspectDeployer will parse the AOP deployment
65
CHAPTER 9. DEPLOYMENT OF AOP-APPLICATIONS 66
init( info )
parseDocument( info )
The parameter info contains
information about the current
create( info ) deployment
deployXML(info.url)
loadURL()
deployXML(document, info.url)
deployMethodPointcut(element)
loadInterceptorsElement(element)
MethodPointcut
<new>
addInterceptorPointcut
The AspectManager singleton class is at the core of the deployment and instrumenta-
tion process. It holds information about all advisable classes, interceptors, pointcuts
etc. in a number of tables. These are the tables populated by the AspectXmlLoader,
and will be used when a class in an AOP-application is loaded and instrumented. The
core tables are displayed in table 9.2.
CHAPTER 9. DEPLOYMENT OF AOP-APPLICATIONS 67
When the AOP elements stated in the AOP deployment descriptor (listing 8.3) are
deployed, the following is put into the tables in the AspectManager (see table 9.2):
These will all come into use when the ProductImpl and ClassUsingProduct are loaded.
For more details on the classes mentioned above see appendix D.
In the next chapter the deployed application will be instrumented during the class
loading process.
Chapter 10
Instrumentation of Classes
This chapter will cover the 4 steps highlighted on the figure on the right: the loading
and instrumentation of classes with an emphasis on the instrumentation process.
operations. We outline the process but will leave out some details Deploying
and try to stick to the core details so as not to make it overly com- Deployed
will not strictly follow the chronology of the instrumentation pro- Initialising Instrumented Class
cess here. Instead we will use our example and break up the in- Creating Class Instance
The adding of generic methods that take care of delegating field access, instance
creation and method calls to the advisor.
69
CHAPTER 10. INSTRUMENTATION OF CLASSES 70
These two classes constitutes the advisor from the model in figure 8.2. Listing 10.1
shows the code that is added to the instrumented ProductImpl that has to do with
advisors. The complete instrumented ProductImpl class can be found in appendix
K.2.
5 static
6 {
7 aop$class$WithoutAdvisement
8 = Class . forName (" jboss . thesis . inventory . model . ProductImpl ");
9 aop$classAdvisor$WithoutAdvisement
10 = AspectManager . instance (). getAdvisor ( aop$class$WithoutAdvisement );
11 }
12
Furthermore a static reference to a Class object for the class being instrumented is
added. This will be used to acquire the ClassAdvisor from the AspectManager when
the static initialiser block in ProductImpl is running. In chapter 11 we will go into
detail about what happens when the static block is run.
In the beginning of the instrumentation process the ClassAdvisor instance that will
be referenced in ProductImpl will be created and added to the Advisor-table (table
9.2). It should be noted that if the ProductImpl class has previously been loaded but
subsequently unloaded by the garbage collector a new ClassAdvisor instance will not
be created. Instead it will be retrieved from the Advisor-table. This means that the
instrumentation will only occur once per deployment. If an instrumented class needs
to have its bytecode changed it must be redeployed.
CHAPTER 10. INSTRUMENTATION OF CLASSES 72
When the ClassAdvisor instance has been created it is time to move object repre-
sentations of pointcuts and metadata from the AspectManager into the ClassAdvisor.
Like the AspectManager, the ClassAdvisor contains a number of tables that hold these
object representations of AOP-elements. The main tables in the ClassAdvisor are
listed in table 10.2.
In our example the following is moved from the AspectManager to the ClassAdvisor of
the ProductImpl :
The MethodPointcut instance that was put into the Pointcut-table in section 9.4
is moved to the Advisor-pointcut-table.
Interceptors will not be moved until the static block in ProductImpl is running. The
caller-pointcut we added belongs to ClassUsingProduct. We will go into detail about
caller-pointcuts in section 10.7.3.
In the model of interaction between a calling and a called class in figure 8.2 we il-
lustrated how instance creation, method calls and field access are delegated to an
advisor. The framework adds a number of generic methods that take care of the dele-
gation to the ClassAdvisor. Listing 10.2 shows the format of such a generic delegation
method:
In some cases the generic methods will be declared static, eg when delegating static
method calls. The different elements of the method requires explanation:
Object obj[]: In the case of method and constructor delegation the object array
contains the arguments to the invoked method or constructor. In the case of
field access the first entry in the array contains a reference to the object in
CHAPTER 10. INSTRUMENTATION OF CLASSES 74
which the field is read. For field write the second entry in the array contains
the new value which should be written to the field.
value: In the case of method delegation this is a hash value of the called method.
In the case of constructor calls and field access delegation, this is an int repre-
senting the position of the field or constructor inside the class.
Table 10.3 illustrates what generic delegation methods the instrumented class can
contain for each kind of delegation event. Events can be: instance method calls, static
method calls, constructor calls, field read, field write or mixin introduced methods.
Furthermore the table shows which methods are called on the ClassAdvisor and with
what arguments.
CHAPTER 10. INSTRUMENTATION OF CLASSES 75
Method to delegate field read static trapRead(Object target, int index, Advisor classAdvisor)
access
target: The instance the field must be read from
index: An index value of the specified field
classAdvisor: ClassAdvisor for the accessed class
Method to delegate Field write static trapWrite(Object target, int index, Object value, Advisor
access classAdvisor)
In section 10.4 we described how methods were added to our ProductImpl in order
to delegate field access, constructor calls and method calls to the ClassAdvisor. The
framework must also change the ProductImpl to make sure that these newly added
methods in ClassUsingProduct are actually used instead of the original methods.
1. Method changes.
2. Field changes.
3. Constructor changes.
To allow interception of method calls, two changes are made for each method in
ProductImpl. Changes that facilitate the use of the newly added generic delegation
methods:
(a) Prepend method name with fully qualified class name, separating elements
with $.
(b) Append the suffix: $WithoutAdvisement
2. For every method in the class a new method will be created that wraps one of the
generic delegation methods. The original methods were renamed with the al-
gorithm in the previous step, so the original method names are no longer used.
As this would obviously break the functionality of the application (Product-
Impl.getID() no longer exists) it is necessary to give the wrapper methods cre-
ated in this step the names of the original methods. Listing 10.3 shows an
example of what such a wrapper looks like.
CHAPTER 10. INSTRUMENTATION OF CLASSES 77
The hasAspects() method in line 4 will return true if a pointcut has been applied to
a method in the ProductImpl.
In order to be able to intercept field access in the ProductImpl class, field access will
be changed to static method calls, that invokes one of the generic delegation methods
added in section 10.4. The framework must add two static methods for every field
in an advisable class. One for reading a field, and one for writing to a field. The
methods wrap calls to the generic field read and write delegation methods that were
previously added (table 10.3). Listing 10.4 shows examples of both read and write
methods:
In section 10.7.1 it will become obvious why the methods are necessary when we show
in detail how these field access methods are used in the ClassUsingProduct.
in ProductImpl a static method is created that calls the generic constructor delegation
method added in section 10.4. Since there is only one constructor in ProductImpl, only
one method will be added.
In section 10.7.2 a more detailed account of how these constructor methods are used
will be provided.
The framework must change the ProductImpl in order to handle the introduced in-
terface MinimumStock. As stated in the AOP deployment descriptor the introduced
methods should be implemented in the ProductMixin class. A number of changes are
made to introduce the interface and use the mixin class in ProductImpl:
1. The framework will add implements MinimumStock to the ProductImpl class dec-
laration.
2. A private field with the mixin class ProductMixin as type is added (listing 10.6).
4. The framework will add the introduced methods to ProductImpl. The methods
will wrap calls to the generic mixin delegation method that was added. Listing
10.8 shows an example of an introduced method.
Note that the mixin delegation method took a reference to the mixin instance as
an argument (table 10.3). This means that the call to an introduced method will
be delegated to the ClassAdvisor, and the ClassAdvisor will further delegate the
call to the mixin class when the interceptor chain has been processed.
Even though the ClassUsingProduct has not been marked as advisable, a number of
changes are still made to it. These changes are made when the ClassUsingProduct
is loaded and instrumented, not when the ProductImpl is loaded and instrumented.
The changes are:
The changes mentioned above will be described in the sections 10.7.1, 10.7.2 and
10.7.3 below.
All classes that use direct field access to an advisable class will have this replaced
with static method calls. In the ClassUsingProduct this means that:
As with the field access, the code for creating instances of advisable classes will also
be replaced by static method calls in ClassUsingProduct. This means that:
CHAPTER 10. INSTRUMENTATION OF CLASSES 81
Note that both field access and constructor calls inside the ProductImpl class itself
are changed in the same manner. This happens when the ProductImpl is loaded and
instrumented.
ClassUsingProduct must be changed to handle the caller-pointcut that runs the Log-
ger interceptor. The interceptor runs when the method getID() in ProductImpl is
called inside the getProductID() method in ClassUsingProduct.
The changes made to ClassUsingProduct are not very different from those needed by
an advisable class. A reference to a Class instance and a ClassAdvisor must be made
as is done for advisable classes in section 10.2.1. However, no ClassInstanceAdvisor
reference will be added. The object representation of the caller-pointcut in the Caller-
pointcut-table in the AspectManager must be moved to the Advisor-caller-pointcut-
table in the ClassAdvisor.
1. Search the ClassAdvisor for caller pointcuts where the non-advisable class (the
ClassUsingProduct) is the calling class.
(a) Find all methods that must be monitored for calls to a method in a class.
(b) In each method replace the method call with a call to invokeCaller(..) in
the ClassAdvisor.
CHAPTER 10. INSTRUMENTATION OF CLASSES 82
Caller-pointcut changes in a non-advisable class will only occur if a class has a caller-
pointcut applied to it in the AOP deployment descriptor. Hence it is not possible to
apply a caller-pointcut dynamically to a class that has not had one applied before the
class was loaded an instrumented.
There are a number of classes that are not allowed to be instrumented by the frame-
work. When the AspectManager begins the instrumentation of a class it will start by
CHAPTER 10. INSTRUMENTATION OF CLASSES 83
If the class is non-instrumentable, the translate() method will return null, and the
class will not be instrumented but loaded unchanged by the class loader.
When all changes have been made to the ProductImpl (or ClassUsingProduct) the
translate() method in the AspectManager returns the modified bytecode of the class
to the classloader. The classloader will load the class and the static block in the
class will run. Before we go into detail with what happens when this static block is
executed we present a class diagram (figure 10.2) that shows the implications of the
instrumentation on the ProductImpl class.
Now the AOP-application has been deployed, instrumented and loaded. The next
chapter describes the initialization of static blocks in an instrumented class.
CHAPTER 10. INSTRUMENTATION OF CLASSES 84
ProductImpl
Class
-aop$class$WithoutAdvisement : Class
-aop$classAdvisor$WithoutAdvisement : ClassAdvisor 0..1 1
#_instanceAdvisor : ClassInstanceAdvisor
+_getAdvisor() : ClassAdvisor 0..1
+_getInstanceAdvisor() : InstanceAdvisor
+_setInstanceAdvisor() 1
ClassAdvisor interface
Interceptor
1 1 0..1 0..*
0..*
0..*
ProductMixin ClassInstanceAdvisor
1 0..1
Chapter 11
Initializing an Instrumented
Class
In Java static blocks are run just after the loading of classes, and this is utilized by
the AOP framework for the initilization of the instrumented classes. This chapter
will describe this process.
11.1 Overview
loaded by the JVM the static block will be executed, thus ini- Deploying
as an argument.
Instrumenting
The getAdvisor() method will find the ClassAdvisor that was
Instrumented
created and put into the Advisor-table in the AspectManager
during instrumentation. When the ClassAdvisor is found, the Loaded
getAdvisor() method will fill the interceptor tables in the Class- Initialising Instrumented Class
Four tables in the ClassAdvisor must be filled with interceptor chains (see table 10.2):
1. The Method-interceptor-table.
2. The Field-interceptor-table.
3. The Constructor-interceptor-table.
4. The Caller-interceptor-table.
85
CHAPTER 11. INITIALIZING AN INSTRUMENTED CLASS 86
How each of these are filled will be described in sections 11.2, 11.3, 11.4 and 11.5.
In order to fill the Method-, Field- and Constructor-interceptor tables in the ClassAd-
visor the Advisor-pointcut-table (see table 10.2) will be searched for method-, field-
and constructor-pointcuts matching the ProductImpl class. Each pointcut has a num-
ber of interceptors, and these interceptors will be put into the appropriate interceptor
tables.
For each method in an advisable class a MethodInfo object is created and added to
the Method-interceptor-table. A MethodInfo object holds information about a given
method in an instrumented class. Most importantly it contains a list of interceptors
for the particular method. The method-pointcuts found in the Advisor-pointcut-table
are checked for referenced interceptors and these are added to the list in the Method-
Info. In addition, interceptors referenced from class-pointcuts are added to the list.
A MethodTailInterceptor is added at the end of the list. The MethodTailInterceptor
will make sure the intercepted method is called (reflectively) and the resulting value
will be returned.
For each calling method in a calling class, tables of classes called are put into
the Caller-interceptor-table.
The tables of called classes are filled with tables of called methods.
The tables of called methods are filled with Interceptor arrays the interceptor
chains..
At this point the AOP-application and AOP-services are deployed, loaded, instru-
mented and initialized. The next chapter will show what is going on when the appli-
cation is actually running.
CHAPTER 11. INITIALIZING AN INSTRUMENTED CLASS 88
Calling Methods in
Calling Class
Called Methods in Called Methods in Called Methods in Called Methods in Called Methods in Called Methods in Called Methods in
Class X Class Y Class X Class Y Class Z Class Y Class Z
doP() doQ() doQ() doR() doP() doP() doQ() doP() doP() doQ() doR() doP()
Interceptor Array
Interceptor Array
Interceptor Array
Interceptor Array
Interceptor Array
Interceptor Array
Interceptor Array
Interceptor Array
Interceptor Array
Interceptor Array
Interceptor Array
Interceptor Array
Chapter 12
Instrumented
As explained in section 10.7.2 all constructor calls are replaced by calls to static meth-
ods added to the instrumented class. The sequence diagram in figure 12.1 illustrates
the process from a call to such a static method in ProductImpl until a new instance is
returned. The numbers in the list below refer to the numbers in figure 12.1.
1. The call to the added static constructor-method is delegated to the generic con-
structor delegation method.
89
CHAPTER 12. USING INSTRUMENTED CLASSES 90
ProductImpl_new_$WithoutAdvisement()
1
_added_m$3( new Object[0], 0 )()
get( int )
returns Interceptor[]
3
new ConstructorInvocation( Interceptor[] ) invocation : ConstructorInvocation
invoke( invocation )
Constructor.newInstance()
6
Creates a java.lang.reflect.Constructor
object and calls newInstance( args[] ) on it.
(The args[] is empty) and thereby running
ProductImpl's real constructor.
with constructor arguments, (b) the ClassAdvisor instance for the instrumented
class and (c) an integer representing the called constructor.
3. All interceptors for this particular constructor are found in the Constructor-
interceptor-table (table 10.2). A ConstructorInvocation instance is created that
contains the interceptors (see appendix F for class descriptions).
5. (Not pictured in the diagram) Each interceptor in the chain calls invokeNext()
on the invocation instance which in turn calls invoke on the next interceptor in
the chain. This way the entire chain will be processed.
In section 10.7.1 we explained that field access was replaced by static method calls.
The way field access is handled is very similar to the way instance creation is handled.
A sequence diagram of this process would be very similar to the diagram for instance
creation (figure 12.1). The main difference is that the invocation object will be a
FieldInvocation and that a FieldTailInterceptor will be at the end of the chain.
The FieldTailInterceptor will take care of reading or setting a value on the field via
reflection. For a more detailed look at the interception of instance creation and field
access see diagram J.2 in appendix J.
The sequence diagram in figure 12.2 illustrates what happens when the method
getID() is invoked and intercepted in a ProductImpl instance. The numbers in the
list below refer to the numbers in figure 12.2:
1. The call to getID() is delegated to the generic invoke method with an Object
array with the arguments to getID() and the hash value of the called method.
The generic invoke method delegates the call by calling invokeMethod on the
ClassAdvisor.
3. Then the MethodInfo object associated with the called method is retrieved from
the Method-interceptor-table (table 10.2).
_instanceAdvisor : ClassInstan
product : ProductImpl advisor : ClassAdvisor info : MethodInfo
ceAdvisor
getID()
_getInstanceAdvisor() 2
_instanceAdvisor
Interceptor[] aspects
new MethodInvocation(aspects) invocation : MethodInvocation
methodHash = methodHash
5 arguments = args
targetObject = product
method = info.advisedMethod
Interceptor invokeNext()
invoke(invocation)
invokeNext() 6
result of invoke to the original method
result : Object
result : Object
6. The interceptor chain is processed by having all but the last interceptor in the
chain call invokeNext on the invocation object, which in turn calls invoke() on
the next interceptor in the chain.
jboss$thesis$inventory$model$ProductImpl$getID$WithoutAdvisement()
When invoke() is called on the MethodTailInterceptor it will call invoke() on the
Method instance with the following arguments: (a)An Object array of arguments to
the renamed getID() method, and (b) the reference to the instance the method should
be invoked on (ProductImpl). This process is illustrated in figure 12.3.
interceptor : MethodTailInterc
invocation MethodInvocation eptor method : Method
invoke( invocation )
Object result
Object result
When explaining instance creation and field access interception we left out the Class-
InstanceAdvisor. The interceptor lists in the ClassInstanceAdvisor are also ap-
pended and inserted into the interceptor chain for instance creation and field access
just as they are for interception of methods.
productImplsAdvisor :
caller : ProductUsingClass callersAdvisor : ClassAdvisor invocation : CallerInvocation CallerTailInterceptor Method product : ProductImpl ClassAdvisor
product.getID()
1 The callingHash is used as key to
invokeCaller(callingHash, "jboss.thesis.experiments.ProductImpl"
, calledHash, p, new Object[0]) retrieve a table of called classes. The
Interceptor[] aspects string name of the called class is used
as key to retrieve a table of called
new (aspects) methods from the table of called
classes. The calledHash is used to Each interceptor will call
set some values retrieve an interceptor chain from the invokeNext() on the
table of called methods. 2 invocation object which in
invokeNext() 3 turn will call invoke on the
call invoke on the first interceptor in the chain (aspects) next interceptor. The last
interceptor will be a
invoke(invocation)
CallerTailInterceptor.
4
invoke(product,invocation.arguments)
getID()
invokeMethod(..)
result Object
result Object
result Object
result Object
result Object
result Object
result ((Long)Object).longValue()
2. The interceptor chain matching the caller-pointcut is extracted from the Caller-
interceptor-table structure (section 11.5).
If the called class has any method pointcuts, the process will then continue as illus-
trated in figure 12.2.
Until now this report has been rich on information and especially the previous five
chapters have provided an exhaustive detailed description on the internal processes
in JBoss-AOP. The next part is devoted to digestion in the form of conclusions on our
work, wrapping up the report.
Part IV
95
Part Overview
The chapters in this part contains an evaluation and critique of the JBoss AOP frame-
work and also the conclusions we have come to since we started work on our thesis.
96
Chapter 13
The preceding chapters have provided the reader with an understanding of the JBoss
AOP framework on two levels:
What is the JBoss AOP framework, what does it offer and how can it be used to
implement aspect oriented applications and services.
This discussion can be considered as an evaluation and critique of the JBoss AOP
framework. We will cover the following subjects:
97
CHAPTER 13. REFLECTIONS AND CONCLUSION ON JBOSS 4 98
Ideally an AOP-application and its AOP-service should be kept apart because it al-
lows two different deployments and also allows the development of AOP-services to be
independent of the development of AOP-applications. However, it turns out that this
separation can sometimes be difficult to achieve. At load-time an AOP-application
can implicitly be dependent on classes normally packaged together with the AOP-
service, and therefore the AOP-application cannot always be oblivious of the AOP-
service. In these cases the AOP-application has a tight coupling to the AOP-service.
Imagine an AOP-application that contains the class A that will have interface B intro-
duced. The AOP deployment descriptor for the AOP-application has only one entry,
which states that A is advisable. The introduction-pointcut for addding B to A is placed
in the AOP deployment descriptor for the AOP-service along with interceptors and
various helper classes for the service.
2. The JVM loads class A because it is referenced by some other class that is loaded.
Class A is advisable and gets instrumented which results in a ClassAdvisor for
A being stored in the AspectManager.
3. The AOP-service is now deployed along with its introduction-pointcut that in-
troduces interface B to A.
4. The AOP framework tries to extend A with B, but discovers that A already has
a ClassAdvisor and stops. A class in the AOP-service that uses A never realizes
that A was not extended with B.
This scenario can be avoided entirely if the AOP-service is packaged as part of the
AOP-application. If this is not desirable, the introduction can be packaged together
with the AOP-application, separating it from the rest of the AOP-service. But every
change to introductions in the AOP-application will then require the AOP-application
to be redeployed.
CHAPTER 13. REFLECTIONS AND CONCLUSION ON JBOSS 4 99
Until the day JBoss allows runtime changing of bytecode, there will be potential
problems in separating the AOP-service form the AOP-application.
The documentation available for the AOP framework is slightly too optimistic. We
have not been able to make AOP remoting work without modifying the ClassAd-
visor class. If a method with arguments was called on a remote object, the ar-
guments of the called methods were not passed on once the method call reached
the server-side object. We found that adding this line: nextInvocation.arguments
= methodInvocation.arguments; to the dynamicInvoke method made it work.
This small error is what you can expect from an unfinished product and is not some-
thing we hold against JBoss. Given the problems and frustration we have experi-
enced we hope that these mistakes will be removed before the final release.
Once we got the remoting part to work, we should have been able to make the objects
in the inventory management application work remotely very quickly. This should
have been easy, but turned out to be a hard nut to crack. Again this has to do with
AOP remoting being unfinished, but only partially.
One of the biggest problems with AOP remoting is the dynamic downloading of classes
from the server to the client. In systems such as Java RMI this process is almost in-
visible: An object is declared remote or not and the RMI subsystem automatically
figures out whether a remote reference to the object should be created and sent to
the client, or if a copy of the object should be serialized to the client. This invisibil-
ity makes it very easy to use Java RMI. In JBoss AOP remoting it is not quite as
invisible.
Note that the JBoss AOP remoting is not the same as the remoting facilities already
existing in JBoss. AOP remoting is JBoss remoting implemented using the AOP
framework. It is implemented as a general AOP-service.
CHAPTER 13. REFLECTIONS AND CONCLUSION ON JBOSS 4 100
Whenever a new object that should also be remote is created, a proxy for the object
must also be created. The proxy can be bound in the JNDI tree where clients can look
it up and the original object must be registered with the AOP Dispatcher object.
Creating the proxy cannot be done in the constructor of the object as the proxy itself
creates an instance of the original object on construction. This would result in a stack
overflow error due to a cyclic reference.
These difficulties may sound trivial, but they are not. In some cases we have not been
able to figure out if a local or remote object was needed and in other cases a proxy
seemed to work when only the original object should have worked. There is no doubt
in our minds that an abstraction like the one made in Java RMI would enhance the
usability of JBoss AOP remoting considerably.
One of the requirements of AOP remoting is that the remote object has a default
empty constructor. We find this somewhat restrictive. It is not a serious problem,
as it is an issue that can easily be worked around by the use of a factory, but it is
nonetheless an annoyance.
Lastly, we have found that the equals method does not work as expected when an
object is both remote and not. In our first implementation of the equals method in
ProductImpl we had a line that checked if the calling classs type was equal to the
arguments (obj) type:
Our implementation of the equals method checks if the IDs of the ProductImpls are
equal. In non-remote objects this method call would return true if the instances
were of the same type and had the same ID. But in AOP remoting it may return
false, even though the instances have the same ID, because it is possible that the
calling instance and the argument are not of the same type. This happens when the
equals method is run on the original object with a proxy as its argument. In that case
the calling instance is an instance of the class jboss.thesis.inventory.model.Pro-
ductImpl, and the argument obj is an instance of org.jboss.aop.proxy$jboss.the-
sis.inventory.model.ProductImpl which extends ProductImpl. In the end we found
an implementation that can match proxies with original objects (see the source code
of ProductImpl in appendix M.6).
Overall we found using AOP remoting a difficult task. Some of our difficulties were
due to the unfinished status of the framework, some could be due to lacking features
or to poor design. It is difficult to tell if lacking features (such as an abstraction
over the dynamic downloading of classes) are because of the unfinished framework,
or simply because it is a feature that was never planned for JBoss remoting.
Since we are not into all details of JBoss remoting, it can be that we have insufficient
knowledge to use it properly, but the fact remains: We found it prohibitively difficult
to work with.
The JBoss AOP framework is very flexible and AOP-services and AOP-applications
can be customized in almost every possible way. But the flexibility comes with a price:
it is not quite the simple silverbullet-solution promised by the JBoss Group.
Interceptors can be applied per instance or per class in a scope ranging from
thread to cluster and implement different functionality.
Metadata can also be applied dynamically with the same scope as the intercep-
tors.
These three variables can result in a vast number of combinations and hence applica-
tion behaviour. Even though it seems simple it can be quite a burden to grasp just the
CHAPTER 13. REFLECTIONS AND CONCLUSION ON JBOSS 4 102
fact that a pointcut can match several classes and methods. It is easy to forget this
when developing an interceptor for a particular pointcut when writing the regular
expressions that matches the classes and methods. Add to this that the interceptor
can be applied to instances or per thread. The staggering number of combinations,
possibilities and sources of errors makes it quite difficult to use the framework. We
feel that it would probably be better to postpone the implementation of some features
until they were actually needed by someone, and thus lifting some of the cognitive
burden from the developers.
It is not sufficient that a complex framework such as JBoss AOP is efficient and
flexible. It should also be possible to understand. People must be able to grasp the
concepts one by one. At first they can understand it through a very abstract model,
like dividing the concerns into vertical and horizontal, and then, later on, in more
detail. The details become clearer when getting deeper into the framework and the
abstract model slowly turns more and more concrete, until people understand enough
to use their knowledge at the required level AOP-application programmers and
AOP-service developers require two different levels of insight.
This descendance into detail can be hindered by inconsistency in the mapping be-
tween the abstract and the concrete. We have found a few of these inconsistencies:
We find it confusing that the mapping between the layers of abstraction are not con-
sistent. The examples above are not grave problems, but they serve as an example of
what we believe is an important area in framework design: making it consistent and
easy to understand.
CHAPTER 13. REFLECTIONS AND CONCLUSION ON JBOSS 4 103
JBoss has provided an impressive framework when it comes to flexibility and dynam-
ics. There are a vast number of different approaches, wheels to turn and buttons to
push. But there is a lack of focus in the current version; it looks like JBoss AOP
wants to do everything at once.
When we approached the task of implementing AOP-services for the Inventory Man-
agement application we found it difficult to choose what AOP-elements to use. We
could have used metadata instead of introduction to add minimum stock control. We
could have loaded initial minimum stock values from custom XML-elements in the
interceptor element in the AOP deployment descriptor. These are just a few examples
of things we could have done and considered doing differently.
Choices are a good thing. They provide an opportunity to implement and adjust an
AOP-service to very specific needs. However, we feel that JBoss will have to provide
better guidelines for the intended use of the different AOP-elements, their benefits
and drawbacks. Often the design situation will provide suggestions as to which spe-
cific elements to use, but a guide of Best Practices would be a beneficial tool for
developers of AOP-services.
An evaluation of a framework like this must also take into consideration: what is
the cost of abstraction and flexibility when it comes to performance? In this section
we will present the results of a range of performance tests run on the JBoss AOP
framework.
In order to find out how the AOP framework performs we have conducted a series of
performance tests. (see appendix R)
As we have seen, the instrumentation process modifies not only the advisable classes,
but also un-advisable classes that create instances of or access fields in advisable
classes. Also un-advisable classes that are callers in caller-pointcuts are modified.
So in the tests we have found four scenarios relevant to test:
3. The called class has constructor-, method-, and field-pointcuts with a shared
interceptor that does nothing but call invokeNext() on the invocation object
CHAPTER 13. REFLECTIONS AND CONCLUSION ON JBOSS 4 104
4. The same as 3, but running in a HotSpot JVM using the -server switch.
Construction.
Method calls.
Field access.
The tests have been run from within an MBean (appendix R.1). All tests have first
been run 107 times to make sure that the HotSpot compiler has compiled the bytecode
into native machine code. Then the code is run another 107 times wrapped in a timer.
Furthermore all tests have been run twice. The first time a test is run the classes
have not been instrumented. This is designated as Unadvised in the tables below.
On the second run classes have been instrumented. This is designated as Advised
in the tables below. The ratio is the relative difference between the advised and
unadvised test runs. The results have been converted into time spent per method call,
per constructor call or per field access measured in nanoseconds (called ns/access
below). The tests were run on an IBM X23 866MhZ laptop with 392 MB ram. The
JBoss server was started with the default configuration, 128 allocated MB of RAM
and without the -server switch except where otherwise stated.
Method calls are both absolutely and relatively the least affected operations.
Field access and constructor calls are relatively the most expensive.
Constructor calls are modified in a similar way (see 10.5.3), and the number of oper-
ations added are also similar (see figure 12.1 in section 12.1).
Test: Advised Classes with Added Interceptors and Pointcuts Using the
-server Switch on the JVM
Figure 13.3: Advised with added interceptors and pointcuts, in the Server HotSpot
VM
In figure 13.3 we have used the -server command line switch when starting JBoss,
which selects the Java HotSpot Server VM mode as opposed to the default HotSpot
Client VM mode. The HotSpot VM optimizes hotspots places in the code that
are very busy. The Client mode is designed for fast start-up and low memory foot-
print. The Server mode gives higher operation speed by doing more aggressive code
optimization and dynamic profiling it is a slow starter but designed to host appli-
cations that run for a long time.
Here the HotSpot VM in server mode has done a good job optimizing the uninstru-
mented code, but it has not been able to optimize the instrumented/intercepted ver-
sion because of the reflective method calls.
13.4.2 Filters
There is a yet unimplemented feature, that does not work in this release. It is possible
to reduce performance hit by setting up filters like "field-filter: none", which means
that no fields must be intercepted. This removes the rather aggressive interception-
activity on field access if you do not need it.
The feature is documented but not implemented, so we have not been able to make it
work. Therefore we could not measure the difference it presumably would make.
CHAPTER 13. REFLECTIONS AND CONCLUSION ON JBOSS 4 107
Even though the JBoss 4 AOP framework is still under development and most likely
will improve in many ways, we still feel that a few suggestions for improvements are
in place.
The Javassist construct that adds a generic mixin delegation method uses a string
with the method signature and method body to add the method. When the framework
attempts to add a second mixin delegation method it will appear to Javassist as if the
framework is trying to add a method with the same signature (mixinInvoke(..)) once
more. However this time the method body will be slightly different (a different mixin
reference in the call to the advisor). Adding the method will fail because of name
clashing and the delegation method will not be added. Hence the first delegation
method added will be used by all introduced methods. We offer two slightly different
solutions to this problem:
Either: Give the method used to make the generic mixin invoke method a
unique name for each mixin class so the name clashing will not occur.
Or: Send the mixin reference as an argument to the generic mixin delegation
method from where it is called ie from the introduced method.
The JBoss AOP framework does not provide the possibility of applying pointcuts on
methods inherited from non-advisable classes. With a little work this feature can be
added to the AOP framework. Figure 13.4 illustrates how this can be implemented.
On the left side we have the situation before the classes have been instrumented.
A class C has a method callA() that calls the method a() on a B instance. A is un-
advisable and B is advisable. The method a() in B is inherited from A.
CHAPTER 13. REFLECTIONS AND CONCLUSION ON JBOSS 4 108
A A a_Advised(){
//delegate call to advisor that
//in the end will call a()
+a() +a()
}
B B
+a_Advised()
The following changes must be made in order to apply pointcuts on inherited methods
in B:
A method (a_Advised()) must be added to B. This method will delegate the call
to the ClassAdvisor which in turn will call a() on the B instance the call that
was originally intended.
The method call in C must be changed via instrumentation to call the added
method in B. This requires a cast of the a reference to the type B.
To really understand the AOP framework it has been invaluable for us to study the
instrumented classes. We have taken the changed classes, created .class files for
them and used a decompiler to get Java source code. But this is not as easy as it
sounds. The instrumented classes in the AOP framework are never actually written
to .class files they are bytecode manipulated in memory and only exist in memory.
Creating .class files for these manipulated classes can be done in several ways. It
could be done by either writing a tool in an MBean to access the Javassist ClassPools
CHAPTER 13. REFLECTIONS AND CONCLUSION ON JBOSS 4 109
in the AspectManager, or the AspectManager class itself could be changed to write the
classes to disk as they are loaded. We investigated the former but chose the latter as
it was the simplest solution.
Ideally a tool for writing these .class files to disk should be written as an AOP-service
that could dump .class files from various points of execution in the JBoss AOP frame-
work. But the JBoss system classes cannot be instrumented, so this approach is out
of the question.
Even though not all users of JBoss AOP are interested in how the framework works,
we believe that a service for dumping the class files will be interesting to a lot of
developers.
Long after we changed the AspectManager to dump the .class files this feature has
been implemented as part of JBoss 4 DR3 in the head branch of CVS. All instru-
mented classes are now written to a temp dir, so they can be re-loaded without doing
the instrumentation all over again. This is relevant when the JVM unloads classes
and then needs to reload them.
Here follows some conclusive and summarising remarks on the JBoss AOP frame-
work.
JBoss 4 and its AOP framework has offered us an excellent opportunity to learn
more about AOP and the design of large complex systems and frameworks. It has
also offered an opportunity for us to share this knowledge with other developers who
are interested in using JBoss 4s AOP framework.
A half-finished framework has the potential to render this document utterly useless,
because it might drastically change after this thesis is finished. However, it is our
firm belief that the AOP framework in JBoss has reached a level where changes to it
will not be of a fundamental character as in a complete rewrite. We therefore antic-
ipate that this report will still have its merits even when the framework is released
some time in the future.
Trying to understand the AOP framework we have read thousands of lines of code and
implemented numerous examples using the different functionalities that the frame-
work offers. As the framework is still under development these tasks can be very
tedious. While going through the framework implementation we have often felt that
discovering and understanding certain parts of the framework opened up a range of
new aspects to understand. This was especially true when trying to use remoting and
trying to understand undocumented code.
CHAPTER 13. REFLECTIONS AND CONCLUSION ON JBOSS 4 110
Although development using JBoss AOP is somewhat complex, we see the JBoss AOP
framework as a promising alternative to the complexities of J2EE.
On the one hand, the number of features and the ability to add pointcuts and inter-
ceptors dynamically to ordinary classes are strong arguments for using JBoss AOP
for developing middleware applications. On the other hand, the cognitive burden of
using all these features and keeping track of the different scopes and uses of pointcuts
is heavy. However, we believe that when JBoss 4 is released, proper documentation
and development guidance in the form of best practises will go a long way in mak-
ing the framework easier to use. It is our feeling, that for most developers it will
be easier to use the JBoss AOP framework rather than J2EE. This does not mean
that JBoss AOP will render J2EE obsolete. J2EE is a proven technology and still has
many features that JBoss AOP does not.
Chapter 14
In this chapter we will do a short evaluation of and conclusion on our own work and
the process we have been through. We separate the conclusions into two areas:
We have presented the JBoss AOP framework to software developers with an interest
in JBoss and the AOP framework, roughly divided into two groups: AOP-application
developers and AOP-service developers.
People who wish to understand the necessities of creating and deploying an AOP-
application or AOP-service can read part one and two that also serve as stepping
stones to part three, which is for those who are interested in further details on AOP-
service development and the AOP framework.
We also feel that the way we present the rather complex AOP framework is high level
enough to make it understandable for most people in the target groups. There is, of
course, always room for improvements.
If we had had the time, an area we could have improved is in the use of examples. We
would have liked to avoid using different examples in our report. We would instead
111
CHAPTER 14. EVALUATION OF THE PROCESS 112
have spent more time perfecting the Inventory Management example application and
let it be the only example application. The problem is that we have a fairly complex
example that is not suited for all chapters. The example application is either too
complicated or it lacks particular details needed for demonstration, and as such it
is hardly useful in any chapters without modifications. This is unfortunate since it
forces us to introduce several different examples that are more or less similar, albeit
simpler, versions of the main example.
We think that these different versions of the main example application can confuse
the reader, and it would be better if the example was one and the same throughout the
presentation. This would require more work on the example application possibly
extending it with functionality; but it would make the example consistent throughout
the report and thus save the reader from confusion.
Overall we are quite happy with the effort and the priorities we have made in the
past six months. During this time we have all worked on all subjects presented in
this report, so we have all got a fairly good understanding of the subjects covered. But
of course we have split up the work load, so some of us know more on some subjects
than the others. We might have been more effective had we not all been part of every
aspect, but we feel that getting an understanding of everything is more important
than being a little more effective.
Looking back on the past six months we can see that not all activities we undertook
were equally necessary, and some things we would have done differently were we
to start all over again. This should not be interpreted as if we are displeased with
everything we have done far from it! But in retrospect there are a few things to
reconsider:
Looking back we have spent a large amount of time on understanding and debugging
AOP remoting. Even though we have obtained valuable information about JBoss
while working with AOP remoting, we feel that we should have stopped working on
it much earlier. Turning our attention away from an unfinished service would have
given us more time to explore details of the actual framework instead.
CHAPTER 14. EVALUATION OF THE PROCESS 113
We also spent some time creating the graphical client application we have used to
access and test the inventory management system with. In retrospect we can see
that this was not really necessary. We could just as easily have used a simpler text-
based client or even just unit tests. Cancelling the client application would have
saved us only little time, but would have helped us keeping better focus on our main
purpose understanding and communicating the JBoss AOP framework.
Much of our time during the past six months has been used to unravel the JBoss
source code. This has been very worthwhile for understanding JBoss and the AOP
framework in detail. The only thing we could have wanted more was a little more
time to look into all the details of the framework.
It is probably naive to think that dead ends can be avoided in a project such as this,
but should we replan the whole thing there would have been a few things to do:
Another interesting project would have been to add aspect oriented persistence to our
case application, as this is one of the primary needs for almost any application.
Bibliography
[1] A. Moreira A. Rashid, P. Sawyer and J. Araujo. Early aspects: A model for
aspect-oriented requirements engineering. In IEEE Joint International Con-
ference on Requirements Engineering, pages 199202. IEEE, IEEE Computer
Society Press, 2002. <http://www.early-aspects.net/papers.html> link worked
on February 7, 2004.
[2] Arie van Deursen, Marius Marin and Leon Moonen. Aspect mining and refactor-
ing. In Proceedings of the First International Workshop on REFactoring: Achieve-
ments, Challenges, Effects (REFACE03). University of Waterloo, 2003.
[6] Joshua Bloch. Jsr 175 a metadata facility for the java programming language.
Technical report, Sun Microsystems Inc., 2003.
[10] Gregor Kiczales, John Lamping, Anurag Menhdhekar, Chris Maeda, Cristina
Lopes, Jean-Marc Loingtier and John Irwin. Aspect-oriented programming. In
Mehmet Aksit and Satoshi Matsuoka, editors, Proceedings European Confer-
ence on Object-Oriented Programming, volume 1241, pages 220242. Springer-
Verlag, Berlin, Heidelberg, and New York, 1997.
114
BIBLIOGRAPHY 115
[15] Lieberherr, Karl and Lorenz, David H. and Ovlinger, Johan. Aspectual Collab-
orations: Combining Modules and Aspects This work was supported in part
by the National Science Foundation (NSF) under Grants No. CCR-0098643 and
CCR-0204432. The Computer Journal, 46(5):542565, 2003.
[17] The 4th aosd modeling with uml workshop, 2003. <http://www.cs.iit.edu/-
oaldawud/AOM/> link worked on February 7, 2004.
Short Introductions to
Technologies Mentioned in the
Report
1
Appendix A
The main way for a J2EE application server to provide these services to applications
running in it, is to provide a container for Enterprise Java Beans (EJB). The applica-
tions themselves are then typically implemented as EJBs, but they do not have to be.
Since management became part of the J2EE specifications (in J2EE 1.4) the use of
JMX (see A.2 below) has also been required. There are further requirements in J2EE
1.4. For a complete listing and all the specifications see the J2EE website [19].
Enterprise Java Beans (EJB) are standard software components defined in one of the
J2EE specifications. A J2EE server must provide an EJB container that offers the
above mentioned services to EJBs. Even though EJBs are standard components they
2
APPENDIX A. SHORT INTRO TO TECHNOLOGIES 3
are often surprisingly difficult to implement and maintain. Many different files are
needed to create and deploy just one EJB. With more EJBs the complexity goes up.
Even if EJBs are somewhat complex to develop and maintain, it is still vastly more
complex to hand code the services mentioned above.
JMX stands for Java Management Extensions and is, in short, a Java standard for
managing applications, appliances and environments dynamically. As everything
else in J2EE, JMX is merely a specification that the J2EE server providers must
implement themselves. JMX can be compared to the Simple Network Management
Protocol (SNMP) standard, which is a standard for managing networked devices.
However, JMX is much more flexible than SNMP.
The JMX specification consists of two main parts (for a full discussion on all fea-
tures and details of the JMX specification see [18] and [20]). The first part are the
manageable software components called MBeans. The second part is a server that
can contain the manageable software components and also provide a management
front-end to the components.
Managed Beans or MBeans are the software components that can be managed through
the JMX server (or MBean server). An MBean expose an interface that can be used
by the MBean server to call the methods on the MBean. MBeans themselves are,
in their simplest form, just normal JavaBeans with a few further rules to stick by.
They can, however, be more complicated and abstract. See the JMX specification for
further details [20].
Every MBean server must provide a front-end that can be used to manipulate the
MBeans deployed in the server. JBoss is no exception in this regard. JBoss includes
a web-console and a jmx-console that acts as front-end to all the MBeans running
in the server. The front-ends are HTML pages generated through Servlets and JSP
pages. This provides JBoss with an easy to use MBean front-end. All the methods of
the MBean that are manageable are put in the HTML page along with a button to
invoke the method.
Part II
5
Appendix B
B.1 Advisor
B.2 ClassAdvisor
B.3 InstanceAdvisor
6
APPENDIX B. SUPPORT CLASSES FOR INSTRUMENTED CLASSES 7
ClassInstanceAdvisor.
B.4 ClassInstanceAdvisor
B.5 InstanceAdvised
B.6 Advised
C.1 AspectManager
C.2 AspectXmlLoader
8
APPENDIX C. CLASSES FOR DEPLOYMENT AND INSTRUMENTATION 9
C.3 DeploymentInfo
C.4 Instrumentor
Pointcut Classes
D.1 Advisable
D.2 InterceptorPointcut
D.3 ConstructorPointcut
10
APPENDIX D. POINTCUT CLASSES 11
D.4 FieldPointcut
D.5 MethodPointcut
D.6 CallerPointcut
D.7 IntroductionPointcut
Interceptor Classes
E.1 Interceptor
E.2 InterceptorFactory
12
APPENDIX E. INTERCEPTOR CLASSES 13
E.3 ConstructorTailInterceptor
E.4 FieldTailInterceptor
E.5 MethodTailInterceptor
E.6 CallerTailInterceptor
Invocation Classes
F.1 Invocation
F.2 ConstructorInvocation
F.3 FieldInvocation
14
APPENDIX F. INVOCATION CLASSES 15
F.4 FieldReadInvocation
F.5 FieldWriteInvocation
F.6 MethodInvocation
F.7 CallerInvocation
F.8 InvocationType
Javassist Classes
G.1 ClassPool
G.2 CtClass
G.3 CtConstructor
16
APPENDIX G. JAVASSIST CLASSES 17
G.4 CtField
G.5 CtMethod
Diagrams
19
Appendix H
Deployment Diagrams
20
APPENDIX H. DEPLOYMENT DIAGRAMS 21
This diagram shows the sequence of operations in the MBean deployment process. Illustrates how the
MBeans in jboss-service.xml are deployed an started.
start()
start() is called on
the proxy instance
APPENDIX H. DEPLOYMENT DIAGRAMS 22
ServiceMBeanSupport
interface
ServiceControllerMBean
SubDeployerSupport
interface *
MBeanRegistration 1
MainDeployer
EARDeployer JARDeployer XSLSubDeployer AspectDeployer SARDeployer
1 ServiceController *
1 1
1
1
1
1 DeploymentInfo URLClassLoader
0..1
1 *
MBeanServer ServiceCreator ServiceConfigurator
* 0..1
* *
UnifiedClassLoader
1
APPENDIX H. DEPLOYMENT DIAGRAMS 23
start() is called on
UrlDeploymentScanners parents URLDeploymentScanner ScannerThread MainDeployer SARDeployer SubDeployerSupport
parent ServiceMBeanSupport.
startService() is called on the start()
parent startService()
AbstractDeploymentScanner.
MainDeployer is set as
UrlDeploymentScanners set as parent
deployer during configuration
from jboss-service.xml.
AspectManagerService MBeanServer
This is how the AspectManager is
told to handle the instrumentation of
createService()
classes.
setAttribute(DEFAULT_LOADER_REPOSITORY, AspectManager.instance())
APPENDIX H. DEPLOYMENT DIAGRAMS 25
NotificationBroadcasterSupport
+sendNotification()
+addNotificationListener()
+handleNotification()
* * *
SubDeployerSupport
MainDeployer Notification
* *
AspectDeployer AspectXmlLoader *
*
* *
* * *
DeploymentInfo
NodeList
#UnifiedClassLoader *
#SubDeployer
#URLClassLoader *
* #parent : DeploymentInfo 1
Appendix I
Instrumentation Process
Diagrams
The instrumentation process is illustrated in the Diagram in figure I.1 and six refer-
enced sub-diagrams (figures I.2 to I.7).
26
APPENDIX I. INSTRUMENTATION PROCESS DIAGRAMS 27
attachCallerPointcuts() iterates
the callerPointcuts hashmap and attachIntroductionPointcuts(advisor,classname)
checks that the classname Replaces instance creation of referenced
matches the class regex pattern advised classes with static methodcalls. For
that this instance holds and adds add the advisor to the hashmap of advisors each constructorcall a methodcall with the
the advisor to the pointcut found. following signature is inserted:
See subdiagram 5
applyCallerPointcuts(clazz,advisor)
write(classname)
A ClassInstanceAdvisor field is
added to the CtClass instance. getter = new
Method : instrumentMethods(clazz,methodFilter)
Instrumentor CTClass:clazz
{static method
OR Will add the following method to the CTClass
non-static method} Instance:
invokeMethod = createInvokeMethod(clazz) public java.lang.Object
invoke(java.lang.Object[] args, long i) {
return
((org.jboss.aop.ClassAdvisor)this._getAdvisor(
)).invokeMethod(this, i, args);
Renaming the orignal that should }
still exist for unadvised usage. method.setName()
invokeMethod = createDelegatingMethod()
CTNewMethod
Here a delegation method is Bytecode
constructed, wrapping the newly wrapped()
constructed invokeMethod or
newMethod
invokeStatic.
new (newMethod ...)
The Bytecode object is the byte-
representation of our class and addAload()
here it is built step by step. This is
not shown in detail here. addGetField()
addInvokeVirtual()
addReturn()
addMethod(delegatingMethod)
All fields in the CtClass instance is * if( isAdvisable(ctfield[index]) ) Will add the following method to
iterated we create an index that is the CtClass instance:
initiated to the offSet that was offSet++ Protected static Object trapRead(
found earlier. Object[] args, int name ){
return ClassAdvisor.trapRead(
First set an int that represents the args[0], name,
CtMethod trapRead = createTrapRead(clazz)
modifier of the curent field. Make aop$classAdvisor
the int contain a value that reflects $Withoutadvisement);
static as well. }
Add the trapConstructor method return classname + "_new_$WithoutAdvisement" Replace new <MyClass>()
that wraps calls to the with calls to
replaceNew(clazz, clazz, s) <MyClass>.<MyClass>_new
trapConstructor method in the
classAdvisor for all constructors. _$WithoutAdevisement(
<params> )
Get a list of all constructors in
clazz object.
CtMethod trapConstructor = createTrapConstructor(clazz)
Creates the following method
Create static methods for each and adds it to clazz.
constructor to use instead of using CtNewMethod.make(methodString,clazz)
new <MyClass> and add these to protected static Object
the CtClass instance. trapConstructor(Object[]
List constructors = getConstructors(clazz) args, int i){
return ClassAdvisor
.trapConstructor(args
, (ClassAdvisor)
aop$classAdvisor
$WithoutAdvsiement, i);
* while list has more - constructor = next }
A String array of interfaces private Object mixinInvoke(Object obj[], long l) throws Throwable{
associated with current return ((ClassAdvisor)_getAdvisor()).invokeMethod(_getInstanceAdvisor(),
introductionpointcut is retrieved. <mixinFullClassName>, l, obj); } is added to the CtClass instance
String[] interfaces = mixin.getInterfaces()
Iterate the list of interfaces. For
each:
* for (int i = 0; i < interfaces.length; i++)
---
Add the interface to the CtClass
instance (adds implements addInterface( interface[i], CtClass )
<interface> to the class)
We add the methods that the interface
Make shure that the each method * addMixinMethod(-,-,-,-) requires as wrappers to the mixinInvoke
that the interface requires us to
method.
implement does not allready exist
in the class or any superclasses
(throws exception if so!).
Method: applyCallerPointcuts(clazz,advisor)
applyCallerPointcuts(clazz, advisor)
All caller-pointcuts that match the
class that is beeing instrumented ArrayList pointcuts = new ArrayList();
will be retrieved from the table of
pointcuts in the AspectManager.
* for all caller-pointcuts in the AspectManager singleton
For each of callerpointcuts calling
method and called method
hashvalues are created. The caller- matches( current caller-pointcut )
pointcut is added to the
ClassAdvisor. The ClassAdvisor will if match - pointcuts.add(pcut)
create a table structure consisting
of a table of calling methods that
contains tables of called classes
that contains tables of called
methods that contains Interceptor * for each pcut in pointcuts
arrays.
- Create hashvalues for the calling method (callingHash) and the
called method (calledHash).
All method calls are replaced and
- Get a String with the classname of the class containg the called
delegated through the
method.
ClassAdvisor.
addCallerPointcut(callingHash, classname, calledHash, pcut)
If a class has any caller-pointcuts applied to it, all method calls will
be replaced with a call to a method in the ClassAdvisor as below:
(ClassAdvisor)aop$classAdvisor$WithoutAdvisement
.invokeCaller( <callingHash>
, <classname>, <calledHash>
, <reference-to-called-class-instance>
, <Object-array-of-arguments>)
APPENDIX I. INSTRUMENTATION PROCESS DIAGRAMS 34
* interface
Advisor
Translator
+translate()
+unregisterClassLoader()
CodeConverter
Instrumentor
Singleton 1 1
*
1
*
1 Javassist.ClassPool
interface * 1 AspectManager
InterceptorFactory * 1
1 1
+create() : Interceptor
1 AOPClassPool
Advisable
SingletonInterceptorFactory GenericInterceptorFactory
InterceptorPointcut
interface
Interceptor
+getName() : string
+invoke() : object MethodPointcut
Appendix J
35
APPENDIX J. DIAGRAMS OF INSTRUMENTED CLASS USE
Instance Creation
product : ProductImpl advisor : ClassAdvisor constructorInterceptors : ArrayList interceptor : ConstructorTailInterceptor
get( int )
returns Interceptor[]
Creates a java.lang.Constructor
object and calls newInstance( args[] ) on it.
(The args[] is empty) and thereby running
invokeNext() ProductImpl's real constructor.
invoke( invocation )
Constructor.newInstance()
36
APPENDIX J. DIAGRAMS OF INSTRUMENTED CLASS USE
Writing to a field
A static initializer is run when the
class is loaded. product : ProductImpl advisor : ClassAdvisor fieldInterceptors : ArrayList interceptor : FieldTailInterceptor
The Class for ProductImpl is saved in a variable.
The ClassAdvisor for ProductImpl is saved in a variable.
(It is taken from the AspectManager)
Constructor.newInstance()
returns an Interceptor[]
{OR}
getInterceptors( aspects )
returns an Interceptor[]
public ProductImpl() {
super(); All Interceptors, except the
id = ProductIdUtil.getNextId(); Set different values on the invocation instance last, in the Interceptor array call
} invokeNext() on the Invocation
object they got in as parameter.
invokeNext() This result in the invocation of
the next interceptor's invoke
invoke( invocation ) method being called.
returns null
Returns null
returns null
returns null
returns a ProductImpl instance
37
APPENDIX J. DIAGRAMS OF INSTRUMENTED CLASS USE 38
getID()
* * *
*
1 ClassInstanceAdvisor
SimpleClassMetaData
Advisor *
ProductImpl
* *
1 1
1
* * InterceptorPointcut
ClassAdvisor ProxyAdvisor
39
Part IV
Simplified Inventory
Management Example
41
Appendix K
The classes below are used as an example Inventory Management system throughout
part III. Below are both the original classes and their instrumented counterparts as
well as the example AOP deployment descriptor.
42
APPENDIX K. CLASSES USED IN PART ?? 43
15 static {
16 aop$class$WithoutAdvisement = Class. forName (
17 " jboss . thesis . inventory . model . ProductImpl ");
18 aop$classAdvisor$WithoutAdvisement = AspectManager . instance (). getAdvisor (
19 aop$class$WithoutAdvisement );
20 }
21
22 private long id ;
23 public String name ;
24 protected transient ClassInstanceAdvisor _instanceAdvisor ;
25 private transient ProductMixin
26 _jboss$thesis$inventory$service$ProductMixin$aop$mixin;
27
28 public ProductImpl () {
29 _instanceAdvisor = new ClassInstanceAdvisor ( this );
30 _jboss$thesis$inventory$service$ProductMixin$aop$mixin = new ProductMixin (
31 this , 20 , 0);
32 }
33
48 }
49
76 public long
77 jboss$thesis$inventory$model$ProductImpl$getId$WithoutAdvisement() {
78 return id_r_$WithoutAdvisement ( this );
79 }
80
99 }
100
6 public ClassUsingProduct () {
7 product = new ProductImpl (); // call constructor
8 product . name = " TestProduct "; // access field directly
9 }
10
7 static {
8 aop$class$WithoutAdvisement = Class. forName (
9 " jboss . thesis . inventory . model . ClassUsingProduct ");
10 aop$classAdvisor$WithoutAdvisement = AspectManager . instance (). getAdvisor (
11 aop$class$WithoutAdvisement );
12 }
13
14 ProductImpl product ;
15
16 public ClassUsingProduct () {
17 // product = new ProductImpl ();
18 product = ProductImpl . ProductImpl_new_$WithoutAdvisement();
19
20 // access field " directly ": product . name = " TestProduct ";
21 ProductImpl . name_w_$WithoutAdvisement ( product , " TestProduct ");
22 }
23
34 return s;
35 }
36
4 < interceptor name =" Logger " singleton =" true "
5 class =" jboss . thesis . inventory . service . logging . LoggingInterceptor ">
6 </ interceptor >
7
8 <method - pointcut class =" jboss . thesis . inventory . model . ProductImpl "
9 methodName =" getID ">
10 < interceptors >
11 < interceptor - ref name =" Logger "/ >
12 </ interceptors >
13 </ method - pointcut >
14
15 < introduction - pointcut class =" jboss . thesis . inventory . model . ProductImpl ">
16 < mixin >
17 < interfaces > jboss . thesis . inventory . service . MinimumStock </ interfaces >
18 <class > jboss . thesis . inventory . service . ProductMixin </ class >
19 < construction >
20 new jboss . thesis . inventory . service . ProductMixin ( this , 20 , 0 )
21 </ construction >
22 </ mixin >
23 </ introduction - pointcut >
24
25 <caller - pointcut
26 class =" jboss . thesis . inventory . model . ClassUsingProduct "
27 calledClass =" jboss . thesis . inventory . model . ProductImpl "
28 calledMethodName =" getID "
29 withinMethodName =" getProductID ">
30 < interceptors >
31 < interceptor - ref name =" Logger "/ >
32 </ interceptors >
33 </ caller - pointcut >
34 </aop >
Part V
Source Code
49
Appendix L
Deployment Descriptors
19 < constructor - pointcut class =" jboss . thesis . inventory . model . Order ">
20 < interceptors >
21 < interceptor - ref name =" ConstructorLogger "/ >
22 </ interceptors >
23 </ constructor - pointcut >
24
25 < constructor - pointcut class =" jboss . thesis . inventory . model . Reservation ">
26 < interceptors >
27 < interceptor - ref name =" ConstructorLogger "/ >
28 </ interceptors >
50
APPENDIX L. DEPLOYMENT DESCRIPTORS 51
31 < interceptor name =" MinimumStockInterceptor " singleton =" true "
32 class =" jboss . thesis . inventory . service . MinimumStockInterceptor ">
33 </ interceptor >
34
43 <method - pointcut class =" jboss . thesis . inventory . model . Reservation "
44 methodName =" setQuantity ">
45 < interceptors >
46 < interceptor - ref name =" MinimumStockInterceptor "/ >
47 < interceptor - ref name =" IncrementReservationInterceptor"/ >
48 </ interceptors >
49 </ method - pointcut >
50
51 < introduction - pointcut class =" jboss . thesis . inventory . model . ProductImpl ">
52 < mixin >
53 < interfaces >
54 jboss . thesis . inventory . service . MinimumStock ,
55 jboss . thesis . inventory . service . ReservationCounter
56 </ interfaces >
57 <class > jboss . thesis . inventory . service . ProductMixin </ class >
58 < construction >
59 new jboss . thesis . inventory . service . ProductMixin ( this , 20 , 0 )
60 </ construction >
61 </ mixin >
62 </ introduction - pointcut >
63
64 < introduction - pointcut class =" jboss . thesis . inventory . model . ProductComposite ">
65 < mixin >
66 < interfaces >
67 jboss . thesis . inventory . service . MinimumStock ,
68 jboss . thesis . inventory . service . ReservationCounter
69 </ interfaces >
70 <class > jboss . thesis . inventory . service . ProductCompositeMixin </ class >
71 < construction >
72 new jboss . thesis . inventory . service . ProductCompositeMixin ( this )
73 </ construction >
74 </ mixin >
75 </ introduction - pointcut >
76
77 <!--
78 * this interceptor and pointcut intercept the creation of new Product
79 * objects and looks up a property file - minimumstock . properties -
APPENDIX L. DEPLOYMENT DESCRIPTORS 52
88 <method - pointcut class =" jboss . thesis . inventory . model . ProductImpl "
89 methodName =" setType ">
90 < interceptors >
91 < interceptor - ref name =" ProductConstructionInterceptor"/ >
92 </ interceptors >
93 </ method - pointcut >
94
95 <method - pointcut class =" jboss . thesis . inventory . model . ProductImpl "
96 methodName =" decreaseStockBy ">
97 < interceptors >
98 < interceptor - ref name =" DecrementReservationInterceptor"/ >
99 </ interceptors >
100 </ method - pointcut >
101
102 <method - pointcut class =" jboss . thesis . inventory . model . ProductComposite "
103 methodName =" decreaseStockBy ">
104 < interceptors >
105 < interceptor - ref name =" DecrementReservationInterceptor"/ >
106 </ interceptors >
107 </ method - pointcut >
108 </aop >
APPENDIX L. DEPLOYMENT DESCRIPTORS 53
Source of inventory-management-service.xml
1 <? xml version ="1.0" encoding =" UTF -8"? >
2 <! DOCTYPE server >
3 < server >
4 <depends > jboss : service = DefaultPartition </ depends >
5
6 < mbean code =" jboss . thesis . inventory . model . jmx . InventoryService "
7 name =" jboss . thesis . inventory : name = InventoryService "/ >
8
9 < mbean code =" jboss . thesis . inventory . model . jmx . TestService "
10 name =" jboss . thesis . inventory : name = TestService "/ >
11
12 < mbean code =" jboss . thesis . inventory . model . jmx . RemoteService "
13 name =" jboss . thesis . inventory : name = RemoteService "/ >
14
15 < mbean code =" jboss . thesis . inventory . model . jmx . DynamicAop "
16 name =" jboss . thesis . inventory : name = DynamicAop "/ >
17
18 < mbean code =" jboss . thesis . inventory . model . jmx . AOPService "
19 name =" jboss . thesis . inventory : name = AOPService "/ >
20
21 < mbean code =" org . jboss . remoting . transport . Connector "
22 xmbean - dd =" org / jboss / remoting / transport / Connector . xml "
23 name =" jboss . remoting : type = Connector , transport = socket5150 ">
24 < attribute name =" InvokerLocator "> socket :// localhost :5150 </ attribute >
25 < attribute name =" Configuration ">
26 < handlers >
27 < handler subsystem =" AOP ">
28 org . jboss . aop . remoting . AOPRemotingInvocationHandler
29 </ handler >
30 </ handlers >
31 </ attribute >
32 </ mbean >
33 </ server >
Appendix M
Inventory Managment
AOP-application
M.1 Customer.java
Source of jboss.thesis.inventory.model.Customer
1 package jboss . thesis . inventory . model ;
2
6 /**
7 * @author Christian Dalager , Simon Jorsal , Eske Sort
8 */
9 public class Customer implements Remote {
10 private long id = 0;
11 private String name ;
12 private String address ;
13 private String email ;
14
15 public Customer () {
16 this ("" , "" , "");
17 }
18
54
APPENDIX M. INVENTORY MANAGMENT AOP-APPLICATION 55
36 return id ;
37 }
38
M.2 IdUtil.java
Source of jboss.thesis.inventory.model.IdUtil
1 package jboss . thesis . inventory . model ;
2
6 /**
7 * @author Christian Dalager , Simon Jorsal , Eske Sort
8 */
9 public class IdUtil {
10 private static Logger log = Logger . getLogger ( IdUtil . class );
11 public static final int PRODUCT = 0;
12 public static final int ORDER = 1;
13 public static final int RESERVATION = 2;
14 public static final int TYPE = 3;
15 public static final int CUSTOMER = 4;
16 private static long itemCounter = 1;
17 private static long orderCounter = 1;
18 private static long reservationCounter = 1;
19 private static long typeCounter = 1;
20 private static long customerCounter = 1;
21
22 private IdUtil () {}
23
27 if ( type == PRODUCT ) {
28 if ( log . isDebugEnabled ()) {
29 log . debug (" new PRODUCT id =" + itemCounter );
30 }
31
66 return returnValue ;
67 }
68
72 if ( type == TYPE ) {
73 returnValue = typeCounter ;
74 }
75 else if ( type == PRODUCT ) {
76 returnValue = itemCounter ;
77 }
78 else if ( type == ORDER ) {
79 returnValue = orderCounter ;
80 }
81 else if ( type == RESERVATION ) {
82 returnValue = reservationCounter ;
83 }
84 else if ( type == CUSTOMER ) {
85 returnValue = customerCounter ;
86 }
87 else {
88 throw new IllegalArgumentException (" Type =" + type + " is not valid ");
89 }
90
91 return returnValue ;
92 }
93 }
APPENDIX M. INVENTORY MANAGMENT AOP-APPLICATION 58
M.3 Order.java
Source of jboss.thesis.inventory.model.Order
1 package jboss . thesis . inventory . model ;
2
12
13 /**
14 * A order holds information about a purchase . It contains information about
15 * products selected as well as name and address of the customer .
16 *
17 * @author Christian Dalager , Simon Jorsal , Eske Sort
18 */
19 public class Order implements Remote , Serializable {
20 private long id ;
21 private List reservations ;
22 private boolean invoiceCreated ;
23 private Date date ;
24 private Customer customer ;
25
26 public Order () {
27 reservations = new ArrayList ();
28 date = new Date ();
29 }
30
34 return id ;
35 }
36
41 /**
42 * Adds a new product ( Reservation ) to the order .
43 *
44 * @param reservation the Reservation to add .
45 */
46 public void addReservation ( Reservation reservation ) {
47 reservations . add ( reservation );
APPENDIX M. INVENTORY MANAGMENT AOP-APPLICATION 59
48 }
49
65 try {
66 reservation = ( Reservation ) reservations . get ( index );
67 }
68 catch ( IndexOutOfBoundsException ignored ) {
69 // if there are no reservations just return null .
70 }
71
72 return reservation ;
73 }
74
86 return null ;
87 }
88
99 return false ;
100 }
101
118 /**
119 * Acumulates the full price of all products in the order .
120 *
121 * @return the acumulated price of the Order .
122 */
123 public double getFullPrice () {
124 double price = 0;
125 Iterator i = reservations . iterator ();
126
158 if (! classesAreCompatible ) {
159 // does not work because of AOP remoting
160 // if ( obj . getClass () != this . getClass () ){
161 return false ;
162 }
163
M.4 OrderList.java
Source of jboss.thesis.inventory.model.OrderList
1 package jboss . thesis . inventory . model ;
2
10
11 /**
12 * @author Christian Dalager , Simon Jorsal , Eske Sort
13 */
14 public class OrderList implements Remote {
15 private static OrderList instance ;
16 private ArrayList orders ;
17
18 public OrderList () {
19 orders = new ArrayList ();
20 }
21
27 return instance ;
28 }
29
37 try {
38 order = ( Order ) orders . get ( index );
39 }
40 catch ( IndexOutOfBoundsException ignored ) {
41 // if index is invalid , just return null
42 }
43
44 return order ;
45 }
46
53 if ( temp . getId () == id ) {
54 return temp ;
55 }
56 }
57
M.5 Product.java
Source of jboss.thesis.inventory.model.Product
1 package jboss . thesis . inventory . model ;
2
6 /**
7 * An Product is a representation of a concrete product ( such as an IBM
8 * Deskstar 75 GXP HDD ). < br >
9 * The name should be the name of the product as stated by the manufacturer .
10 * <br >
11 * The description contains all relevant information about the product , that
12 * is not stated in its name , manufacturer information , price or Type .<br >
13 * The manufacturer is the company that manufactors this product .<br >
14 * The price is the price of the product . < br >
15 * The Type is the group into which this product belongs - for example the
16 * IBM Deskstar 75 GXP falls into the category / group HDD .
17 *
18 * @author Christian Dalager , Simon Jorsal , Eske Sort
19 */
20 public interface Product extends Serializable {
21 public long getId ();
22
39 /**
40 * Gets the name of this product . The name can be the name of a single
41 * Product or an ProductComposite .
42 *
43 * @return the name of the Product or ProductComposite .
44 */
45 public String getName ();
46
47 /**
APPENDIX M. INVENTORY MANAGMENT AOP-APPLICATION 65
48 * Gets the type of this product . The Type can both describe an Product or a
49 * ProductComposite .
50 *
51 * @return the Type of this Product or ProductComposite .
52 */
53 public Type getType ();
54
55 /**
56 * Gets the description of this product . This describes the Product or the
57 * ProductComposite .
58 *
59 * @return the decription of this Product or ProductComposite .
60 */
61 public String getDescription ();
62
63 /**
64 * Gets the manufacturer of this Product . This should probably be in the
65 * form of some Company object , but for the sake of simplicity , it is just
66 * a String representation here .
67 *
68 * @return a String representing the manufacturer of this Product .
69 */
70 public String getManufacturer ();
71
72 /**
73 * Gets the price of this Product . If the Product is an ProductComposite the
74 * price is calculated form all the Products contained in the
75 * ProductComposite . The price should probably be contained in some Price
76 * object , where VAT etc . can be part of it . For simplicity s sake it is
77 * just a double here .
78 *
79 * @return a double with the price of this Product .
80 */
81 public double getPrice ();
82
83 /**
84 * Sets the ID of this Product . It does so by calling the IdUtil . getNextId (
85 * IdUtil . ITEM ) method .
86 *
87 * @return the id this Product acquired .
88 */
89 public long setId ();
90 }
APPENDIX M. INVENTORY MANAGMENT AOP-APPLICATION 66
M.6 ProductImpl.java
Source of jboss.thesis.inventory.model.ProductImpl
1 package jboss . thesis . inventory . model ;
2
4 /**
5 * Represents a Product .
6 *
7 * @author Christian Dalager , Simon Jorsal , Eske Sort
8 */
9 public class ProductImpl implements jboss . thesis . inventory . model . Product ,
10 java . rmi . Remote {
11 private long id ;
12 private String name ;
13 private Type type ;
14 private String description ;
15 private String manufacturer ;
16 private double price ;
17 private int stock ;
18
19 public ProductImpl () {
20 super ();
21 }
22
31 return id ;
32 }
33
48 }
49
99 /*
100 With AOP remoting :
101 ( this . equals ( productImpl ))
102 this . class = jboss . thesis . inventory . model . ProductImpl
103 obj . class = org . jboss . aop . proxy$jboss . thesis . inventory . model . ProductImpl
104 Where obj extends this
105 */
106
112 if (! classesAreCompatible ) {
113 // does not work because of AOP remoting
114 // if ( obj . getClass () != this . getClass () ){
115 return false ;
116 }
117
M.7 ProductComposite.java
Source of jboss.thesis.inventory.model.ProductComposite
1 package jboss . thesis . inventory . model ;
2
7 /**
8 * @author Christian Dalager , Simon Jorsal , Eske Sort
9 */
10 public class ProductComposite implements Product , java . io . Serializable ,
11 java . rmi . Remote {
12 private long id ;
13 private String name ;
14 private Type type ;
15 private String description ;
16 private String manufacturer ;
17 private double price ;
18 private ArrayList products = new ArrayList ();
19
20 public ProductComposite () {
21 super ();
22 }
23
32 return id ;
33 }
34
48 }
49
99 if ( minStock != -1) {
100 minStock = Math . min ((( Product ) i. next ()). getStock () , minStock );
101 }
102 else {
103 minStock = (( Product ) i. next ()). getStock ();
104 }
105 }
106
134 if (! classesAreCompatible ) {
135 return false ;
136 }
137
M.8 Reservation.java
Source of jboss.thesis.inventory.model.Reservation
1 package jboss . thesis . inventory . model ;
2
6 /**
7 * @author Christian Dalager , Simon Jorsal , Eske Sort
8 */
9 public class Reservation implements Remote {
10 private long id ;
11 private int quantity ;
12 private Product product ;
13
14 public Reservation () {}
15
23 return id ;
24 }
25
34 /**
35 * Sets the Product reserved . The Product designates which product is
36 * reserved . Use the { @link setQuantity } method to set how many Products
37 * are actally reserved .
38 *
39 * @param product the product to set .
40 */
41 public void setProduct ( Product product ) {
42 this . product = product ;
43 }
44
48
49 /**
50 * Sets how many Products are reserved via this Reservation . The actual type
51 * of Product reserved is set via the method { @link setProduct }.
52 *
53 * @param quantity the quantity of Products to reserve
54 */
55 public void setQuantity ( int quantity ) {
56 this . quantity = quantity ;
57 }
58
65 if (! classesAreCompatible ) {
66 // Does not work because of AOP remoting :
67 // if ( obj . getClass () != this . getClass () ){
68 return false ;
69 }
70
75 return false ;
76 }
77 }
APPENDIX M. INVENTORY MANAGMENT AOP-APPLICATION 74
M.9 Type.java
Source of jboss.thesis.inventory.model.Type
1 /*
2 * Created on 02 -10 -2003
3 */
4 package jboss . thesis . inventory . model ;
5
7 /**
8 * A Type represents a group of units . It could be for example CPUs , HDDs or
9 * similiar . The name of the Type should categorise the units such
10 * as name = & quot ; CPU & quot ;. < br >
11 * The description should describe common characteristica of the group
12 * designated by the name .
13 *
14 * @author Christian Dalager , Simon Jorsal , Eske Sort
15 */
16 public class Type implements java . rmi . Remote {
17 private long id ;
18 private String name ;
19 private String description ;
20
21 public Type () {}
22
30 return id ;
31 }
32
33 /**
34 * Gets the description that characterizes this Type .
35 *
36 * @return a String with the description .
37 */
38 public String getDescription () {
39 return description ;
40 }
41
42 /**
43 * Gets the name of this Type . The name should characterize a group of units
44 * ie . CPU or HDD .
45 *
46 * @return
47 */
APPENDIX M. INVENTORY MANAGMENT AOP-APPLICATION 75
52 /**
53 * Sets the descripton of this Type .
54 *
55 * @param description the description that describes the group of units
56 * designated by the name field .
57 */
58 public void setDescription ( String description ) {
59 this . description = description ;
60 }
61
62 /**
63 * Sets the name of this Type . The name should characterize a group of units
64 * - such as CPU or HDD .
65 *
66 * @param name the name that designates this Type ( or group of units ).
67 */
68 public void setName ( String name ) {
69 this . name = name ;
70 }
71
Inventory Management
Application Controller
N.1 CreationException.java
Source of jboss.thesis.inventory.controller.CreationException
1
4 /**
5 * @author Christian Dalager , Simon Jorsal , Eske Sort
6 */
7 public class CreationException extends Exception {
8 public CreationException () {
9 super ();
10 }
11
76
APPENDIX N. INVENTORY MANAGEMENT APPLICATION CONTROLLER 77
N.2 InventoryController.java
Source of jboss.thesis.inventory.controller.InventoryController
1 package jboss . thesis . inventory . controller ;
2
20
21 /**
22 * @author Simon Jorsal , Eske Sort , Christian Dalager .
23 */
24 public class InventoryController implements Remote {
25 static InventoryController me ;
26 OrderList orders ;
27 List products = new ArrayList ();
28
29 public InventoryController () {
30 orders = OrderList . instance ();
31 }
32
38 return me ;
39 }
40
41 /**
42 * This method should only be called by server - side components ! Otherwise
43 * this will throw strange NullPointerExceptions and other
44 * AOP - Remoting - hard -to -see - through errors .
45 */
46 public List getProducts () {
47 return products ;
APPENDIX N. INVENTORY MANAGEMENT APPLICATION CONTROLLER 78
48 }
49
50 /**
51 * This method should only be called by server - side components ! Otherwise
52 * this will throw strange NullPointerExceptions and other
53 * AOP - Remoting - hard -to -see - through errors .
54 */
55 public OrderList getOrders () {
56 return orders ;
57 }
58
62 try {
63 product = ( Product ) products . get ( index );
64 }
65 catch ( IndexOutOfBoundsException e ) {
66 // just return null
67 }
68
69 return product ;
70 }
71
83 return null ;
84 }
85
89 try {
90 order = ( Order ) orders . get ( index );
91 }
92 catch ( IndexOutOfBoundsException e ) {
93 // just return null
94 }
95
96 return order ;
97 }
98
APPENDIX N. INVENTORY MANAGEMENT APPLICATION CONTROLLER 79
149 try {
APPENDIX N. INVENTORY MANAGEMENT APPLICATION CONTROLLER 80
160 try {
161 if ( registerInJNDI ) {
162 // Bind the proxy in JNDI :
163 new InitialContext (). rebind ( uniqueId , proxy );
164 }
165 }
166 catch ( NamingException e ) {
167 e. printStackTrace ();
168 throw new CreationException (e );
169 }
170
N.3 InventoryFactory.java
Source of jboss.thesis.inventory.controller.InventoryFactory
1 package jboss . thesis . inventory . controller ;
2
21
22 /**
23 * @author Christian Dalager , Simon Jorsal , Eske Sort
24 */
25 public class InventoryFactory implements Remote {
26 private static Logger log = Logger . getLogger ( InventoryFactory . class );
27 private static InventoryFactory instance ;
28
29 public InventoryFactory () {}
30
36 return instance ;
37 }
38
50 return proxy ;
51 }
52
68 return proxy ;
69 }
70
86 return proxy ;
87 }
88
138 try {
139 // Create the proxy for the Product object :
140 proxy = Remoting . createRemoteProxy (
141 uniqueId , original . getClass () , RemoteUtil . CONNECT_URL );
142 }
143 catch ( Exception e ) {
144 throw new CreationException (e );
145 }
146
147 try {
148 if ( registerInJNDI ) {
149 // Bind the proxy in JNDI :
APPENDIX N. INVENTORY MANAGEMENT APPLICATION CONTROLLER 84
N.4 NoSuchOrderException.java
Source of jboss.thesis.inventory.controller.NoSuchOrderException
1 package jboss . thesis . inventory . controller ;
2
3 /**
4 * @author Christian Dalager , Simon Jorsal , Eske Sort
5 */
6 public class NoSuchOrderException extends Exception {
7 public NoSuchOrderException () {
8 super ();
9 }
10
N.5 RemoteUtil.java
Source of jboss.thesis.inventory.controller.RemoteUtil
1 package jboss . thesis . inventory . controller ;
2
13
14 /**
15 * @author Christian Dalager , Simon Jorsal , Eske Sort
16 */
17 public class RemoteUtil {
18 public static final String CONNECT_URL = " socket :// localhost :5150";
19
39 try {
40 // value = getInitialContext (). lookup ( proxyId );
41 value = new InitialContext (). lookup ( proxyId );
42 }
43 catch ( Exception e1 ) {
44 System . out . println (" Exception in getRemoteProxy ");
45 log . debug ("" + e1 . getCause ());
46 e1 . printStackTrace ();
47 // throw e1 ;
APPENDIX N. INVENTORY MANAGEMENT APPLICATION CONTROLLER 87
48 }
49
50 return value ;
51 }
52
64 try {
65 ctx = new InitialContext ( props );
66 }
67 catch ( Exception e1 ) {
68 log . debug (" Got a NamingException :" + e1 . getCause ());
69 e1 . printStackTrace ();
70 }
71
72 return ctx ;
73 }
74 }
Appendix O
Inventory Management
AOP-services
O.1 DecrementReservationInterceptor.java
Source of jboss.thesis.inventory.service.DecrementReservationInterceptor
1 package jboss . thesis . inventory . service ;
2
11
12 /**
13 * @author Christian Dalager , Simon Jorsal , Eske Sort
14 *
15 */
16 public class DecrementReservationInterceptor implements Interceptor {
17 private InventoryFactory factory = InventoryFactory . instance ();
18
19 public DecrementReservationInterceptor() {
20 super ();
21 }
22
88
APPENDIX O. INVENTORY MANAGEMENT AOP-SERVICES 89
O.2 IncrementReservationInterceptor.java
Source of jboss.thesis.inventory.service.IncrementReservationInterceptor
1 package jboss . thesis . inventory . service ;
2
14
15 /**
16 * @author Christian Dalager , Simon Jorsal , Eske Sort
17 */
18 public class IncrementReservationInterceptor implements Interceptor {
19 private Logger log = Logger . getLogger ( IncrementReservationInterceptor. class );
20 private InventoryFactory factory = InventoryFactory . instance ();
21
48 "( in all Reservations ) made for " + realProduct . getName () + ": " +
49 p. getNumberOfReservations ());
50 log . debug (
51 " The new total amount of reservations for " + realProduct . getName () +
52 ": " + total );
53 }
54
O.3 MinimumStock.java
Source of jboss.thesis.inventory.service.MinimumStock
1 package jboss . thesis . inventory . service ;
2
4 /**
5 * @author Christian Dalager , Simon Jorsal , Eske Sort
6 *
7 */
8 public interface MinimumStock {
9 public int getMinimumStock ();
10
O.4 MinimumStockInterceptor.java
Source of jboss.thesis.inventory.service.MinimumStockInterceptor
1 package jboss . thesis . inventory . service ;
2
14
15 /**
16 * @author Christian Dalager , Simon Jorsal , Eske Sort
17 *
18 */
19 public class MinimumStockInterceptor implements Interceptor {
20 private Logger log = Logger . getLogger ( MinimumStockInterceptor . class );
21 private InventoryFactory factory = InventoryFactory . instance ();
22
23 public MinimumStockInterceptor () {
24 super ();
25 }
26
O.5 ProductCompositeMixin.java
Source of jboss.thesis.inventory.service.ProductCompositeMixin
1 package jboss . thesis . inventory . service ;
2
8 /**
9 * @author Christian Dalager , Simon Jorsal , Eske Sort
10 */
11 public class ProductCompositeMixin implements MinimumStock ,
12 ReservationCounter {
13 private ProductComposite proxyProduct ;
14 private InventoryFactory factory = InventoryFactory . instance ();
15 private int reservations = 0;
16
38 if ( result == -1) {
39 result = minStock ;
40 }
41 }
42
43 return result ;
44 }
45
57 synchronized ( this ) {
58 int minStock = currentMinStockProduct . getMinimumStock ();
59
67 /**
68 * This is a bit odd . Because of how this method is called through
69 * interception of the decreaseStockBy method in a ProductImpl and
70 * ProductComposite we do not call decrementReservation in the children .
71 * decreaseStockBy in ProductComposite calls decreaseStockBy in its
72 * children . This will be intercepted and the call to decrementReservations
73 * wil be made then .
74 *
75 * @see jboss . thesis . inventory . service . ReservationCounter #
76 * decrementReservations ( int )
77 */
78 public void decrementReservations ( int numOfReservations ) {
79 this . reservations -= numOfReservations ;
80
81 /*
82 // This is what would logically need to be done according to the
83 // JavaDoc comment above :
84 ProductComposite realProduct = factory . getLocalProductComposite (
85 proxyProduct . getId () );
86 int numOfProducts = realProduct . numberOfProducts ();
87
O.6 ProductConstructionInterceptor.java
Source of jboss.thesis.inventory.service.ProductConstructionInterceptor
1 package jboss . thesis . inventory . service ;
2
23
24 /**
25 * This class intercept on a method - pointcut : product . setType ( Type t )
26 * Originally this interceptor should have been associated with a
27 * constructor - pointcut , but as the aop - remoting framework does not allow for
28 * constructors with arguments .
29 *
30 * @author Christian Dalager , Simon Jorsal , Eske Sort
31 */
32 public class ProductConstructionInterceptor implements Interceptor {
33 private Logger log = Logger . getLogger ( ProductConstructionInterceptor. class );
34 private InventoryFactory factory = InventoryFactory . instance ();
35
36 /**
37 * The method that s invoked on interception . Calls the next interceptor in
38 * the chain and eventually it will return the Object that it has received
39 * from that interceptor .
40 *
41 * @return the response from the next interceptor
42 */
43 public Object invoke ( Invocation inv ) throws Throwable {
44 if ( inv . getType () == InvocationType . METHOD ) {
45 MethodInvocation methodInv = ( MethodInvocation ) inv ;
46 Product target = ( Product ) methodInv . targetObject ;
47 Type productType = ( Type ) methodInv . arguments [0];
APPENDIX O. INVENTORY MANAGEMENT AOP-SERVICES 99
66 /**
67 * Parses the property file from the loadConfiguration () method and returns
68 * the minimumStock for the Type t . If there is no value for the key t , a
69 * default value of 0 is returned .
70 *
71 * @param t
72 *
73 * @return default
74 */
75 private int getMinimumStock ( Type t ) {
76 Properties props = loadConfiguration ();
77 int retVal = 0;
78 String preparedKey = t. getName (). replaceAll (" " , ".");
79
84 return retVal ;
85 }
86
87 /**
88 * This method is a trick we apply to avoid using reflection
89 */
90 private ClassInstanceAdvisor getAdvisor ( Object o ) throws
91 NotAdvisedException {
92 Advised a = ( Advised ) o;
93
97 /**
98 * Should intercept on a method - pointcut : product . setType ( Type t );
APPENDIX O. INVENTORY MANAGEMENT AOP-SERVICES 100
99 */
100 public String getName () {
101 return " ProductConstructionInterceptor";
102 }
103
104 /**
105 * Loads a property file with the initial minimumStock for each Type of
106 * Product
107 *
108 * @return Properties from file
109 */
110 private Properties loadConfiguration () {
111 Properties conf = new Properties ();
112 FileInputStream fis = null ;
113
114 try {
115 Properties sysProps = System . getProperties ();
116
117 String jbossServerHome = sysProps . getProperty (" jboss . server . base . dir ");
118
O.7 ProductMixin.java
Source of jboss.thesis.inventory.service.ProductMixin
1 package jboss . thesis . inventory . service ;
2
6 /**
7 * @author Christian Dalager , Simon Jorsal , Eske Sort
8 */
9 public class ProductMixin implements MinimumStock , ReservationCounter {
10 private Product owner ;
11 private int minimumStock ;
12 private int reservations ;
13
14 public ProductMixin () {
15 super ();
16 }
17
48
O.8 ReservationCounter.java
Source of jboss.thesis.inventory.service.ReservationCounter
1 package jboss . thesis . inventory . service ;
2
11
12 /**
13 * @author Christian Dalager , Simon Jorsal , Eske Sort
14 *
15 */
16 public class DecrementReservationInterceptor implements Interceptor {
17 private InventoryFactory factory = InventoryFactory . instance ();
18
19 public DecrementReservationInterceptor() {
20 super ();
21 }
22
O.9 WatchListInterceptor.java
Source of jboss.thesis.inventory.service.WatchListInterceptor
1 package jboss . thesis . inventory . service ;
2
14
15 /**
16 * This Interceptor is meant to be added dynamically to selected instances of
17 * Product objects .
18 *
19 * @author Christian Dalager , Simon Jorsal , Eske Sort
20 */
21 public class WatchListInterceptor implements Interceptor {
22 Logger log = Logger . getLogger ( WatchListInterceptor . class );
23
48
O.10 ModelConstructorLoggingInterceptor.java
Source of jboss.thesis.inventory.service.logging.ModelConstructorLoggingInterceptor
1 /*
2 * Created on 19 -12 -2003
3 *
4 */
5 package jboss . thesis . inventory . service . logging ;
6
17
18 /**
19 * @author Christian Dalager , Simon Jorsal , Eske Sort
20 */
21 public class ModelConstructorLoggingInterceptor implements Interceptor {
22 private static Logger log = Logger . getLogger (
23 ModelConstructorLoggingInterceptor. class );
24
48 }
49
65 /*
66 * To turn on logging , the following should be
67 * inserted into the JBoss log4j . xml file :
68 * < appender name =" INVENTORY " class =" org . apache . log4j . FileAppender ">
69 * < errorHandler class =" org . jboss . logging . util . OnlyOnceErrorHandler "/ >
70 * < param name =" Append " value =" false "/ >
71 * < param name =" File "
72 * value =" ${ jboss . server . home . dir }/ log / inventory - management . log "/ >
73 * < layout class =" org . apache . log4j. PatternLayout ">
74 * < param name =" ConversionPattern "
75 * value ="% d{ ABSOLUTE } % -5p [% c {1}] % m%n "/ >
76 * </ layout >
77 * </ appender >
78 *
79 * < category name =" jboss. thesis . inventory . service .
80 * logging . ConstructorLoggingInterceptor">
81 * < priority value =" INFO "/ >
82 * < appender - ref ref =" INVENTORY "/ >
83 * </ category >
84 */
85 }
Appendix P
P.1 AOPService.java
Source of jboss.thesis.inventory.model.jmx.AOPService
1 package jboss . thesis . inventory . model . jmx ;
2
21
22 /**
23 * @author Christian Dalager , Simon Jorsal , Eske Sort
24 */
25 public class AOPService extends ServiceMBeanSupport implements
26 MBeanRegistration , AOPServiceMBean {
108
APPENDIX P. INVENTORY MANAGEMENT MBEANS 109
31 public AOPService () {
32 super ();
33 controller = InventoryController . instance ();
34 }
35
48 int minStock = 0;
49
50 try {
51 MinimumStock min = dirtyCast (p );
52 System . out . println (" Calling getMinimumStock ");
53 minStock = min . getMinimumStock ();
54 }
55 catch ( ClassCastException cce ) {
56 System . out . println (" Product is a composite , cannot get Minimum Stock ");
57 System . out . println (" getClass (): " + p. getClass ());
58 cce . printStackTrace ();
59 }
60
65 String watchlink = " <a href =\" HtmlAdaptor ? action = invokeOpByName & name =" +
66 " jboss . thesis . inventory %3 Aname %3 DAOPService & methodName =" +
67 " watchProduct & argType = long & arg0 =" +
68 p. getId () + "\" > Add watch </a >< br /><br /><br / >";
69
78
102 try {
103 MinimumStock ms = ( MinimumStock ) product ;
104 ms . setMinimumStock ( minimumStock );
105 }
106 catch ( ClassCastException cce ) {
107 result = " Product has not been made advisable " +
108 " - minimum stock not available ";
109 }
110
129 " to your watchlist .< br /> You will be informed when decreaseStock ()" +
130 " is called < br / >");
131 sb . append ( " < a href =\" HtmlAdaptor ? action = invokeOpByName & name " +
132 " jboss . thesis . inventory %3 Aname %3 DAOPService & methodName =" +
133 " listProducts \" > Back to list of products </ a >");
134
159 return m;
160 }
161
P.2 AOPServiceMBean.java
Source of jboss.thesis.inventory.model.jmx.AOPServiceMBean
1 package jboss . thesis . inventory . model . jmx ;
2
6 /**
7 * @author Christian Dalager , Simon Jorsal , Eske Sort
8 */
9 public interface AOPServiceMBean extends ServiceMBean {
10 public String listProducts ();
11 public String setMinimumQuantity ( long productid , int minimumStock );
12 public String watchProduct ( long productId );
13 public String unWatchProduct ( long productId );
14 }
APPENDIX P. INVENTORY MANAGEMENT MBEANS 113
P.3 InventoryService.java
Source of jboss.thesis.inventory.model.jmx.InventoryService
1 package jboss . thesis . inventory . model . jmx ;
2
33
34 /**
35 * @author Christian Dalager , Simon Jorsal , Eske Sort
36 */
37 public class InventoryService extends ServiceMBeanSupport
38 implements MBeanRegistration , InventoryServiceMBean {
39 static Logger log = Logger . getLogger ( InventoryService . class );
40 MBeanServer m_mbeanServer ;
41
42 // ProductComposite list ;
43 public InventoryService () {
44 super ();
45 }
46
48 createInventoryFactory ();
49 createInventoryController ();
50 createOrderList ();
51 createDummyProducts ();
52 }
53
54 /**
55 * Creates and registers an OrderList with the Dispatcher and binds it in
56 * JNDI . If the OrderList is already bound in JNDI it will be replaced by
57 * the newly created OrderList . ( But note that OrderList is Singleton ).
58 */
59 public void createOrderList () throws Exception {
60 OrderList list = OrderList . instance ();
61 String oid = " orderList ";
62
70 /**
71 * Creates and registers an InventoryFactory with the Dispatcher and binds
72 * it in JNDI . If the InventoryFactory is already bound in JNDI it will be
73 * replaced by the newly created factory . ( But note that InventoryFactory
74 * is Singleton ).
75 */
76 public void createInventoryFactory () throws Exception {
77 InventoryFactory factory = new InventoryFactory ();
78 String oid = " inventoryFactory ";
79
80 InventoryFactory factoryProxy =
81 ( InventoryFactory ) Remoting . createRemoteProxy (
82 oid , factory . getClass () , RemoteUtil . CONNECT_URL );
83
87 /**
88 * Creates and registers an InventoryController with the Dispatcher and
89 * binds it in JNDI . If the InventoryController is already bound in JNDI it
90 * will be replaced by the newly created controller . ( InventoryController
91 * is a Singleton ).
92 */
93 public void createInventoryController () throws Exception {
94 InventoryController controller = InventoryController . instance ();
95 String oid = " inventoryController ";
96
97 InventoryController controllerProxy =
98 ( InventoryController ) Remoting . createRemoteProxy (
APPENDIX P. INVENTORY MANAGEMENT MBEANS 115
127 try {
128 type = factory . createType ();
129 }
130 catch ( CreationException ignored ) {
131 ignored . printStackTrace ();
132 }
133
179 try {
180 list = ( ProductComposite ) factory . createProductComposite ();
181 }
182 catch ( CreationException ignored ) {}
183
194 try {
195 product = factory . createProductImpl ();
196 }
197 catch ( CreationException ignored ) {}
198
206 if (i == 0 || i == 6 || i == 12) {
207 list . add ( product );
208 }
209
219 try {
220 InventoryFactory factory =
221 ( InventoryFactory ) ( new InitialContext ()). lookup (
222 " inventoryFactory ");
223 log . info (" Testing createProductComposite remotely and " +
224 " getting Products not registered in JNDI ");
225 list = ( ProductComposite ) factory . createProductComposite ();
226 list . setName (" productComposite ");
227
303 }
304 }
305
P.4 InventoryServiceMBean.java
Source of jboss.thesis.inventory.model.jmx.InventoryServiceMBean
1 package jboss . thesis . inventory . model . jmx ;
2
6 /**
7 * @author Christian Dalager , Simon Jorsal , Eske Sort
8 */
9 public interface InventoryServiceMBean extends ServiceMBean {
10 public void registerProduct ();
11 public void createProductComposite ();
12 public void writeLoadedClassFiles ();
13 public String printAspectManagerInfo ();
14 }
Appendix Q
Q.1 AddReservationButton.java
Source of jboss.thesis.inventory.client.AddReservationButton
1 package jboss . thesis . inventory . client ;
2
8 /**
9 * @author Christian Dalager , Simon Jorsal , Eske Sort
10 */
11 public class AddReservationButton extends JButton {
12 private Product product ;
13
121
APPENDIX Q. THE GRAPHICAL CLIENT 122
Q.2 ButtonCellRenderer.java
Source of jboss.thesis.inventory.client.ButtonCellRenderer
1 package jboss . thesis . inventory . client ;
2
9 /**
10 * @author Christian Dalager , Simon Jorsal , Eske Sort
11 */
12 public class ButtonCellRenderer extends DefaultTableCellRenderer {
13 public Component getTableCellRendererComponent( JTable table ,
14 Object value , boolean isSelected , boolean hasFocus , int nRow ,
15 int nCol ) {
16 return ( OrderDetailButton ) value ;
17 }
18 }
APPENDIX Q. THE GRAPHICAL CLIENT 123
Q.3 ColumnData.java
Source of jboss.thesis.inventory.client.ColumnData
1 package jboss . thesis . inventory . client ;
2
3 /**
4 * @author Christian Dalager , Simon Jorsal , Eske Sort
5 */
6 public class ColumnData {
7 public String title ;
8 public int width ;
9 public int alignment ;
10
Q.4 InventoryProxyClient.java
Source of jboss.thesis.inventory.client.InventoryProxyClient
1 package jboss . thesis . inventory . client ;
2
27
28 /**
29 * @author Christian Dalager , Simon Jorsal , Eske Sort
30 */
31 public class InventoryProxyClient {
32 private ObjectName serviceName = ObjectNameFactory . create (
33 " jboss . thesis . inventory : name = RemoteService ");
34 private Object [] noparams = { };
35 private String [] nosig = { };
36 private RMIAdaptor server = null ;
37
38 /**
39 * The constructor initializes the connection with the server running on
40 * localhost .
41 */
42 public InventoryProxyClient () {
43 try {
44 server = ( RMIAdaptor ) getInitialContext (). lookup (" jmx / rmi / RMIAdaptor ");
45 }
46 catch ( NamingException e1 ) {
47 System . out . println (" Error happened !");
APPENDIX Q. THE GRAPHICAL CLIENT 125
48 e1 . printStackTrace ();
49 }
50 catch ( AccessControlException e2 ) {
51 e2 . printStackTrace ();
52 }
53
77 /**
78 * @return ArrayList of Products on the server . These Products are <i > not </i >
79 * remote objects .
80 */
81 public ArrayList getRemoteProducts () {
82 ArrayList list = null ;
83
84 try {
85 list = ( ArrayList ) server . invoke (
86 serviceName , " retrieveAllProducts " , noparams , nosig );
87 System . out . println (" list =" + list );
88 }
89 catch ( InstanceNotFoundException e2 ) {
90 e2 . printStackTrace ();
91 }
92 catch ( MBeanException e2 ) {
93 e2 . printStackTrace ();
94 }
95 catch ( ReflectionException e2 ) {
96 e2 . printStackTrace ();
97 }
98 catch ( RemoteException e2 ) {
APPENDIX Q. THE GRAPHICAL CLIENT 126
99 e2 . printStackTrace ();
100 }
101
109 System . out . println (" Number of prodcts = " + al . size ());
110 System . out . println ("\ nProducts on server : ");
111
120 /**
121 * Sets up a default security manager
122 */
123 private void setupSecurityManager () {
124 System . out . println (" SecurityManager =" + System . getSecurityManager ());
125 System . out . println (" Setting security manager ");
126
127 try {
128 if ( System . getSecurityManager () == null ) {
129 System . setSecurityManager ( new RMISecurityManager ());
130 }
131 }
132 catch ( SecurityException se ) {
133 System . out . println (" SecurityManager already set !");
134 }
135
139 /**
140 * @return InitialContext
141 */
142 private InitialContext getInitialContext () {
143 Hashtable props = new Hashtable ();
144 props . put ( Context . INITIAL_CONTEXT_FACTORY ,
145 " org . jnp . interfaces . NamingContextFactory ");
146 props . put ( Context . URL_PKG_PREFIXES , " org . jboss . naming : org . jnp . interfaces ");
147
Q.5 JTableButtonListener.java
Source of jboss.thesis.inventory.client.JTableButtonListener
1 package jboss . thesis . inventory . client ;
2
11 /**
12 * @author Christian Dalager , Simon Jorsal , Eske Sort
13 */
14 class JTableButtonListener implements MouseListener {
15 private JTable table ;
16
Q.6 MainWindow.java
Source of jboss.thesis.inventory.client.MainWindow
1 package jboss . thesis . inventory . client ;
2
42
43 /**
44 * @author Christian Dalager , Simon Jorsal , Eske Sort
45 */
46 public class MainWindow extends JFrame implements ActionListener {
47 private static Logger log = Logger . getLogger ( MainWindow . class );
APPENDIX Q. THE GRAPHICAL CLIENT 131
57 private MainWindow () {
58 super (" Inventory Management Client ");
59
60 try {
61 factory = RemoteUtil . getFactory ();
62 controller = RemoteUtil . getController ();
63 }
64 catch ( NamingException e1 ) {
65 System . out . println (" Exception in MainWindow constructor ");
66 e1 . printStackTrace ();
67 }
68
95 if (k == 5) {
96 renderer = new ButtonCellRenderer ();
97 }
98 else {
APPENDIX Q. THE GRAPHICAL CLIENT 132
114 try {
115 Customer customer = factory . createCustomer ();
116 customer . setAddress (" Enter Address ");
117 customer . setEmail (" Enter Email ");
118 customer . setName (" Enter Name ");
119
150 }
151
181 try {
182 if ( System . getSecurityManager () == null ) {
183 System . setSecurityManager ( new RMISecurityManager ());
184 }
185 }
186 catch ( SecurityException se ) {
187 System . out . println (" Exception in setSecurityManager ");
188 }
189 }
190
Q.7 OrderDetailButton.java
Source of jboss.thesis.inventory.client.OrderDetailButton
1 package jboss . thesis . inventory . client ;
2
8 /**
9 * @author Christian Dalager , Simon Jorsal , Eske Sort
10 */
11 public class OrderDetailButton extends JButton {
12 Order order ;
13
Q.8 OrderFrame.java
Source of jboss.thesis.inventory.client.OrderFrame
1 package jboss . thesis . inventory . client ;
2
38
39 /**
40 * @author Christian Dalager , Simon Jorsal , Eske Sort
41 */
42 public class OrderFrame extends JFrame {
43 private static InventoryController controller ;
44 Order order ;
45 ReservationTableData reservationData ;
46 ProductTableData productData ;
47 JLabel title ;
APPENDIX Q. THE GRAPHICAL CLIENT 136
48 JTable reservationTable ;
49 JTable productTable ;
50 JScrollPane productScrollPane ;
51 JScrollPane reservationScrollPane ;
52 final JTextField nameTxt ;
53 final JTextField addressTxt ;
54 final JTextField emailTxt ;
55 JButton deleteButton ;
56 JButton saveButton ;
57 JButton invoiceButton ;
58
62 try {
63 // factory = RemoteUtil . getFactory ();
64 controller = RemoteUtil . getController ();
65 }
66 catch ( NamingException e1 ) {
67 e1 . printStackTrace ();
68 }
69
87 title = new JLabel (" Edit order # " + order . getId () , SwingConstants . LEFT );
88 title . setFont ( new Font (" Helvetica " , Font . PLAIN , 18));
89 this . getContentPane (). setLayout ( new BorderLayout ());
90
105 if (k == 2) {
106 renderer = new ReservationButtonCellrenderer();
107 }
108 else {
109 renderer = new DefaultTableCellRenderer ();
110 }
111
127 if (k == 1) {
128 JTextField text = new JTextField ();
129 text . setBorder ( null );
130
180 nameTxt = new JTextField ( null , order . getCustomer (). getName () , 15);
181 nameTxt . addFocusListener ( new FocusAdapter () {
182 public void focusLost ( FocusEvent e ) {
183 order . getCustomer (). setName ( nameTxt . getText ());
184 }
185 });
186 addressTxt = new JTextField ( order . getCustomer (). getAddress () , 25);
187 addressTxt . addFocusListener ( new FocusAdapter () {
188 public void focusLost ( FocusEvent e ) {
189 order . getCustomer (). setAddress ( addressTxt . getText ());
190 }
191 });
192
252 }
253
Q.9 OrderTableData.java
Source of jboss.thesis.inventory.client.OrderTableData
1 package jboss . thesis . inventory . client ;
2
23
24 /**
25 * @author Christian Dalager , Simon Jorsal , Eske Sort
26 */
27 public class OrderTableData extends AbstractTableModel {
28 private static Logger log = Logger . getLogger ( OrderTableData . class );
29 static final public ColumnData [] columns = {
30 new ColumnData (" OrderNo " , 50 , JLabel . LEFT ),
31 new ColumnData (" Customer " , 100 , JLabel . LEFT ),
32 new ColumnData (" Date " , 50 , JLabel . LEFT ),
33 new ColumnData (" Price " , 50 , JLabel . LEFT ),
34 new ColumnData (" Paid " , 20 , JLabel . LEFT ),
35 new ColumnData (" " , 30 , JLabel . LEFT )
36 };
37 private InventoryController controller ;
38
39 public OrderTableData () {
40 try {
41 controller = RemoteUtil . getController ();
42 log . debug (" controller =" + controller );
43 }
44 catch ( NamingException e1 ) {
45 log . debug (" NamingException occured : " + e1 . getMessage ());
46 }
47 }
APPENDIX Q. THE GRAPHICAL CLIENT 142
48
52 if ( controller != null ) {
53 rowCount = controller . getNumberOfOrders ();
54 }
55
56 return rowCount ;
57 }
58
78 if ( order == null ) {
79 return " ";
80 }
81
82 switch ( columnIndex ) {
83 case 0 :
84 long id = order . getId ();
85 if ( id < 0) {
86 return " ";
87 }
88 return new Long ( id );
89
90 case 1 :
91 Customer customer = order. getCustomer ();
92 if ( customer == null ) {
93 return " ";
94 }
95 return customer . getName ();
96
97 case 2 :
98 Date date = order . getDate ();
APPENDIX Q. THE GRAPHICAL CLIENT 143
99 if ( date == null ) {
100 return " ";
101 }
102 return DateFormat . getDateInstance (). format ( date );
103
104 case 3 :
105 double price = order . getFullPrice ();
106 if ( price < 0) {
107 return " ";
108 }
109 return new Double ( price );
110
111 case 4 :
112 return ( order . invoiceCreated () ? " yes " : " no ");
113
114 case 5 :
115
Q.10 ProductTableData.java
Source of jboss.thesis.inventory.client.ProductTableData
1 package jboss . thesis . inventory . client ;
2
22
23 /**
24 * @author Christian Dalager , Simon Jorsal , Eske Sort
25 */
26 public class ProductTableData extends AbstractTableModel {
27 static final public ColumnData [] columns = {
28 new ColumnData (" Product " , 200 , JLabel . LEFT ),
29 new ColumnData (" Price " , 30 , JLabel . LEFT ),
30 new ColumnData (" Action " , 90 , JLabel . LEFT )
31 };
32 private InventoryFactory factory ;
33 private InventoryController controller ;
34 private List products ;
35 private Order order ;
36
48
72 switch ( columnIndex ) {
73 case 0 :
74 return product . getName () + " , " + product . getType () + " , " +
75 product . getDescription ();
76
77 case 1 :
78 return new Double ( product . getPrice ());
79
80 case 2 :
81
Q.11 ReservationButtonCellRenderer.java
Source of jboss.thesis.inventory.client.ReservationButtonCellRenderer
1 package jboss . thesis . inventory . client ;
2
9 /**
10 * @author Christian Dalager , Simon Jorsal , Eske Sort
11 */
12 public class ReservationButtonCellrenderer extends DefaultTableCellRenderer {
13 public Component getTableCellRendererComponent( JTable table , Object value ,
14 boolean isSelected , boolean hasFocus , int nRow , int nCol ) {
15 return ( AddReservationButton ) value;
16 }
17 }
APPENDIX Q. THE GRAPHICAL CLIENT 148
Q.12 ReservationTableData.java
Source of jboss.thesis.inventory.client.ReservationTableData
1 package jboss . thesis . inventory . client ;
2
10 /**
11 * @author Christian Dalager , Simon Jorsal , Eske Sort
12 */
13 public class ReservationTableData extends AbstractTableModel {
14 static final public ColumnData [] columns = {
15 new ColumnData (" Product " , 200 , JLabel . LEFT ),
16 new ColumnData (" Quantity " , 30 , JLabel . LEFT ),
17 new ColumnData (" Price " , 70 , JLabel . LEFT )
18 };
19 private Order order ;
20
42 return false ;
43 }
44
48 }
49
52 switch ( columnIndex ) {
53 case 0 :
54 return reservation . getProduct (). getName () + " , " +
55 reservation . getProduct (). getType () + " , " +
56 reservation . getProduct (). getDescription ();
57
58 case 1 :
59 return new Integer ( reservation . getQuantity ());
60
61 case 2 :
62 return new Double ( reservation . getPrice ());
63 }
64
R.1 PerformanceTest.java
Source of jboss.thesis.inventory.model.jmx.PerformanceTest
1 package jboss . thesis . inventory . model . jmx ;
2
14
15 /**
16 * @author Christian Dalager , Simon Jorsal , Eske Sort
17 */
18 public class PerformanceTest implements PerformanceTestMBean ,
19 MBeanRegistration {
20 MBeanServer m_mbeanServer ;
21 Timer t;
22
23 public PerformanceTest () {
24 super ();
25 }
150
APPENDIX R. AOP PERFORMANCE TEST 151
26
77
179
R.2 PerformanceTestMBean.java
Source of jboss.thesis.inventory.model.jmx.PerformanceTestMBean
1 package jboss . thesis . inventory . model . jmx ;
2
4 /**
5 * @author Christian Dalager , Simon Jorsal , Eske Sort
6 */
7 public interface PerformanceTestMBean {
8 public String runPerformanceSuite ( int iterations );
9 public double testConstruction ( int iterations );
10 public double testConstructionWithFieldSet ( int iterations );
11 public double testUnadvisedConstructionWithFieldSet( int iterations );
12 public double testUnadvisedConstruction ( int iterations );
13 public double testMethodStatic ( int iterations );
14 public double testUnadvisedMethodStatic ( int iterations );
15 public double testMethod ( int iterations );
16 public double testUnadvisedMethod ( int iterations );
17 public double testInterceptedMethod ( int iterations );
18 public double testNonPublicMethod ( int iterations );
19 public double testPublicMethod ( int iterations );
20 public double testFallThroughConstructionUnadvised( int iterations );
21 public double testFallThroughConstruction ( int iterations );
22 public double testFieldAccess ( int iterations );
23 public double testUnadvisedFieldAccess ( int iterations );
24 }
APPENDIX R. AOP PERFORMANCE TEST 158
R.3 ConstructorTest.java
Source of jboss.thesis.performancetest.ConstructorTest
1 package jboss . thesis . performancetest ;
2
3 /**
4 * @author Christian Dalager , Simon Jorsal , Eske Sort This Class is used to
5 * test , how fall - through constructors are performing aop vs .
6 * nonadvised
7 */
8 public class ConstructorTest {
9 // these fields are not used in this class , but they are used in
10 // the SimplePerformClassA
11 public static int k = 0;
12 public String str = " myString ";
13 private int i = 0;
14
15 public ConstructorTest () {
16 this ( null );
17 }
18
R.4 ConstructorTestUnadvised.java
Source of jboss.thesis.performancetest.ConstructorTestUnadvised
1 package jboss . thesis . performancetest ;
2
3 /**
4 * @author Christian Dalager , Simon Jorsal , Eske Sort This Class is used to
5 * test , how fall - through constructors are performing aop vs .
6 * nonadvised
7 */
8 public class ConstructorTestUnadvised {
9 // these fields are not used in this class , but they are used in
10 // the SimplePerformClassA
11 public static int k = 0;
12 public String str = " myString ";
13 private int i = 0;
14
15 public ConstructorTestUnadvised () {
16 this ( null );
17 }
18
R.5 PerformanceInterceptor.java
Source of jboss.thesis.performancetest.PerformanceInterceptor
1 package jboss . thesis . performancetest ;
2
7 /**
8 * @author Christian Dalager , Simon Jorsal , Eske Sort
9 */
10 public class PerformanceInterceptor implements Interceptor {
11 public String getName () {
12 return " PerformanceInterceptor ";
13 }
14
R.6 SimplePerformanceClassA.java
Source of jboss.thesis.performancetest.SimplePerformanceClassA
1 package jboss . thesis . performancetest ;
2
3 /**
4 * @author Christian Dalager , Simon Jorsal , Eske Sort
5 */
6 public class SimplePerformanceClassA {
7 public static int k = 0;
8 public String str = " myString ";
9 private int i = 0;
10
11 public SimplePerformanceClassA () {}
12
65 double pm ( double x ) {
66 if (k > 0) {
67 return x * x;
68 }
69 else
70 {
71 return 2 * pm (x );
72 }
73 }
74 }
APPENDIX R. AOP PERFORMANCE TEST 163
R.7 SimplePerformanceClassB.java
Source of jboss.thesis.performancetest.SimplePerformanceClassB
1 package jboss . thesis . performancetest ;
2
3 /**
4 * @author Christian Dalager , Simon Jorsal , Eske Sort
5 */
6 public class SimplePerformanceClassB {
7 int i = 0;
8
R.8 SimpleUnadvisedPerformanceClassA.java
Source of jboss.thesis.performancetest.SimpleUnadvisedPerformanceClassA
1 package jboss . thesis . performancetest ;
2
3 /**
4 * @author Christian Dalager , Simon Jorsal , Eske Sort
5 */
6 public class SimpleUnadvisedPerformanceClassA {
7 public static int k = 0;
8 public String str = " myString ";
9 private int i = 0;
10
11 public SimpleUnadvisedPerformanceClassA() {}
12
R.9 SimpleUnadvisedPerformanceClassB.java
Source of jboss.thesis.performancetest.SimpleUnadvisedPerformanceClassB
1 package jboss . thesis . performancetest ;
2
3 /**
4 * @author Christian Dalager , Simon Jorsal , Eske Sort
5 */
6 public class SimpleUnadvisedPerformanceClassB {
7 int i = 0;
8
R.10 Timer.java
Source of jboss.thesis.util.Timer
1 package jboss . thesis . util ;
2
3 /**
4 * @author Christian Dalager , Simon Jorsal , Eske Sort
5 */
6 public class Timer {
7 private long start ;
8
9 public Timer () {
10 start = System . currentTimeMillis ();
11 }
12
167
Appendix S
Instrumented Decompiled
Classes
The classes below are a selection of instrumented classes from the Inventory Manage-
ment AOP-application. The classes were decompiled with the DJ Java Decompiler.
The classes below are all part of the jboss.thesis.inventory.model and jboss.the-
sis.inventory.controller packages.
S.1 Order.java
Source of jboss.thesis.inventory.model.Order
1 package jboss . thesis . inventory . model ;
2
13
19 static {
168
APPENDIX S. INSTRUMENTED DECOMPILED CLASSES 169
26 private long id ;
27 private List reservations ;
28 private boolean invoiceCreated ;
29 private Date date ;
30 private Customer customer ;
31 protected transient ClassInstanceAdvisor _instanceAdvisor ;
32
33 public Order () {
34 _instanceAdvisor = new ClassInstanceAdvisor ( this );
35 reservations_w_$WithoutAdvisement( this , new ArrayList ());
36 date_w_$WithoutAdvisement ( this , new Date ());
37 }
38
45 public Iterator
46 jboss$thesis$inventory$model$Order$getReservationIterator$WithoutAdvisement() {
47 return reservations_r_$WithoutAdvisement( this ). iterator ();
48 }
49
50 public void
51 jboss$thesis$inventory$model$Order$addReservation$WithoutAdvisement(
52 Reservation reservation ) {
53 reservations_r_$WithoutAdvisement( this ). add ( reservation );
54 }
55
56 public void
57 jboss$thesis$inventory$model$Order$removeReservation$WithoutAdvisement(
58 Reservation reservation ) {
59 reservations_r_$WithoutAdvisement( this ). remove ( reservation );
60 }
61
62 public void
63 jboss$thesis$inventory$model$Order$removeReservation$WithoutAdvisement(
64 int index ) {
65 reservations_r_$WithoutAdvisement( this ). remove ( index );
66 }
67
68 public void
69 jboss$thesis$inventory$model$Order$clearReservations$WithoutAdvisement() {
70 reservations_r_$WithoutAdvisement( this ). clear ();
APPENDIX S. INSTRUMENTED DECOMPILED CLASSES 170
71 }
72
73 public Reservation
74 jboss$thesis$inventory$model$Order$getReservation$WithoutAdvisement(
75 int index ) {
76 Reservation reservation = null ;
77
78 try {
79 reservation = ( Reservation ) reservations_r_$WithoutAdvisement( this ). get (
80 index );
81 }
82 catch ( IndexOutOfBoundsException ignored ) {}
83
84 return reservation ;
85 }
86
87 public Reservation
88 jboss$thesis$inventory$model$Order$getReservationByProduct$WithoutAdvisement(
89 Product product ) {
90 for (
91 Iterator i = reservations_r_$WithoutAdvisement( this ). iterator ();
92 i. hasNext ();) {
93 Reservation current = ( Reservation ) i. next ();
94
122
128 for (
129 Iterator i = reservations_r_$WithoutAdvisement( this ). iterator ();
130 i. hasNext (); product . decreaseStockBy ( current . getQuantity ())) {
131 current = ( Reservation ) i. next ();
132 product = current . getProduct ();
133 }
134
142 for (
143 Iterator i = reservations_r_$WithoutAdvisement( this ). iterator ();
144 i. hasNext ();) {
145 price += (( Reservation ) i. next ()). getPrice ();
146 }
147
173 }
174
179 if (! classesAreCompatible ) {
180 return false ;
181 }
182
224 jboss$thesis$inventory$model$Order$addReservation$WithoutAdvisement(
225 reservation );
226
227 return ;
228 }
229
238 return ;
239 }
240
248 return ;
249 }
250
258 return ;
259 }
260
314 return ;
315 }
316
345 return ;
346 }
347
428 }
429
S.2 ProductComposite.java
Source of jboss.thesis.inventory.model.ProductComposite
1 package jboss . thesis . inventory . model ;
2
16
23 static {
24 aop$class$WithoutAdvisement = Class. forName (
25 " jboss . thesis . inventory . model . ProductComposite ");
26 aop$classAdvisor$WithoutAdvisement = AspectManager . instance (). getAdvisor (
27 aop$class$WithoutAdvisement );
28 }
29
30 private long id ;
31 private String name ;
32 private Type type ;
33 private String description ;
34 private String manufacturer ;
35 private double price ;
36 private ArrayList products ;
37 protected transient ClassInstanceAdvisor _instanceAdvisor ;
38 private transient ProductCompositeMixin
39 _jboss$thesis$inventory$service$ProductCompositeMixin$aop$mixin;
40
41 public ProductComposite () {
42 _instanceAdvisor = new ClassInstanceAdvisor ( this );
43 _jboss$thesis$inventory$service$ProductCompositeMixin$aop$mixin =
44 new ProductCompositeMixin ( this );
45 products_w_$WithoutAdvisement( this , new ArrayList ());
46 }
47
APPENDIX S. INSTRUMENTED DECOMPILED CLASSES 179
56 public long
57 jboss$thesis$inventory$model$ProductComposite$setId$WithoutAdvisement() {
58 id_w_$WithoutAdvisement ( this , IdUtil . getNextId (0));
59
63 public void
64 jboss$thesis$inventory$model$ProductComposite$add$WithoutAdvisement(
65 Product product ) {
66 products_r_$WithoutAdvisement( this ). add ( product );
67 }
68
69 public long
70 jboss$thesis$inventory$model$ProductComposite$getId$WithoutAdvisement() {
71 return id_r_$WithoutAdvisement ( this );
72 }
73
74 public Product
75 jboss$thesis$inventory$model$ProductComposite$get$WithoutAdvisement(
76 int index ) {
77 return ( Product ) products_r_$WithoutAdvisement( this ). get ( index );
78 }
79
80 public int
81 jboss$thesis$inventory$model$ProductComposite$numberOfProducts$WithoutAdvisement() {
82 return products_r_$WithoutAdvisement( this ). size ();
83 }
84
85 public void
86 jboss$thesis$inventory$model$ProductComposite$setName$WithoutAdvisement(
87 String name ) {
88 name_w_$WithoutAdvisement ( this , name );
89 }
90
91 public void
92 jboss$thesis$inventory$model$ProductComposite$setType$WithoutAdvisement(
93 Type type ) {
94 type_w_$WithoutAdvisement ( this , type );
95 }
96
97 public void
98 jboss$thesis$inventory$model$ProductComposite$setDescription$WithoutAdvisement(
APPENDIX S. INSTRUMENTED DECOMPILED CLASSES 180
99 String description ) {
100 description_w_$WithoutAdvisement( this , description );
101 }
102
187 if (! classesAreCompatible ) {
188 return false ;
189 }
190
201 }
202
231 return ;
232 }
233
252 }
253 else {
254 return ( Product ) _added_m$0 (
255 new Object [] { new Integer (i ) } , 0 xbd19d69d08df0e34L );
256 }
257 }
258
274 return ;
275 }
276
285 return ;
286 }
287
296 return ;
297 }
298
307 return ;
308 }
309
317 return ;
318 }
319
400 return ;
401 }
402
405
411 return ;
412 }
413
456
S.3 ProductImpl.java
Source of jboss.thesis.inventory.model.ProductImpl
1 package jboss . thesis . inventory . model ;
2
11
18 static {
19 aop$class$WithoutAdvisement = Class. forName (
20 " jboss . thesis . inventory . model . ProductImpl ");
21 aop$classAdvisor$WithoutAdvisement = AspectManager . instance (). getAdvisor (
22 aop$class$WithoutAdvisement );
23 }
24
25 private long id ;
26 private String name ;
27 private Type type ;
28 private String description ;
29 private String manufacturer ;
30 private double price ;
31 private int stock ;
32 protected transient ClassInstanceAdvisor _instanceAdvisor ;
33 private transient ProductMixin
34 _jboss$thesis$inventory$service$ProductMixin$aop$mixin;
35
36 public ProductImpl () {
37 _instanceAdvisor = new ClassInstanceAdvisor ( this );
38 _jboss$thesis$inventory$service$ProductMixin$aop$mixin = new ProductMixin (
39 this , 20 , 0);
40 }
41
48
49 public long
50 jboss$thesis$inventory$model$ProductImpl$setId$WithoutAdvisement() {
51 id_w_$WithoutAdvisement ( this , IdUtil . getNextId (0));
52
56 public void
57 jboss$thesis$inventory$model$ProductImpl$setName$WithoutAdvisement(
58 String name ) {
59 name_w_$WithoutAdvisement ( this , name );
60 }
61
62 public long
63 jboss$thesis$inventory$model$ProductImpl$getId$WithoutAdvisement() {
64 return id_r_$WithoutAdvisement ( this );
65 }
66
67 public void
68 jboss$thesis$inventory$model$ProductImpl$setType$WithoutAdvisement(
69 Type type ) {
70 type_w_$WithoutAdvisement ( this , type );
71 }
72
73 public void
74 jboss$thesis$inventory$model$ProductImpl$setDescription$WithoutAdvisement(
75 String description ) {
76 description_w_$WithoutAdvisement( this , description );
77 }
78
79 public void
80 jboss$thesis$inventory$model$ProductImpl$setManufacturer$WithoutAdvisement(
81 String manufacturer ) {
82 manufacturer_w_$WithoutAdvisement( this , manufacturer );
83 }
84
85 public void
86 jboss$thesis$inventory$model$ProductImpl$setPrice$WithoutAdvisement(
87 double price ) {
88 price_w_$WithoutAdvisement ( this , price );
89 }
90
91 public String
92 jboss$thesis$inventory$model$ProductImpl$getName$WithoutAdvisement() {
93 return name_r_$WithoutAdvisement ( this );
94 }
95
96 public Type
97 jboss$thesis$inventory$model$ProductImpl$getType$WithoutAdvisement() {
98 return type_r_$WithoutAdvisement ( this );
APPENDIX S. INSTRUMENTED DECOMPILED CLASSES 191
99 }
100
149 if (! classesAreCompatible ) {
APPENDIX S. INSTRUMENTED DECOMPILED CLASSES 192
193 return ;
194 }
195
201 return
202 jboss$thesis$inventory$model$ProductImpl$getId$WithoutAdvisement();
203 }
204 else
205 {
206 return (( Long ) _added_m$0 ( new Object [0] ,
207 0 xac2adf437a698318L )). longValue ();
208 }
209 }
210
215 return ;
216 }
217
225 return ;
226 }
227
235 return ;
236 }
237
245 return ;
246 }
247
323 return ;
324 }
325
344 return ;
345 }
346
354 return ;
355 }
356
S.4 Reservation.java
Source of jboss.thesis.inventory.model.Reservation
1 package jboss . thesis . inventory . model ;
2
14 static {
15 aop$class$WithoutAdvisement = Class. forName (
16 " jboss . thesis . inventory . model . Reservation ");
17 aop$classAdvisor$WithoutAdvisement = AspectManager . instance (). getAdvisor (
18 aop$class$WithoutAdvisement );
19 }
20
21 private long id ;
22 private int quantity ;
23 private Product product ;
24 protected transient ClassInstanceAdvisor _instanceAdvisor ;
25
26 public Reservation () {
27 _instanceAdvisor = new ClassInstanceAdvisor ( this );
28 }
29
40 public double
41 jboss$thesis$inventory$model$Reservation$getPrice$WithoutAdvisement() {
42 return product_r_$WithoutAdvisement ( this ). getPrice () *
43 ( double ) quantity_r_$WithoutAdvisement( this );
44 }
45
46 public Product
47 jboss$thesis$inventory$model$Reservation$getProduct$WithoutAdvisement() {
APPENDIX S. INSTRUMENTED DECOMPILED CLASSES 200
51 public void
52 jboss$thesis$inventory$model$Reservation$setProduct$WithoutAdvisement(
53 Product product ) {
54 product_w_$WithoutAdvisement ( this , product );
55 }
56
57 public int
58 jboss$thesis$inventory$model$Reservation$getQuantity$WithoutAdvisement() {
59 return quantity_r_$WithoutAdvisement( this );
60 }
61
62 public void
63 jboss$thesis$inventory$model$Reservation$setQuantity$WithoutAdvisement(
64 int quantity ) {
65 quantity_w_$WithoutAdvisement( this , quantity );
66 }
67
68 public boolean
69 jboss$thesis$inventory$model$Reservation$equals$WithoutAdvisement(
70 Object obj ) {
71 boolean classesAreCompatible = getClass (). isAssignableFrom ( obj . getClass ());
72
73 if (! classesAreCompatible ) {
74 return false ;
75 }
76
99 }
100 else {
101 return (( Long ) _added_m$0 ( new Object [0] ,
102 0 xac2adf437a698318L )). longValue ();
103 }
104 }
105
142 return ;
143 }
144
150 return
151 jboss$thesis$inventory$model$Reservation$getQuantity$WithoutAdvisement();
152 }
153 else {
154 return (( Integer ) _added_m$0 ( new Object [0] ,
155 0 x38e2a4bb703e541cL )). intValue ();
156 }
157 }
158
201
Developing complex systems is not a simple matter. Using a build tool like Ant is
not just a good idea it is a necessity. As the construction and maintenance of build
scripts can be a major challenge we here supply the complete build script for our
Inventory Management system. It is here for inspiration note that it is not a
fine-tuned build script with production qualities and that it contains elements not
relevant for the code supplied in the appendices.
Source of ant.properties
1 project . name = Inventory Management
2 version = 0.1
3 project = inventory - management
4 year = 2003
5
6 debug = on
7 optimize = on
8 deprecation = off
9
13 # LIB SETTINGS
14 lib . dir = ${ basedir }/ lib
15 common . lib . dir = ${ basedir }/../ lib
16
17 # SRC SETTINGS
18 src . dir = ${ basedir }/ src
204
APPENDIX T. BUILDING AND DEPLOYING WITH ANT 205
33 # OTHER SETTINGS
34 jboss. home = ${ env . JBOSS_HOME }
35 jdk . home = ${ env . JAVA_HOME }
36 # java . home = ${ env . JAVA_HOME }
37 # ant . home = ${ env . ANT_HOME }
38 j2ee . jars = ${ lib . dir }/ j2ee . jar
39 servlet - lib . path = ${ jboss . home }/ server / default / lib / javax. servlet . jar
40 jboss. configuration = default
41 # print property info at every target invocation or not :
42 print - info = false
43
44
45 # DEPENDENCY DIRS
46
47 # BUILD SETTINGS
48 build. dir = ${ basedir }/ build
49 build. classes . dir = ${ build. dir }/ classes
50 build. tmp . dir = ${ build . dir }/ tmp
51 build. war . dir = ${ build . dir }/ war
52 build. aop . dir = ${ build . dir }/ aop
53 build. client . dir = ${ build . dir }/ client
54 build. generate . dir = ${ build . dir }/ generate
55 build. bin . dir = ${ build . dir }/ bin
56 build. javadocs . dir = ${ build . dir }/ docs / api
57 build. metainf . dir = ${ build. dir }/ META - INF
58 build. webinf . dir = ${ build . dir }/ WEB - INF
59 build. mbeans . dir = ${ build . dir }/ mbeans
60
67
68
69 # JUNIT SETTINGS
APPENDIX T. BUILDING AND DEPLOYING WITH ANT 206
Source of build.xml
1 <? xml version ="1.0"? >
2 < project name =" AOP - examples " default =" compile - all " basedir ="." >
3 <!--
4 Give user a chance to override without editing this file
5 ( and without typing -D each time they run it )
6 -->
7 < property file =" ${ basedir }/ ant . properties " / >
8 < property file =" ${ user . home }/ ant . properties " / >
9 < property environment =" env "/ >
10 < property name =" user " value =" ${ user . name }"/ >
11 < property name =" jboss . home " value =" ${ env . JBOSS_HOME }"/ >
12 < property name =" jdk . home " value =" ${ env . JAVA_HOME }"/ >
13 < property name =" junit . home " value =" ${ env . JUNIT_HOME }"/ >
14 < property name =" jboss . lib " value =" ${ jboss . home }/ lib " / >
15 < property name =" jboss . client " value =" ${ jboss . home }/ client " / >
16 < property name =" jboss . deploy "
17 value =" ${ env . JBOSS_HOME }/ server /${ jboss . configuration }/ deploy "/ >
18 < property name =" jboss . server . conf "
19 value =" ${ env . JBOSS_HOME }/ server /${ jboss . configuration }"/ >
20
48 < pathelement location =" ${ env . JBOSS_HOME }/ lib / jboss - system . jar " / >
49 < pathelement location =" ${ env . JBOSS_HOME }/ lib / jboss - common . jar " / >
50 < pathelement location =" ${ env . JBOSS_HOME }/ lib / javassist . jar " / >
51 < pathelement location =" ${ env . JBOSS_HOME }/ lib / jboss - jmx . jar " / >
52 < pathelement
53 location =" ${ env . JBOSS_HOME }/ server /${ jboss . configuration }/ lib / jboss . jar "
54 />
55
56 < pathelement
57 location =" ${ env . JBOSS_HOME }/ server /
58 ${ jboss . configuration }/ lib / jboss - aop . jar "
59 />
60
61 < pathelement
62 location =" ${ env . JBOSS_HOME }/ server /
63 ${ jboss . configuration }/ lib / javax . servlet . jar "
64 />
65
66 < pathelement
67 location =" ${ env . JBOSS_HOME }/ server /
68 ${ jboss . configuration }/ lib / jboss - j2ee . jar "
69 />
70 </ path >
71
80 < pathelement
81 location =" ${ env . JBOSS_HOME }/ server /
82 ${ jboss . configuration }/ lib / jboss - management . jar "
83 />
84
85 < pathelement
86 location =" ${ env . JBOSS_HOME }/ server /
87 ${ jboss . configuration }/ lib / jboss - remoting . jar "
88 />
89
90 < pathelement
91 location =" ${ env . JBOSS_HOME }/ server /
92 ${ jboss . configuration }/ lib / jmx - adaptor - plugin . jar "
93 />
94
95 < pathelement
96 location =" ${ env . JBOSS_HOME }/ server /
97 ${ jboss . configuration }/ lib / jnpserver . jar "
98 />
APPENDIX T. BUILDING AND DEPLOYING WITH ANT 209
99
100 <!-- include necessary jar files from jboss - client -->
101 < pathelement location =" ${ env . JBOSS_HOME }/ client / concurrent . jar " / >
102
123 < target name =" info " if =" print - info ">
124 < echo message ="-------------- USER INFO -------------"/>
125 < echo message =" user = ${ user }"/ >
126 < echo message =" user . home = ${ user . home }"/ >
127 < echo message =" "/ >
128 < echo message ="-------------- HOME CONFIG -------------"/>
129 < echo message =" java . home = ${ java . home }"/ >
130 < echo message =" jdk . home = ${ jdk . home }"/ >
131 < echo message =" ant . home = ${ ant . home }"/ >
132 < echo message =" jboss . home = ${ jboss. home }"/ >
133 < echo message =" "/ >
134 < echo message ="-------------- DEPLOY DIRS -------------"/>
135 < echo message =" jboss . deploy = ${ jboss . deploy }"/ >
136 < echo message =" "/ >
137 < echo message ="-------------- JBOSS PATHS -------------"/>
138 < echo message =" jboss . configuration = ${ jboss . configuration }"/ >
139 < echo message =" jboss . lib = ${ jboss . lib }"/ >
140 < echo message =" jboss . client = ${ jboss . client }"/ >
141 < echo message =" jboss . lib = ${ jboss . lib }"/ >
142 < echo message =" "/ >
143 < echo message ="-------------- BUILD DIRS -------------"/>
144 < echo message =" build . classes . dir = ${ build . classes . dir }"/ >
145 < echo message =" build . war . dir = ${ build . war . dir }"/ >
146 < echo message =" build . deploy . dir = ${ build. deploy . dir }"/ >
147 < echo message =" build . dir = ${ build . dir }"/ >
148 < echo message =" lib . dir = ${ lib . dir }"/ >
149 < echo message =" "/ >
APPENDIX T. BUILDING AND DEPLOYING WITH ANT 210
167 < target name =" compile - all " depends =" init ">
168 < antcall target =" compile "/ >
169 < antcall target =" compile - aop "/ >
170 < antcall target =" compile - mbeans "/ >
171 </ target >
172
173 < target name =" compile " depends =" init ">
174 < mkdir dir =" ${ build . classes . dir }"/ >
175
176 < javac destdir =" ${ build. classes . dir }" debug =" ${ debug }"
177 deprecation =" ${ deprecation }" optimize =" ${ optimize }"
178 classpathref =" mbean . classpath " >
179 < src path =" ${ src . java . dir }"/ >
180 </ javac >
181
182 <!-- set a property to true if the build . classes . dir is not empty -->
183 < available file =" ${ build . classes . dir }/ jboss " type =" dir "
184 property =" build . classes . dir -is -not - empty "/ >
185 </ target >
186
187 < target name =" compile - aop " depends =" init ">
188 < mkdir dir =" ${ build . aop . dir }"/ >
189 < antcall target =" deploy - util " / >
190
191 < javac destdir =" ${ build. aop . dir }" debug =" ${ debug }"
192 deprecation =" ${ deprecation }" optimize =" ${ optimize }"
193 classpathref =" mbean . classpath " >
194 < src path =" ${ src . aop . dir }"/ >
195 </ javac >
196
197 <!-- set a property to true if the build . aop . dir is not empty -->
198 < available file =" ${ build . aop . dir }/ jboss " type =" dir "
199 property =" build . aop .dir -is -not - empty "/ >
200 </ target >
APPENDIX T. BUILDING AND DEPLOYING WITH ANT 211
201
202 < target name =" compile - client " depends =" init ">
203 < mkdir dir =" ${ build . classes . dir }"/ >
204
205 < javac destdir =" ${ build. classes . dir }" debug =" ${ debug }"
206 deprecation =" ${ deprecation }" optimize =" ${ optimize }"
207 classpathref =" mbean. classpath ">
208 < src path =" ${ src . client . dir }"/ >
209 </ javac >
210
211 < copy todir =" ${ build . classes . dir }" >
212 < fileset dir =" ${ src . resources . dir }" includes =" jndi . properties , policy "/ >
213 </ copy >
214
215 <!-- set a property to true if the build . aop . dir is not empty -->
216 < available file =" ${ build . aop . dir }/ jboss " type =" dir "
217 property =" build . aop .dir -is -not - empty "/ >
218 </ target >
219
220 < target name =" compile - web " depends =" compile , compile - aop "
221 if =" servlet - lib . path ">
222 < mkdir dir =" ${ build . war . dir }"/ >
223
228 < javac destdir =" ${ build. war . dir }" debug =" ${ debug }"
229 deprecation =" ${ deprecation }" optimize =" ${ optimize }"
230 classpathref =" web . path " >
231 < src path =" ${ src . servlet . dir }"/ >
232 </ javac >
233
234 <!-- set a property to true if the build . war . dir is not empty -->
235 < available file =" ${ build . war . dir }/ jboss " type =" dir "
236 property =" build . war .dir -is -not - empty "/ >
237 </ target >
238
239 < target name =" compile - mbeans " depends =" compile - aop ">
240 < mkdir dir =" ${ build . mbeans . dir }"/ >
241
242 < javac destdir =" ${ build. mbeans . dir }" debug =" ${ debug }"
243 deprecation =" ${ deprecation }" optimize =" ${ optimize }"
244 classpathref =" mbean . classpath " >
245 < src path =" ${ src . mbeans . dir }"/ >
246 </ javac >
247
248 <!-- set a property to true if the build . mbeans . dir is not empty -->
249 < available file =" ${ build . mbeans . dir }/ jboss " type =" dir "
250 property =" build . mbeans . dir -is - not - empty "/ >
251 </ target >
APPENDIX T. BUILDING AND DEPLOYING WITH ANT 212
252
253 < target name =" sar " depends =" compile - mbeans , aop "
254 if =" build . mbeans .dir -is - not - empty ">
255 < mkdir dir =" ${ build . deploy . dir }"/ >
256 < mkdir dir =" ${ build . mbeans . dir }"/ >
257 < mkdir dir =" ${ build . metainf . dir }"/ >
258
264 < move file =" ${ build . metainf . dir }/ ${ project }- service . xml "
265 tofile =" ${ build . metainf . dir }/ jboss - service . xml "/ >
266
267 < copy file =" ${ src . resources . dir }/ policy " todir =" ${ build . metainf . dir }"/ >
268
269 <!-- create the sar file called ${ project }. sar -->
270 < jar jarfile =" ${ build . deploy . dir }/ ${ project }. sar ">
271 < metainf dir =" ${ build. metainf . dir }" >
272 < include name =" jboss - service . xml "/ >
273 < include name =" policy "/ >
274 </ metainf >
275 < fileset dir =" ${ build. mbeans . dir }"
276 excludes ="**/ Performance * ,**/ Experiment * " / >
277 < fileset dir =" ${ build. deploy . dir }" includes =" ${ project }- jar . aop "/ >
278 </ jar >
279
284 < target name =" jar " depends =" compile " if =" build . classes .dir -is - not - empty ">
285 < mkdir dir =" ${ build . deploy . dir }"/ >
286 < mkdir dir =" ${ build . client . dir }"/ >
287
288 <!-- create the jar file called ${ project }- jar . jar -->
289 < jar jarfile =" ${ build . deploy . dir }/ ${ project }- jar . jar ">
290 < metainf dir =" ${ src . metainf . dir }" >
291 < include name =" ${ project }- jar . xml "/ >
292 </ metainf >
293 < fileset dir =" ${ build. classes . dir }" / >
294 </ jar >
295 </ target >
296
297 < target name =" util - jar " depends =" compile ">
298 < mkdir dir =" ${ build . deploy . dir }"/ >
299
300 <!-- create the jar file called thesis - util . jar -->
301 < jar jarfile =" ${ build . deploy . dir }/ thesis - util . jar ">
302 < fileset dir =" ${ build. classes . dir }" / >
APPENDIX T. BUILDING AND DEPLOYING WITH ANT 213
306 < target name =" aop " depends =" compile - aop " if =" build . aop .dir -is - not - empty ">
307 < mkdir dir =" ${ build . deploy . dir }"/ >
308 < mkdir dir =" ${ build . metainf . dir }"/ >
309
310 <!-- rename ${ project }- aop . xml to jboss - aop . xml -->
311 < copy todir =" ${ build . metainf . dir }" >
312 < fileset dir =" ${ src . metainf . dir }" includes =" ${ project }- aop . xml "/ >
313 </ copy >
314
315 < move file =" ${ build . metainf . dir }/ ${ project }- aop . xml "
316 tofile =" ${ build . metainf . dir }/ jboss - aop . xml "/ >
317
318 <!-- create the jar file called ${ project }- jar . aop -->
319 < jar jarfile =" ${ build . deploy . dir }/ ${ project }- jar . aop ">
320 < metainf dir =" ${ build. metainf . dir }" >
321 < include name =" jboss - aop . xml "/ >
322 </ metainf >
323 < fileset dir =" ${ build. aop . dir }" >
324 < include name =" jboss / thesis / inventory / controller /**" / >
325 < include name =" jboss / thesis / inventory / model /**" / >
326 < include name =" jboss / thesis / inventory / service /**" / >
327 </ fileset >
328 </ jar >
329
334 < target name =" war " depends =" compile - web " if =" build . war .dir -is - not - empty ">
335 < mkdir dir =" ${ build . deploy . dir }"/ >
336 < mkdir dir =" ${ build . classes . dir }"/ >
337
338 < war destfile =" ${ build . deploy . dir }/ ${ project }- web . war "
339 webxml =" ${ src . webinf . dir }/ ${ project }- web . xml " >
340 < fileset dir =" ${ src . web . dir }" excludes ="**/. donotremove "/ >
341 < classes dir =" ${ build. war . dir }"/ >
342 </ war >
343 </ target >
344
345 < target name =" ear " depends =" aop , jar ,war , sar ">
346 < ear appxml =" ${ src . metainf . dir }/ ${ project }- application . xml "
347 destfile =" ${ build . deploy . dir }/ ${ project }- app . ear ">
348 < fileset dir =" ${ build. deploy . dir }" includes ="*. war ,*. aop ,*. jar ,*. sar "
349 excludes ="*. ear "/ >
350 </ ear >
351 </ target >
352
353 < target name =" client - jar " depends =" compile , aop , compile - client ">
APPENDIX T. BUILDING AND DEPLOYING WITH ANT 214
354 < mkdir dir =" ${ build . deploy . dir }"/ >
355 < mkdir dir =" ${ build . client . dir }"/ >
356
357 < copy file =" ${ src . metainf . dir }/ log4j . xml " todir =" ${ build . deploy . dir }"/ >
358
359 <!-- create the jar file called ${ project }- client . jar -->
360 < jar jarfile =" ${ build . deploy . dir }/ ${ project }- client . jar ">
361 < fileset dir =" ${ build. classes . dir }" / >
362 < fileset dir =" ${ build. aop . dir }" / >
363 < manifest >
364 < attribute name =" Main - Class " value =" ${ main . class }"/ >
365 </ manifest >
366 </ jar >
367
368 <!-- Uncomment this the first time you run this target .
369 Comment out again after first run -->
370 <!--
371 < genkey alias =" inventory - management " storepass =" secret "
372 dname =" CN = Thesis Boyzz , OU = AOP Division , O= itu .dk , C= DK "/ >
373 -->
374
375 < copy file =" ${ env . JBOSS_HOME }/ client / concurrent . jar "
376 todir =" ${ build . deploy . dir }"/ >
377 < signjar jar =" ${ build . deploy . dir }/ concurrent . jar "
378 alias =" inventory - management " storepass =" secret "/ >
379
386 < copy file =" ${ env . JBOSS_HOME }/ client / jboss - common - client . jar "
387 todir =" ${ build . deploy . dir }"/ >
388 < signjar jar =" ${ build . deploy . dir }/ jboss - common - client . jar "
389 alias =" inventory - management " storepass =" secret "/ >
390
404 < signjar jar =" ${ build . deploy . dir }/ ${ project }- client . jar "
APPENDIX T. BUILDING AND DEPLOYING WITH ANT 215
405 alias =" inventory - management " storepass =" secret "/ >
406
407 < copy file =" ${ build . deploy . dir }/ concurrent . jar "
408 todir =" ${ build . deploy . dir }/ temp "/ >
409
410 < copy file =" ${ build . deploy . dir }/ jboss - aop . jar "
411 todir =" ${ build . deploy . dir }/ temp "/ >
412
413 < copy file =" ${ build . deploy . dir }/ ${ project }- client . jar "
414 todir =" ${ build . deploy . dir }/ temp "/ >
415
416 < copy file =" ${ build . deploy . dir }/ jboss - common - client . jar "
417 todir =" ${ build . deploy . dir }/ temp "/ >
418
419 < copy file =" ${ build . deploy . dir }/ jnpserver . jar "
420 todir =" ${ build . deploy . dir }/ temp "/ >
421
422 < copy file =" ${ build . deploy . dir }/ jboss - remoting . jar "
423 todir =" ${ build . deploy . dir }/ temp "/ >
424
425 < copy file =" ${ build . classes . dir }/ policy " todir =" ${ build . deploy . dir }/ temp "/ >
426
432 < target name =" client - war " depends =" client - jar ">
433 < war destfile =" ${ build . deploy . dir }/ ${ project }- client . war "
434 webxml =" ${ src . webinf . dir }/ ${ project }- web . xml ">
435 < fileset dir =" ${ build. deploy . dir }/ temp " includes ="**/*. jar , **/ policy "/ >
436 < fileset dir =" ${ build. deploy . dir }" includes ="**/*. jnlp "/ >
437 </ war >
438 </ target >
439
440 < target name =" deploy " depends =" ear ">
441 < copy file =" ${ build . deploy . dir }/ ${ project }- app . ear "
442 todir =" ${ jboss . deploy }"/ >
443 </ target >
444
445 < target name =" deploy - aop " depends =" aop ">
446 < copy file =" ${ build . deploy . dir }/ ${ project }- jar . aop "
447 todir =" ${ jboss . deploy }"/ >
448 </ target >
449
450 < target name =" deploy - client " depends =" client - war ">
451 < copy file =" ${ build . deploy . dir }/ ${ project }- client . war "
452 todir =" ${ jboss . deploy }"/ >
453 </ target >
454
455 < target name =" undeploy - client " depends =" clean ">
APPENDIX T. BUILDING AND DEPLOYING WITH ANT 216
456 < delete file =" ${ jboss . deploy }/ ${ project }- client . war "/ >
457 </ target >
458
459 < target name =" deploy - sar " depends =" sar ">
460 < copy file =" ${ build . deploy . dir }/ ${ project }. sar " todir =" ${ jboss . deploy }"/ >
461 < copy file =" ${ src . resources . dir }/ minimumstock . properties "
462 todir =" ${ env . JBOSS_HOME }/ server /${ jboss . configuration }/ conf "/ >
463 </ target >
464
465 < target name =" undeploy - sar " depends =" clean ">
466 < delete file =" ${ jboss . deploy }/ ${ project }. sar "/ >
467 </ target >
468
469 < target name =" run - remote - client " depends =" compile , aop , compile - client ">
470 < java classname =" ${ main . class }" fork =" true " failonerror =" true "
471 maxmemory ="128 m " classpathref =" tests . classpath ">
472 < jvmarg
473 value =" - Djava . security . policy = file :/ ${ build . classes . dir }/ policy "/ >
474 < jvmarg
475 value =" - Dlog4j . configuration = file :/ ${ src . metainf . dir }/ log4j. xml "/ >
476 < jvmarg value =" - Dorg . jboss . logging . Logger . pluginClass =
477 org . jboss . logging . Log4jLoggerPlugin "/ >
478 </ java >
479 </ target >
480
481 < target name =" run - tests " depends =" compile - client ">
482 < junit dir =" ${ build . classes . dir }" printsummary =" ${ junit . printsummary }"
483 haltonerror =" ${ junit . haltonerror }" haltonfailure =" ${ junit. haltonfailure }"
484 fork =" ${ junit . fork }" jvm =" ${ junit. jvm }" >
485 < jvmarg value =" - Djava. security . policy = policy "/ >
486 < jvmarg value =" - Dlog4j . configuration = file :/ ${ src . metainf . dir }/ log4j . xml "
487 />
488 < jvmarg value =" - Dorg . jboss . logging . Logger . pluginClass =
489 org . jboss . logging . Log4jLoggerPlugin "/ >
490
491 < test name =" ${ main . test . class }" haltonfailure =" no " outfile =" result "/ >
492
497 < formatter type =" plain " usefile =" ${ junit . formatter . usefile }"/ >
498 </ junit >
499 </ target >
500
505 < target name =" clean - deploy - sar " depends =" clean ">
506 < antcall target =" undeploy - sar "/ >
APPENDIX T. BUILDING AND DEPLOYING WITH ANT 217
509 < target name =" deploy - util " depends =" util - jar ">
510 < copy file =" ${ build . deploy . dir }/ thesis - util . jar "
511 todir =" ${ env . JBOSS_HOME }/ server /${ jboss . configuration }/ lib "/ >
512
513 <!--
514 copy the src file instead of the comiled file . This will ensure
515 that the file will be included in a jboss jar file somewhere and thus
516 included on the class path and that it will be available at server boot .
517 -->
518 < copy file =" ${ src . metainf . dir }/ class - file - writer . properties "
519 todir =" ${ env . JBOSS_HOME }/ server /${ jboss. configuration }/ conf "/ >
520 </ target >
521
534 <!-- rename ${ project }- aop . xml to jboss - aop . xml -->
535 < copy todir =" ${ build . metainf . dir }" >
536 < fileset dir =" ${ src . metainf . dir }" includes =" performancetest - aop . xml "/ >
537 </ copy >
538
539 < move file =" ${ build . metainf . dir }/ performancetest - aop . xml "
540 tofile =" ${ build . metainf . dir }/ jboss - aop . xml "/ >
541
542 <!-- create the jar file called performancetest - jar . aop -->
543 < jar jarfile =" ${ build . deploy . dir }/ performancetest - jar . aop ">
544 < metainf dir =" ${ build. metainf . dir }" >
545 < include name =" jboss - aop . xml "/ >
546 </ metainf >
547 < fileset dir =" ${ build. aop . dir }"
548 includes =" jboss / thesis / performancetest /**" / >
549 </ jar >
550
557 < move file =" ${ build . metainf . dir }/ performancetest - service . xml "
APPENDIX T. BUILDING AND DEPLOYING WITH ANT 218
558 tofile =" ${ build . metainf . dir }/ jboss - service . xml "/ >
559
560 <!-- create the sar file called ${ project }. sar -->
561 < jar jarfile =" ${ build . deploy . dir }/ performancetest . sar ">
562 < metainf dir =" ${ build. metainf . dir }" >
563 < include name =" jboss - service . xml "/ >
564 </ metainf >
565 < fileset dir =" ${ build. mbeans . dir }" includes ="**/ PerformanceT *" / >
566 < fileset dir =" ${ build. deploy . dir }" includes =" performancetest - jar . aop "/ >
567 < fileset dir =" ${ build. classes . dir }" includes ="**/ Timer . class "/ >
568 </ jar >
569
573 < copy file =" ${ build . deploy . dir }/ performancetest . sar "
574 todir =" ${ jboss . deploy }"/ >
575 </ target >
576
577 < target name =" undeploy - performancetest " depends =" clean ">
578 < delete file =" ${ jboss . deploy }/ performancetest . sar "/ >
579 </ target >
580
593 <!-- rename experiments - aop . xml to jboss - aop . xml -->
594 < copy todir =" ${ build . metainf . dir }" >
595 < fileset dir =" ${ src . metainf . dir }" includes =" experiments - aop . xml "/ >
596 </ copy >
597
598 < move file =" ${ build . metainf . dir }/ experiments - aop . xml "
599 tofile =" ${ build . metainf . dir }/ jboss - aop . xml "/ >
600
601 <!-- create the jar file called experiments - jar . aop -->
602 < jar jarfile =" ${ build . deploy . dir }/ experiments - jar . aop ">
603 < metainf dir =" ${ build. metainf . dir }" >
604 < include name =" jboss - aop . xml "/ >
605 </ metainf >
606 < fileset dir =" ${ build. aop . dir }" includes =" jboss / thesis / experiments /**" / >
607 </ jar >
608
APPENDIX T. BUILDING AND DEPLOYING WITH ANT 219
614 < move file =" ${ build . metainf . dir }/ experiments - service . xml "
615 tofile =" ${ build . metainf . dir }/ jboss - service . xml "/ >
616
617 <!-- create the sar file called experiments . sar -->
618 < jar jarfile =" ${ build . deploy . dir }/ experiments . sar ">
619 < metainf dir =" ${ build. metainf . dir }" >
620 < include name =" jboss - service . xml "/ >
621 <!-- include name =" policy "/ - - >
622 </ metainf >
623 < fileset dir =" ${ build. mbeans . dir }" includes ="**/ Experiment *" / >
624 < fileset dir =" ${ build. deploy . dir }" includes =" experiments - jar . aop "/ >
625 <!-- fileset dir =" ${ build . classes . dir }" includes =" Timer . class "/ - - >
626 </ jar >
627
631 < copy file =" ${ build . deploy . dir }/ experiments . sar " todir =" ${ jboss . deploy }"/ >
632 </ target >
633
634 < target name =" undeploy - experiments " depends =" undeploy - sar ">
635 < delete file =" ${ jboss . deploy }/ experiments . sar "/ >
636 </ target >
637 </ project >