ObjectWeb Consortium
Print

Advanced Search - Powered by Google

  Consortium     Activities     Projects     Forge     Events 

Fractal


Project Links
· Home
· Documentation
· Download
· License
· What's New
· Wiki

Developers' Corner
· Workplan
· SVN Repository
· ObjectWeb Forge Site

About
· Team
· Users
· Partners
· Mailing List Archive




Julia Tutorial



AUTHOR :       
E. Bruneton          (France Telecom R&D)

Version   2.0
Released    November 12, 2003




This tutorial explains how to configure the Julia framework, and shows the results of several configuration options.

1 Julia Configuration File

1.1 Generalities

When the getBootstrapComponent() method is called for the first time (see the Fractal Tutorial), and if the fractal.provider system property is set to org.objectweb.fractal.julia.Julia, the Julia framework initializes itself by reading the configuration files whose names are specified in the julia.config system property (in a comma separated name list such as "julia.cfg,julia1.cfg,julia2.cfg").

The Julia configuration files must define the "aliases" used in the newFcInstance method, such as "primitiveTemplate", "compositeTemplate", ... (see the Fractal Tutorial). For each such alias, one must define an Interface class generator, a set of control interface types, a set of controller classes implementing these control interfaces, a set of interceptors, and an optimization level (see next section).

A Julia configuration file uses a LISP-like syntax, and contains a set of alias definitions:

(alias-name1 alias-definition1)
(alias-name2 alias-definition2)
...
(alias-nameN alias-definitionN)

where each definition is a LISP-like term that can contain (backward or forward) references to other aliases (be careful to avoid recursive definitions!). A reference to an alias is a term of the form 'alias-name. If an alias name is defined several times, the last definition overrides the previous ones. It is therefore possible to define a "generic" and shared configuration file, that can be extended and partially or completely overriden by additional, user specific configuration files.

1.2 Controller Descriptor Definitions

The definitions of the aliases used in the newFcInstance method, such as "primitiveTemplate" or "composite", called controller descriptors, must be LISP-like terms of the following form (see ContextClassGenerator for more details):

  # controller descriptor
  (
    # Interface class generator
    class descriptor

The above class descriptor describes the class generator that will be used to generate the Interface objects of the component. A class descriptor must be either of the form "className", or of the form "(objectDescriptor arg1 ... argN)". The first case describes the class "className". The second case describes the class generated by the class generator instance described by "objectDescriptor" with the given arguments. An object descriptor must be either of the form "className", or of the form "(classDescriptor arg1 ... argN)". The first case describes an instance of "className". The second case describes an instance of the class described by "classDescriptor" constructed with the given arguments.

   # control interfaces
   (
     (name signature)
     ...
     (name signature)
   )

The above list describes the control interfaces of the component, as well as its hidden interfaces (whose name starts with '/' - see the Julia documentation). Each element of the list gives the name and the signature (i.e the fully qualified name of a Java interface) of a control interface.

   # controller classes
   (
     object descriptor
     ...
     object descriptor
   )

The above list describes the controller objects of the component. The classes of these objects classes can be arbitrary, provided they have a default public constructor. However, if a controller class needs access to other controller classes, it must implement the Controller interface. The class described by the first class descriptor must implement the Component interface. In these descriptors the 'attributeControllerInterface alias will be replaced by the name of the actual attribute controller interface declared in the component's type, if any.

Although the controller classes can be normal Java classes, in the standard Julia configuration file most of the controller classes are generated classes, generated from mixin classes (see the Julia documentation). For example the object that implements the Component interface is defined as follows:

(component-impl
  ((org.objectweb.fractal.julia.asm.MixinClassGenerator
    ComponentImpl
    org.objectweb.fractal.julia.BasicControllerMixin
    org.objectweb.fractal.julia.BasicComponentMixin
    # to check type related constraints, and for collection interfaces support:
    org.objectweb.fractal.julia.TypeComponentMixin
  ))
)

This means that the class must be generated by mixing the BasicControllerMixin, the BasicComponentMixin and the TypeComponentMixin classes, in this order, which gives a class equivalent to an hypothetical TypeComponentMixin class subclassing a BasicComponentMixin class, itself subclassing the BasicControllerMixin class. The first name after MixinClassGenerator, ComponentImpl, is the name that is given to this mixed class; this name will appear in the exception stack traces.

   ( # interceptors
     [object descriptor]
   )

This optional object descriptor should describe a ClassGenerator object generating Interceptor objects (or an empty tree if the component does not need any interceptor object). This interceptor class generator should be used to generate the interceptor objects of the component. It should behave like the InterceptorClassGenerator. In particular, it should accept the same arguments.

   # optimizations
   object descriptor
   optimization level
 )

