Chapter 4 GJMA Design Issues
4.4. Computing Model Adaptation Mechanism
4.4.3. Adapt to the MASTER-SLAVE Mode
4.4.3.3. How to Create Complementary Objects
4.4.3.3. How to Create Complementary Objects
In order to solve the third problem, instance creation actions have to be intercepted. To do this, GJMA has to find a hook point in an object initialization path and then inject some interception-related codes into it. It is desirable to describe some Java characteristics before moving on to the main topic. Java guarantees that the constructor method of a class is called whenever an instance of that class is created. It also guarantees that the constructor is called whenever an instance of any subclass is created. In order to guarantee this second point, Java must ensure that every constructor method calls its superclass constructor method. In other words, there is a constructor chaining when creating an object. Because the top class in every constructor chaining is always the class java.lang.Object, which is the root of the class hierarchy as Figure 4-9 shows, and it has only one constructor Object( ), the constructor is always called when an object is created. If it is possible to inject interception-related codes into the constructor Object( ), then instance creation actions can be intercepted. However, there is no way to replace the built-in class java.lang.Object as the previous discussion. Hence, GJMA exploits another way to do this. GJMA modifies the original inheritance relationships as Figure 4-9(a) shows by inserting a class org.gjma.application.GJMAObject as Figure 4-9(b) shows.
The superclass of the class org.gjma.application.GJMAObject is the class java.lang.Object.
After the insertion, the constructor within the class org.gjma.application.GJMAObject will be called when every managed object is created and then the interception-related codes can be put in the constructor.
- 45 -
Figure 4-9: Insert GJMAObject in the inheritance chaining
When the interception-related codes are executed, it implies a managed object is been creating and the codes respond to send a creation command encoded in a GJMAMesg to the other part’s object manager. When the object manager receives the GJMAMesg, the object manager will create the corresponding complementary object. After the complementary object is built, some initialization codes belonging to the other constructors in the constructor chaining will be executed to complete all necessary initializations. The following serves as an example.
Figure 4-10(a) is the general case and the original classes are placed on the same host. Figure 4-10(b) is the case after a deployment and the original classes are spread into two parts. In order to make the discussion clear, some fields and methods are ignored. In Figure 4-10(a), if ObjectX is created from ClassB, ObjectX will have three fields: field1, field2 and field3. This obeys inheritance associations. If ClassA and ClassB are placed on the same host, there is no trouble. In Figure 4-10(b), ClassA on HostB (GJMAClient) is replaced by its proxy class and ClassB on HostC (GJMAServer) is also replaced by its proxy class. In Figure 4-10(b), if ObjextY is created from ClassB, ObjectY will have only two fields: field2 and field3, because of no fields in proxy classes. According to the previous definition, the missed field field1 should be in its complementary object in the other part. In the example, the complementary object of ObjectY will be created from ClassB on HostC, and it will have one field: field1. This means that a logical object may be divided into two parts physically. Traditionally, when an
- 46 -
object is created from a class, its constructor will be called and the constructor will call the constructor of the superclass recursively. For example, in Figure 4-10(a), when an object is created from ClassB, the constructor chaining is executed as following orders:
1. Constructor ClassB( ) is called and it calls the constructor ClassA( ).
2. Constructor ClassA( ) is called, and it calls the constructor Object( ).
3. Constructor Object( ) is called and it is the last constructor to be called. It will create the object instance and then return.
4. Return to constructor ClassA( ). The field1 is initialized here and the remaining initialization codes in the constructor are executed. After completion, the constructor returns.
5. Return to constructor ClassB( ). The field2 as well as field3 are initialized here and the remaining initialization codes in the constructor are executed. After completion, the constructor returns and the object initialization is completed.
- 47 -
Figure 4-10: Separate two associated classes into two different hosts.
We should notice that the initialization order has to be kept after replacing some classes with proxy classes. Figure 4-10 (b) is an example after a deployment. When an object is created from ClassB on HostB (GJMAClient), the initialization order is as follows: (The paragraph starting with Arabic numerals is used to describe the actions taken place on HostB. The paragraph starting with Roman numerals is used to express the actions taken place on HostC.)
1. Constructor ClassB( ) is called and it calls the constructor ClassA( ).
2. Constructor ClassA( ) is called, and it calls the constructor GJMAObject( ).
3. Constructor GJMAObject( )is called and it calls the constructor Object( ).
4. Constructor Object( ) is called and it is the last constructor to be called. It will create
+ClassA()
- 48 -
the object instance and then return.
5. Return to constructor GJMAObject ( ). The codes will send a creation command to the object manager on HostC (GJMAServer).
I. The object manager on HostC receives the command. It calls constructor ClassB(GJMApp) to create the complementary object.
II. Constructor ClassB(GJMApp) is called and it calls the constructor ClassA(GJMApp).
III. Constructor ClassA(GJMApp) is called and it calls the constructor GJMAObject(GJMApp).
IV. Constructor GJMAObject(GJMApp) is called and it calls the constructor Object( ).
V. Constructor Object( ) is called and it is the last constructor to be called. It will create the object instance and then return.
VI. Return to constructor GJMAObject(GJMApp). The codes will set object id and then return.
VII. Return to constructor ClassA(GJMApp). Do nothing and return directly.
VIII. Return to constructor ClassB(GJMApp). Do nothing and return directly. The empty complementary object is completely created.
IX. Return to the object manager. It will store the relationship between the object id and the complementary object reference and then send result to HostB.
6. Return to constructor GJMAObject( ). It will store the relationship between the object id and the object reference and then return.
7. Return to constructor ClassA( ). Because ClassA is a proxy class, it will invoke a remote method init_ClassA( ). The field1 will be initialized in its complementary object on HostC.
8. Return to constructor ClassB( ). ClassB is not a proxy class so the field2 and field3 will be initialized here by invoking the method init_classB( ). After completion, the constructor
- 49 -
returns and the object initialization is completed.
When an object is created from ClassB on HostC (GJMAServer), the initialization order is as follows: (The paragraph starting with Arabic numerals is used to describe the actions taken place on HostC. The paragraph starting with Roman numerals is used to express the actions taken place on HostB.)
1. Constructor ClassB( ) is called and it calls the constructor ClassA( ).
2. Constructor ClassA( ) is called, and it calls the constructor GJMAObject( ).
3. Constructor GJMAObject( )is called and it calls the constructor Object( ).
4. Constructor Object( ) is called and it is the last constructor to be called. It will create the object instance and then return.
5. Return to constructor GJMAObject ( ). The codes will send a creation command to the object manager on HostC (GJMAServer).
I. The object manager on HostB receives the command. It calls constructor ClassB(GJMApp) to create the complementary object.
II. Constructor ClassB(GJMApp) is called and it calls the constructor ClassA(GJMApp).
III. Constructor ClassA(GJMApp) is called and it calls the constructor GJMAObject(GJMApp).
IV. Constructor GJMAObject(GJMApp) is called and it calls the constructor Object( ).
V. Constructor Object( ) is called and it is the last constructor to be called. It will create the object instance and then return.
VI. Return to constructor GJMAObject(GJMApp). The codes will set object id and then return.
VII. Return to constructor ClassA(GJMApp). Do nothing and return directly.
- 50 -
VIII. Return to constructor ClassB(GJMApp). Do nothing and return directly. The empty complementary object is completely created.
IX. Return to the object manager. It will store the relationship between the object id and the complementary object reference and then send result to HostB.
6. Return to constructor GJMAObject( ). It will store the relationship between the object id and the object reference and then return.
7. Return to constructor ClassA( ). ClassA is not a proxy class so the field1 will be initialized here by invoking the method init_classA( ). After completion, it returns.
8. Return to constructor ClassB( ). Because ClassB is a proxy class, it will invoke a remote method init_ClassB( ). The field2 and field3 will be initialized in its complementary object on HostB. After completion, the constructor returns and the object initialization is completed.
It will be clear from these examples that wherever the object is created on, the initializations orders are similar to the original initialization orders but the original object is divided into two objects (an object and its complementary object) physically. So far, we have seen that creating an object from ClassB on HostB is equivalent to creating an object from ClassB on HostC.