4.3 Implementing the Component Model
4.3.1 Employed Java technologies
Above all, we need to define which specifics of Java programming language we used for implementating component model.
Java Reflection
Reflection is a feature of Java language, used by programs to examine, or modify the runtime behaviour of applications. It is an advanced feature which needs to be employed with following concerns kept in developer’s mind [40]:
• Performance overhead, because Java virtual machine10 (JVM) optimizations can not be done for dynamically resolved reflection types, parts of the code which use reflection have slower perfor- mance, and therefore in performance demanding applications, using of reflection should be considered carefully;
• Security restrictions, when the application is running under se- curity manager11, some of the required reflection permissions do
not have to be permitted;
• Exposure of internals, because with use of reflection operations, it is for example possible to access private12 fields and methods, it can have unexpected side-effects, and can destroy portability of the application. Reflection behaviour can be changed with upgrades of Java platform, which can cause that application cease to function.
10. The environment where all Java applications run.
11. A mechanism in Java to determine security policy of the application, that is actions which are permitted to perform in an application.
12. Private is key word in Java to determine fields and methods which can be directly accessed only from the class, where they are defined.
Listing 4.4 shows an example of Java class and its fields declared on lines 4 and 7, its method on line 10. That class does not have defined constructor explicitly, therefore a default one is defined for it.
Wile using reflection it is possible to for example access and manip- ulate this class, its fields and constructors during runtime. Listing 4.5 shows an example of such manipulation with this class. On line 5, all declared fields are retrieved. On line 7 we are iterating over this array of all declared fields, retrieving the name of the field, its annotation Page if exists, information whether the field is accessible, and its generic type. On line 20, there is a demonstration of a way of creating new instances of classes.
1 public c l a s s S h o w c a s e R e f l e c t i o n C a p a b i l i t i e s { 2
3 public s t a t i c void main ( S t r i n g [ ] a r g s ) throws
I n s t a n t i a t i o n E x c e p t i o n , I l l e g a l A c c e s s E x c e p t i o n { 4 5 F i e l d [ ] d e c l a r e d F i e l d s = T e s t G o o g l e T r a n s l a t e .c l a s s. g e t D e c l a r e d F i e l d s ( ) ; 6 7 f o r( F i e l d i : d e c l a r e d F i e l d s ) { 8 S t r i n g name = i . getName ( ) ; 9 Page a n n o t a t i o n = i . g e t A n n o t a t i o n ( Page .c l a s s) ; 10 boolean i s A c c e s s i b l e = i . i s A c c e s s i b l e ( ) ; 11 Type t y p e = i . getType ( ) ; 12 13 System . o u t . p r i n t l n ( name ) ; 14 System . o u t . p r i n t l n ( a n n o t a t i o n ) ; 15 System . o u t . p r i n t l n ( i s A c c e s s i b l e ) ; 16 System . o u t . p r i n t l n ( t y p e ) ; 17 System . o u t . p r i n t l n ( ) ; 18 } 19 20 T e s t G o o g l e T r a n s l a t e i n s t a n c e = T e s t G o o g l e T r a n s l a t e .c l a s s. n e w I n s t a n c e ( ) ; 21 System . o u t . p r i n t l n ( i n s t a n c e ) ; 22 } 23 }
Listing 4.5: Java Reflection example.
List of Java Reflection features is not completed with these few ones described, but these are almost all, which were used in the implemen-
tation. Moreover one another Java reflection feature is utilized in the implementation model, which is quite fundamental, and that is Java Dynamic Proxies.
Java Dynamic Proxies
Firstly, we need to define Proxy pattern. Formally, it can be defined as a pattern that provides a surrogate for another object to control access to it.
A class diagram for this pattern is shown on Figure 4.4. Both Proxy and RealSubject classes implement a common interface Subject. Hence when a RealSubject instance is needed, the Proxy instance can be used instead. Usually, Proxy instance contains reference to the RealSubject, and dispatches the method invocations to it [39].
Figure 4.4: UML Class diagram for Proxy Pattern.
There are several reasons for creating a surrogate object, and then the names of the proxies are inferred from this reasons; for example it is created to control access to a network resources (Firewall Proxy), it can be created to provide temporary storage for results of expensive operations (Caching Proxy), or to act as local representative for an object that does run in the same address space (Remote Proxy), in the case of Java language, in the same JVM.
Java Dynamic Proxies is a mechanism for creating a Proxy object at runtime, that implements an interface, or multiple interfaces, and forwards methods invocations to a specified class. They are created as stated in the previous section with use of Java Reflection API. The
class diagram for Java Dynamic Proxy (Figure 4.5) differs a little from the general Proxy class diagram, because it is supplemented with InvocationHandler class. Its purpose is to respond to any method calls on the Proxy; it is the way of declaring what Proxy has to do before invoking method on the real object [39].
An example of the Java Dynamic Proxies use case is creating dynamic mock objects for unit testing.
Figure 4.5: UML Class diagram for Java Dynamic Proxy Pattern.
Java Generics
Java Generics is a feature added to Java language in version 1.3. Its main purpose is to enhance type-safety. Consider following Listing 4.6, which demonstrates the problems, when not using Java Generics.
The class Drawer enables to add any object to it, because its field is of the Object type, which is the super type of all Java objects. The main method of the class ShowcaseGenericProblems is compiled without problems, however, when running, ClassCastException Java exception is thrown because of line 20, where we are trying to cast an object of type String to an object of type Object. This is just an artificial example, but similar problem can easily occur in real-world examples. The main problem is that it is not caught at compile time, but it is exposed during runtime.
Listing 4.7 solves this problem by using of Generics. GenericDrawer has generic type T, which can be supplemented by
any type, and the return value of method getItem is also of the generic type T. In the main method of the class GenericsSolution, we are per- forming the same scenario as in previous example, only the instantiation of the class Drawer uses generics now. Note that is not possible to even compile GenericsSolution class, we get the error message "Cannot cast from String to Integer". The result is expected and desired as we want to catch this type of errors during compile time.
1 public c l a s s GenericDrawer<T> { 2
3 private T i t e m ; 4
5 public void addItem (T i t e m ) { 6 t h i s. i t e m = i t e m ; 7 } 8 9 public T g e t I t e m ( ) { 10 return t h i s. i t e m ; 11 } 12 } 13 14 public c l a s s G e n e r i c s S o l u t i o n { 15
16 public s t a t i c void main ( S t r i n g [ ] a r g s ) { 17
18 GenericDrawer<S t r i n g > drawer = new
GenericDrawer<S t r i n g >() ;
19 drawer . addItem (" pen ") ; 20
21 I n t e g e r pen = ( I n t e g e r ) drawer . g e t I t e m ( ) ;
22 }
23 }
Listing 4.6: Example demonstrating type-safety problem when not using Java Generics.
1 public c l a s s Drawer { 2 private O b j e c t i t e m ; 3
4 public void addItem ( O b j e c t i t e m ) { 5 t h i s. i t e m = i t e m ;
6 }
7
9 return t h i s. i t e m ; 10 } 11 } 12 13 public c l a s s S h o w c a s e G e n e r i c P r o b l e m s { 14
15 public s t a t i c void main ( S t r i n g [ ] a r g s ) { 16
17 Drawer drawer = new Drawer ( ) ; 18 drawer . addItem (" pen ") ;
19
20 I n t e g e r pen = ( I n t e g e r ) drawer . g e t I t e m ( ) ;
21 }
22 }
Listing 4.7: Example of solving type-safety problem from Listing 4.6 with using of Java Generics.
Service Provider Interface
Service Provider Interface (SPI) is a mechanism to create modular, plug-in architectures13 which are easy to maintain. For example an
upgrade of one part should not affect whole application.
In Java environment, SPI is a set of public interfaces and abstract classes which defines a service contract. Service provider than has to implement these interfaces, and hence also this contract to fetch its functionality into the application. The exact procedure looks as [41]:
1. The desired functionality which we want to add is packed in a JAR14 file and is on the application classpath15;
2. You have to identify the provided service by placing a file into the directory where the sources of your application are, and under it to the directory /META-INF/services, which contains a fully qualified service name16.
13. An architecture which allows to add functionality by adding to it small modular applications, so called plug-ins.
14. The type of archive in which a Java applications are distributed. 15. It is a parameter to tell JVM where classes are located.
16. A name which is complete in a sense that it contains all names in the sequence above and the name itself, an example is java.lang.String [42].