The object descriptor should describe a class generator that merges several classes into a single class. This class generator should accept the same arguments as the MergeClassGenerator generator.

The optimization level should be equal to none, mergeControllers, mergeControllersAndInterceptors, mergeControllersAndContent or mergeControllersInterceptorsAndContent. In the first case the controller objects will be instantiated separately, as well as the interceptors and the content part of the component. In the second case a class merging the classes of the controller objects will be generated and instantiated, resulting in a single controller object, while the interceptors and the content part will still be instantiated separately. In the third case a merged class will be generated as before, and the interceptor class generator will be used to generate a sub class of this class that includes the controllers and interceptors code. This sub class will then be instantiated, resulting in a single object playing all the controller and interceptor roles at the same time. In the last two cases, a sub class of the content class including the controller - and, in the last case, the interceptor - classes will be generated and instantiated. In the last case the whole component is therefore instantiated as a single Java object.

2 Configuration Examples

This section shows the impact of various Julia configuration options on deployed applications. It uses the same example as in the Fractal Tutorial. Since the configuration options of each section are given relatively to the configuration options of the previous one, the examples must be executed in the given order.

2.1 Initial Configuration

Go to the example/helloworld directory and type ant execute. You should get the following result:
execute:
     [java] Server: print method called
     [java]     at ServerImpl.print(ServerImpl.java:31)
     [java]     at org.objectweb.fractal.julia.generated.Cf359f1f4_0.print(INTERCEPTOR[Service])
     [java]     at org.objectweb.fractal.julia.generated.Ca49e1bb9_0.print(INTERFACE[Service])
     [java]     at ClientImpl.main(ClientImpl.java:31)
     [java]     at org.objectweb.fractal.julia.generated.Cd9152578_0.main(INTERCEPTOR[Main])
     [java]     at org.objectweb.fractal.julia.generated.C84d15fbd_0.main(INTERFACE[Main])
     [java]     at HelloWorld.main(HelloWorld.java:206)
     [java] Server: begin printing...
     [java] -> hello world
     [java] Server: print done.

The exception stack trace is normal: this is because a printStrackTrace() instruction is included in the print method of the ServerImpl class. This stack trace indicates that there are two indirections between the "external client" HelloWorld and the client component ClientImpl, and two indirections between the client component and the server component ServerImpl. These indirections can be explained as follows.

With the default Julia configuration file used in this example, the "primitive" and "composite" aliases are defined by:

(primitive
  (
    'interface-class-generator
    (
      'component-itf
      'binding-controller-itf
      'super-controller-itf
      'lifecycle-controller-itf
      'name-controller-itf
    )
    (
      'component-impl
      'container-binding-controller-impl
      'super-controller-impl
      'lifecycle-controller-impl
      'name-controller-impl
    )
    (
      (org.objectweb.fractal.julia.asm.InterceptorClassGenerator
        org.objectweb.fractal.julia.asm.LifeCycleCodeGenerator
      )
    )
    org.objectweb.fractal.julia.asm.MergeClassGenerator
    'optimizationLevel
  )
)

(composite
  (
    'interface-class-generator
    (
      'component-itf
      'binding-controller-itf
      'content-controller-itf
      'super-controller-itf
      'lifecycle-controller-itf
      'name-controller-itf
    )
    (
      'component-impl
      'composite-binding-controller-impl
      'content-controller-impl
      'super-controller-impl
      'composite-lifecycle-controller-impl
      'name-controller-impl
    )
    (
    )
    org.objectweb.fractal.julia.asm.MergeClassGenerator
    'optimizationLevel
  )
)

As can be seen, the composite component does not have any interceptor (its life cycle controller is an optimized life cycle controller that does not need interceptor objects, because it delegates the life cycle management operations to the life cycle controller of the sub components). On the other hand, the primitive components have an interceptor used to manage their life cycle. Given the main Julia data structures, and the shortcut algorithm, this configuration explains the previous indirections, as shown in the figure below:

2.2 Effects of intermediate composite components

In the example/helloworld/etc/execute.properties file, change the "run.parameters" line to "run.parameters wrapper". The effect of this change is to instantiate an application with an additional composite component around each primitive component, as shown in the figure below:

Then, type ant execute in the example/helloworld directory. You should get exactly the same result as in the previous section. In other words, despite the fact that two intermediate composite components have been added, the number of indirections between the encapsulated components has not changed. This is because the composite components do not have interceptors, and therefore several component controllers can be bypassed by the shortcut algorithm. In fact, the actual links between the components are the following:

If the composite components have interceptors, then there are more indirections between components. In order to see this, uncomment the (composite 'composite-section2.2) line in the example/helloworld/julia-tutorial.cfg (the effect of this definition is to add an interceptor at the server and client interfaces of the composite components, in order to trace ingoing and outgoing method calls):

(composite-section2.2
  (
    'interface-class-generator
    (
      'component-itf
      'binding-controller-itf
      'content-controller-itf
      'super-controller-itf
      'lifecycle-controller-itf
      'name-controller-itf
    )
    (
      'component-impl
      'composite-binding-controller-impl
      'content-controller-impl
      'super-controller-impl
      'composite-lifecycle-controller-impl
      'name-controller-impl
    )
    (
      (org.objectweb.fractal.julia.asm.InterceptorClassGenerator
        (org.objectweb.fractal.julia.asm.TraceCodeGenerator inout)
      )
    )
    org.objectweb.fractal.julia.asm.MergeClassGenerator
    'optimizationLevel
  )
)

This time the result of ant execute is the following:

execute:
     [java] Entering public abstract void Main.main(java.lang.String[])
     [java] Entering public abstract void Main.main(java.lang.String[])
     [java] Entering public abstract void Service.print(java.lang.String)
     [java] Entering public abstract void Service.print(java.lang.String)
     [java] Server: print method called
     [java]     at ServerImpl.print(ServerImpl.java:31)
     [java]     at org.objectweb.fractal.julia.generated.Cf359f1f4_0.print(INTERCEPTOR[Service])
     [java]     at org.objectweb.fractal.julia.generated.C6a61e603_0.print(INTERCEPTOR[Service])
     [java]     at org.objectweb.fractal.julia.generated.C54a577e2_0.print(INTERCEPTOR[Service])
     [java]     at org.objectweb.fractal.julia.generated.Ca49e1bb9_0.print(INTERFACE[Service])
     [java]     at ClientImpl.main(ClientImpl.java:31)
     [java]     at org.objectweb.fractal.julia.generated.Cd9152578_0.main(INTERCEPTOR[Main])
     [java]     at org.objectweb.fractal.julia.generated.Cc2b70e07_0.main(INTERCEPTOR[Main])
     [java]     at org.objectweb.fractal.julia.generated.Cc2b70e07_0.main(INTERCEPTOR[Main])
     [java]     at org.objectweb.fractal.julia.generated.C84d15fbd_0.main(INTERFACE[Main])
     [java]     at HelloWorld.main(HelloWorld.java:206)
     [java] Server: begin printing...
     [java] -> hello world
     [java] Server: print done.
     [java] Leaving public abstract void Service.print(java.lang.String)
     [java] Leaving public abstract void Service.print(java.lang.String)
     [java] Leaving public abstract void Main.main(java.lang.String[])
     [java] Leaving public abstract void Main.main(java.lang.String[])

The first four lines are printed, in this order, by the input interceptor of the root composite component, the input interceptor of the composite component around the client component, the output interceptor of the composite component around the client component, and finally the input interceptor of the composite component around the server component. The last four lines are also printed by these interceptors, in the reverse order. As shown by the stack trace, there are now four indirections bewteen the components. Indeed, the actual links between the components are the following:

If you change "inout" to "in" in the "composite-section2.2" definition, then no output interceptor is generated, which removes one trace and one indirection between the client and server component. If you change "inout" to "out", then no input interceptor is generated, which removes three traces and many indirections.

2.3 Life cycle management options

In the previous examples the life cycle was managed by interceptors in the primitive components (the role of these interceptors is to suspend incoming method calls while the component is stopped). The advantage of this approach is that is does not require life cycle related interceptors in the composite components, which allows for many shortcut opportunities. The disadvantage is that there is always at least two indirections between the primitive components.

Another solution is to put the life cycle management interceptors in the composite component, instead of in the primitive ones. In this case the minimum number of indirections between two sibling primitive components is only one. But then there are more indirections between components that are not in the same composite, and the primitive components can no longer have their own life cycle controller interface, i.e., they can no longer be started and stopped individually (they can still be dynamically reconfigured but, for that, the whole enclosing component must be stopped first).

The two approaches can be mixed and used at the same time. For example, a composite component without interceptor can contain a primitive component with an interceptor, and a composite component with an interceptor (that itself contains primitive components without interceptors). The figures below summarizes all these possibilities.


Life cycle managed by interceptors in primitive components


Life cyle managed by interceptors in composite components


Mix of the two previous approaches

In order to use interceptors in the composite components but not in the primitive ones, uncomment the (primitive 'primitive-section2.3) and (composite 'composite-section2.3) lines in the julia-tutorial.cfg file (and comment the previously uncommented lines):

(primitive-section2.3
  (
    'interface-class-generator
    (
      'component-itf
      'binding-controller-itf
      'super-controller-itf
      'name-controller-itf
    )
    (
      'component-impl
      'container-binding-controller-impl
      'super-controller-impl
      'name-controller-impl
    )
    (
    )
    org.objectweb.fractal.julia.asm.MergeClassGenerator
    'optimizationLevel
  )
)

(composite-section2.3
  (
    'interface-class-generator
    (
      'component-itf
      'binding-controller-itf
      'content-controller-itf
      'super-controller-itf
      'lifecycle-controller-itf
      'name-controller-itf
    )
    (
      'component-impl
      'composite-binding-controller-impl
      'content-controller-impl
      'super-controller-impl
      'lifecycle-controller-impl
      'name-controller-impl
    )
    (
      (org.objectweb.fractal.julia.asm.InterceptorClassGenerator
        org.objectweb.fractal.julia.asm.LifeCycleCodeGenerator
      )
    )
    org.objectweb.fractal.julia.asm.MergeClassGenerator
    'optimizationLevel
  )
)

Edit the execute.properties file in order to change the "run.parameters ..." line to "run.parameters". Then type ant execute. You should get the following result:

execute:
     [java] Server: print method called
     [java]     at ServerImpl.print(ServerImpl.java:31)
     [java]     at org.objectweb.fractal.julia.generated.Ca49e1bb9_0.print(INTERFACE[Service])
     [java]     at ClientImpl.main(ClientImpl.java:31)
     [java]     at org.objectweb.fractal.julia.generated.C55d992cb_0.main(INTERCEPTOR[Main])
     [java]     at org.objectweb.fractal.julia.generated.C84d15fbd_0.main(INTERFACE[Main])
     [java]     at HelloWorld.main(HelloWorld.java:206)
     [java] Server: begin printing...
     [java] -> hello world
     [java] Server: print done.

As can be seen, there is now only one indirection between the client and server primitive components. Indeed, the actual links between the components are the following:

2.4 Optimized configuration

If some part of an application is composed of components that do not exchange component interface references dynamically, or that always exchange these references via the "meta level", by using the Fractal control interfaces (instead of using the "base level", i.e. business method call parameters), then it is possible to remove all indirections between these components. In order to do this, the primitive components (of this part of the application) must not have life cycle related interceptors, and no life cycle controller interface, as explained in the previous section. In addition, the binding controller of these components must include the OptimizedContainerBindingMixin (this mixin binds the user components to each other directly, without intermediate Interface objects. It also stores the meta data about bindings in a private internal map).

In order to see this, uncomment the (primitive 'primitive-section2.4) (composite 'composite-section2.4) lines in the julia-tutorial.cfg file (and comment the previously uncommented lines):

(primitive-section2.4
  (
    'interface-class-generator
    (
      'component-itf
      'binding-controller-itf
      'super-controller-itf
      'name-controller-itf
    )
    (
      'component-impl
      'static-container-binding-controller-impl
      'super-controller-impl
      'name-controller-impl
    )
    (
    )
    org.objectweb.fractal.julia.asm.MergeClassGenerator
    'optimizationLevel
  )
)

(composite-section2.4
  'composite-section2.3
)

Then type ant execute. You should get the following result, showing that there is no indirection between the client and server component:

execute:
     [java] Server: print method called
     [java]     at ServerImpl.print(ServerImpl.java:31)
     [java]     at ClientImpl.main(ClientImpl.java:31)
     [java]     at org.objectweb.fractal.julia.generated.C55d992cb_0.main(INTERCEPTOR[Main])
     [java]     at org.objectweb.fractal.julia.generated.C84d15fbd_0.main(INTERFACE[Main])
     [java]     at HelloWorld.main(HelloWorld.java:206)
     [java] Server: begin printing...
     [java] -> hello world
     [java] Server: print done.

Indeed, in this case, the actual links between the components are the following:

2.5 Mixin classes

TODO. TO BE UPDATED.

2.6 Merged classes

Julia offers some optimization options to merge some or (almost) all the objects that make up a component into a single object (see here). In order to see the effect of these options, uncomment the (primitive 'primitive-section2.6) line in the julia-tutorial.cfg file. The effect of this change is to print the internal structure of the components of the application, when they are create. Then, uncomment one of the (optimizationLevel ...) line in the julia-tutorial.cfg file (and comment the previously uncommented lines), in order to change the merge class generator optimization level from none to mergeControllers, mergeControllersAndInterceptors, mergeControllersAndContent or mergeControllersInterceptorsAndContent. Then type ant execute to launch the application.

With the none option, you will get something like this for the server component:

     [java] COMPONENT CREATED
     [java] INTERFACES:
     [java]   attribute-controller org.objectweb.fractal.julia.generated.C8a201a40_0@1e00c26c
     [java]   component org.objectweb.fractal.julia.generated.C5929b02d_0@bfd7b62c
     [java]   s org.objectweb.fractal.julia.generated.Ca49e1bb9_0@23087a14
     [java]   lifecycle-controller org.objectweb.fractal.julia.generated.C18c4c884_0@6e4fa7e4
     [java]   binding-controller org.objectweb.fractal.julia.generated.Ce7005b70_0@6d7aaef0
     [java]   super-controller org.objectweb.fractal.julia.generated.C7d0bf956_0@442b008
     [java] CONTROLLER OBJECTS:
     [java]   org.objectweb.fractal.julia.generated.C3d06d42e_0@37697
     [java]   org.objectweb.fractal.julia.generated.C3aa6a740_0@5ecdec
     [java]   org.objectweb.fractal.julia.generated.Cda074c35_0@21807c
     [java]   org.objectweb.fractal.julia.generated.Ccac238dc_0@7a7e74
     [java]   HelloWorld$DebugController@3f74d
     [java]   org.objectweb.fractal.julia.generated.C87ecd5ad_0@6102dc (Interceptor,impl=ServerImpl@2c01f)
     [java] CONTENT:
     [java]   ServerImpl@2c01f

This shows that there are 6 objects for the server interfaces, 6 objects for the controller part (including one interceptor), and one for the content part. With the mergeControllers option, the five controller objects are merged into a single one:

     [java] INTERFACES:
     [java]   attribute-controller org.objectweb.fractal.julia.generated.C8a201a40_0@75ba517c
     [java]   component org.objectweb.fractal.julia.generated.C5929b02d_0@530b523c
     [java]   s org.objectweb.fractal.julia.generated.Ca49e1bb9_0@2a968104
     [java]   lifecycle-controller org.objectweb.fractal.julia.generated.C18c4c884_0@68774c94
     [java]   binding-controller org.objectweb.fractal.julia.generated.Ce7005b70_0@13f78a30
     [java]   super-controller org.objectweb.fractal.julia.generated.C7d0bf956_0@8e81dc68
     [java] CONTROLLER OBJECTS:
     [java]   org.objectweb.fractal.julia.generated.C254eb21f_0@21807c
     [java]   org.objectweb.fractal.julia.generated.Ce26412b6_0@7a7e74 (Interceptor,impl=ServerImpl@3f74d)
     [java] CONTENT:
     [java]   ServerImpl@3f74d

With the mergeControllersAndInterceptors option, the five controller objects and the interceptor object are merged into a single one:

     [java] INTERFACES:
     [java]   attribute-controller org.objectweb.fractal.julia.generated.C8a201a40_0@eb345b4b
     [java]   component org.objectweb.fractal.julia.generated.C5929b02d_0@16bdb73b
     [java]   s org.objectweb.fractal.julia.generated.Ca49e1bb9_0@18e45d5
     [java]   lifecycle-controller org.objectweb.fractal.julia.generated.C18c4c884_0@aa23e489
     [java]   binding-controller org.objectweb.fractal.julia.generated.Ce7005b70_0@49a4db7c
     [java]   super-controller org.objectweb.fractal.julia.generated.C7d0bf956_0@1a755222
     [java] CONTROLLER OBJECTS:
     [java]   org.objectweb.fractal.julia.generated.C91bbe713_0@5ecdec
     [java] CONTENT:
     [java]   ServerImpl@21807c

Finally, with the mergeControllersInterceptorsAndContent option, the content is also merged into the controller and interceptor objects:

     [java] INTERFACES:
     [java]   attribute-controller org.objectweb.fractal.julia.generated.C8a201a40_0@75ba517c
     [java]   component org.objectweb.fractal.julia.generated.C5929b02d_0@530b523c
     [java]   s org.objectweb.fractal.julia.generated.Ca49e1bb9_0@2a968104
     [java]   lifecycle-controller org.objectweb.fractal.julia.generated.C18c4c884_0@68774c94
     [java]   binding-controller org.objectweb.fractal.julia.generated.Ce7005b70_0@13f78a30
     [java]   super-controller org.objectweb.fractal.julia.generated.C7d0bf956_0@8e81dc68
     [java] CONTROLLER OBJECTS:
     [java]   org.objectweb.fractal.julia.generated.Ca3313c69_0@21807c
     [java] CONTENT:
     [java]   org.objectweb.fractal.julia.generated.Ca3313c69_0@21807c

2.7 Class generation options

In all the previous examples, many classes were automatically and transparently generated on the fly (the names of some of these classes appear in the stack traces). It is possible to log all the classes that are generated during execution. For this, in the execute.properties file, add the "-Djulia.loader.gen.log=err" argument to the "run.jvm.parameters" property. With the initial configuration (see section 2.1), the result of ant execute in then the following:
execute:
     [java] (org.objectweb.fractal.julia.asm.MixinClassGenerator ...
     [java] (org.objectweb.fractal.julia.asm.MixinClassGenerator ...
     [java] (org.objectweb.fractal.julia.asm.MixinClassGenerator ...
     [java] ((org.objectweb.fractal.julia.asm.InterfaceClassGenerator ...
     [java] ((org.objectweb.fractal.julia.asm.InterfaceClassGenerator ...
     [java] ((org.objectweb.fractal.julia.asm.InterfaceClassGenerator ...
     [java] ((org.objectweb.fractal.julia.asm.InterfaceClassGenerator ...
...
     [java] Server: print method called
     [java]     at ServerImpl.print(ServerImpl.java:31)
     [java]     at org.objectweb.fractal.julia.generated.Cf359f1f4_0.print(INTERCEPTOR[Service])
     [java]     at org.objectweb.fractal.julia.generated.Ca49e1bb9_0.print(INTERFACE[Service])
     [java]     at ClientImpl.main(ClientImpl.java:31)
     [java]     at org.objectweb.fractal.julia.generated.Cd9152578_0.main(INTERCEPTOR[Main])
     [java]     at org.objectweb.fractal.julia.generated.C84d15fbd_0.main(INTERFACE[Main])
     [java]     at HelloWorld.main(HelloWorld.java:206)
     [java] Server: begin printing...
     [java] -> hello world
     [java] Server: print done.

The first lines describe the classes that are generated on the fly: each line is in fact the class descriptor (see section 1.2) of a class that has just been dynamically generated.

With the "-Djulia.loader.gen.log=err" option the previous trace is sent to the standard error stream. It is also possible to use "out" instead of "err", to sent the trace to the standard output stream. With any other name the trace will be stored an a file of that name. It is also possible to directly store the dynamically generated classes on disk, by using the "-Djulia.loader.gen.dir=directory" option.

The dynamic class generation process heavily relies on the Java Reflection API, which is not available on all Java environments. In these cases Julia can still be used but, in order to do this, all the "dynamically generated" classes must be statically generated and stored on disk (in a directory that is accessible from the class path) before launching an application.

In order to illustrate all the above options, replace "DynamicLoader" with "BasicLoader" in the execute.properties file. The effect of this change is that Julia will use a basic class loader, that loads all classes from the classpath, instead of a class loader that can generate classes on the fly. If you then type ant execute, you should get an exception: this is because the "dynamically generated" classes can neither be generated nor found in the class path.

In order to solve the problem, we must statically generate the previous classes. To do this, first change back "BasicLoader" to "DynamicLoader". Then add the "-Djulia.loader.gen.dir=build" argument to the "run.jvm.parameters" system property, and type ant execute to launch the application. You should get the same trace as above and, in addition, a new org/objectweb/... directory containing the generated classes should have been created in the build directory. If you then type ant execute again, you will see that no class is dynamically generated: instead, the classes previously generated are loaded directly from the class path.

You can now switch to the "BasicLoader": uncomment the (bootstrap 'bootstrap-section2.7) line in the julia-tutorial.cfg file, type ant execute (the effect is to generate and store on disk a new class for the new bootstrap component) and, finally, change "DynamicLoader" with "BasicLoader" in the execute.properties file. If you type ant execute again, this time the application is executed correctly (you can even delete or move to another directory the julia-asm.jar and the julia-mixins.jar files, in the dist/lib directory, the example will still execute normally: this shows that only the julia-runtime.jar is really needed at runtime, when the generated classes are statically generated).

In order to see what kind of classes are dynamically generated, you may reexecute the examples of the previous sections with the "-Djulia.loader.gen.dir=/tmp" option, and by decompiling the generated classes with a decompiler such as Jad. You may also reexecute these examples with the none optimisation level changed to mergeXXX (see section 1.2), in order to see how controller, interceptors and user component classes are merged.

Appendix A Changes

  • July 31, 2002: added a section about mixin classes.
  • September 2, 2002: updated optimization level options and mixin alias definition.
  • November 26, 2002: improved section 1.2, replaced "container" with "primitive".
  • December 20, 2002: updated section 1.1 (new generic bootstrap mechanism).
  • February 10, 2003: updated class names (julia.control package refactored).
  • June 13, 2003: updated stack traces, added section "merged classes".
  • November 12, 2003: updated content to match Fractal Specification v2.0 and Julia v2.0.

Copyright © 1999-2009, OW2 Consortium | contact | webmaster | Last modified at 2012-12-03 09:57 PM