Advanced Programming

The goal of this section is to introduce advanced features (especially clusturing features and how to program new aspects) of JAC and show how applications can be programmed without UMLAF. Indeed, even if UMLAF is useful, JAC applications (written in pure Java) can be programmed with other IDEs. Moreover, UML is still beta and unstable. If you really use JAC, you'd rather use a stable IDE.

We have chosen very simple examples. More interesting ones can be found in the JAC tarball (src/org/objectweb/jac/samples). You can also see the UMLAF source (src/org/objectweb/jac/ide) for a complex example.

For more general overview on the JAC's programming philosophy, see the JAC Programmer's Guide.

Programming the base application

The base application is the functionnal or core-business application. In other words, it is the simpliest expression of your functionnal needs. Here, we would like to have a class that performs some simple calculi. Wherever you want (in a directory APP_DIR), create a file called Calcul.java. The code is the following:

// Calcul.java file
// A simple component definition that can perform 
// add and sub operations...
public class Calcul {
   protected float value = 0;
   public void add(float toadd) {
      value+=toadd;
   }
   public void sub(float tosub) {
      value-=tosub;
   }
   // IMPORTANT: in JAC, each instance-field better have
   // a getter of the form getFieldName.
   public float getValue() {
      return value;
   }
   // IMPORTANT: in JAC, each instance-field better have 
   // a setter of the form setFieldName.
   public void setValue(float value) {
      this.value=value;
   }

   // Program entry-point
   public static void main( String[] args ) {
      // Actually launch the calcul program by creating an 
      // instance of the Calcul class that waits to be used...
      Calcul myCalcul = new Calcul();
   }
}

Note that the need of the getters and setters comes from the aspects that will use them later-on.

In JAC, any application must have a program descriptor that we put in a *.jac file. This file declares the new application and the supported aspects to the JAC system.

// calcul.jac file
applicationName: calcul
launchingClass: Calcul

The launching class is a regular class that contains a static main method. For simplicity, we put the main() in the Calcul class.

Compile these files like you are used to doing in Java (*.jac and *.acc files do not need to be compiled).

javac Calcul.java

When compiled, run the JAC server and indicate to launch the calcul sample.

cd <jac_dir>

## LINUX ##
java -jar org.objectweb.jac.jar -R . 
     -C <APP_DIR> 
     APP_DIR/calcul.jac

## WINDOWS ##
java -jar org.objectweb.jac.jar -R .
     -C <APP_DIR> 
     APP_DIR\calcul.jac

Since no aspects are configured for the application, All you will see is this:

--- Launching Application calcul ---
JAC system shutdown: notifying all ACs...
Bye bye.

This is not very usefull, but is it prooves that JAC is working on your system.

Configuring the RTTI and GUI aspects

org.objectweb.jac.core.rtti.RttiConf is a core aspect that allows the programmer to define extra type information that will be used by other aspects at runtime.

For instance, it can be very useful for other aspects to be aware that a given method modify the object's state. Since JAC can detect that automatically, we do not need to add specific configurations for our sample application. All you need to do is create an empty file rtti.acc.

The GUI aspect (extends ClassAppearenceGuiConf, FieldAppearenceGuiConf, MethodAppearenceGuiConf, and BehaviorGuiConf) allows the programmer to define some presentation information, and to parameterize the interactions between the application objects and the user. For instance, by configuring a personal GUI aspect, a programmer can define the names of the method parameters as they will be displayed by a GUI.

For our example, create a gui.acc file:

// configuration for the Calcul class
class Calcul {
   // Show a button for each of these methods
   setMethodsOrder {add,sub};
   // Set the names of the parameters of add and sub methods
   setParameterNames add { "Value to add" };
   setParameterNames sub { "Value to sub" };
   // Set a default value for add
   setDefaultValues add { 1 };
}

// Says that all the methods of class Calcul can 
// be called interactively
askForParameters "Calcul";

// The GUI main window configuration
window default {
   registerCustomized;
   setTitle "Calculator";

   // A real simple GUI
   setSubPanesGeometry 1 VERTICAL { false };
   // Display the object named "calcul0" in the 
   // panel "0" of the window.
   setPaneContent 0 Object { "calcul0" };
}

Once you have created your ACC files, you must declare them to the application by modifying the calcul.jac file as following:

// calcul.jac file
applicationName: calcul
launchingClass: Calcul
aspects: \
  rtti rtti.acc true \
  gui gui.acc true

You can then launch the application with the following command:

cd <jac_dir>

## LINUX ##
java -jar org.objectweb.jac.jar -R . 
     -C <APP_DIR> 
     -G default
     APP_DIR/calcul.jac

## WINDOWS ##
java -jar org.objectweb.jac.jar -R .
     -C <APP_DIR> 
     -G default
     APP_DIR\calcul.jac

And you should see a window like this:

The calcul sample main window

As you can see, the calcul instance is being introspected by the GUI aspect of JAC that offers a default view on it. It shows the fields of the calcul0 object (here value, and the methods that can be called on the object (the two buttons add and sub)). The pencil-like button Edit icon on the right of the field means that you can edit the field value by calling the field's setter. Click on it to change the value of the value field. The following box pops-up. Type a new value:

Edit box for value

When you click on OK, you can notice that the view is automatically refreshed. Indeed, thanks to bytecode analysis, JAC knows that setValue is a setter for the value field. Thus the MVC (Model-View-Controller) underlying framework of the GUI aspect refreshes the view.

Let us now try the add button:

Edit box for value

You will first notice that the default value to be added is "1". This is because of the setDefaultValues instruction in the gui.acc. When you click on OK, once again the view of the main window is automatically refreshed because JAC detected that the add method modifies the field value.

All this configuration works also with the WEB. If you launch JAC with the WEB-GUI server:

cd <jac_dir>

## LINUX ##
java -jar org.objectweb.jac.jar -R . 
     -C <APP_DIR> 
     -W default
     APP_DIR/calcul.jac

## WINDOWS ##
java -jar org.objectweb.jac.jar -R .
     -C <APP_DIR> 
     -W default
     APP_DIR\calcul.jac

You will see the following output on the console:

--- Launching Application calcul ---
WARNING: Resource rtti.acc not found
13:34:52.863 EVENT  Starting Jetty/4.1
13:34:53.832 EVENT  Started HttpContext[/jac]
13:34:53.841 EVENT  Started HttpContext[/org/objectweb/jac/resources]
13:34:54.295 EVENT  Started SocketListener on 0.0.0.0:8088
13:34:54.306 EVENT  Started org.mortbay.http.HttpServer@100bac2
WARNING: Web server already started

Then, with you favorite web browser, go to http://localhost:8088/org/objectweb/jac/default:

The calcul's view from a web browser

Configuring other aspects

Other aspects are available and can be configured using the same process that the one depicted for the RTTI and GUI aspects.

Usable aspects aliases are declared in the org.objectweb.jac.prop file. These aliases are used in *.jac application descriptors. By default, available aliases are (click on the link to see the corresponding aspect configuration):

These aspects implementations can be found in the org.objectweb.jac.aspects package (see the JAC API documentation for further details).

Using AOP to program distributed applications

JAC provides full support for distributed AOP (then, it is easy to implement clusturing features by configuring aspects). Basically, the deployment aspect provides a set of deployment rules that the programmer can use to deploy its application over a set of containers.

If we take again the calcul example, you may intend to launch JAC in a distributed mode where a set of clients will access to one unique instance of calcul (here, calcul0) located on a server host.

To allow this, first modify the application descriptor to tell that the application knows a set of two other containers, and activate the deployment aspect.

// calcul.jac file
applicationName: calcul
launchingClass: Run
aspects: \
    rtti rtti.acc true \
    gui gui.acc true \
    deployment deployment.acc true \
    consistency consistency.acc true
topology: //localhost/s1 //localhost/s2

This means that, including the master host (called //localhost/s0), your JAC system will contain three local sites s0, s1, s2. If you want to replicate calcul0 on s1 and s2, just write an ACC file, deployment.acc:

// replicate the calcul0 object from s0 to s1
replicate ".*s0" "calcul0" ".*s[12]";

The deployment aspect only instanciates objects on remote servers. In order to introduce some consistency between those replicas we must configure the consistency aspect in the consistency.acc file:

addStrongPushConsistency "calcul0" "MODIFIERS" ".*[0-2]";

Thus, any call to a modifier method on a site will also be called on the other ones.

Then, start 2 JAC slave servers in distributed mode.

cd <jac_dir>

java -Djava.security.policy=<jac_dir>/org.objectweb.jac.policy -jar org.objectweb.jac.jar -R . -D s1
java -Djava.security.policy=<jac_dir>/org.objectweb.jac.policy -jar org.objectweb.jac.jar -R . -D s2

Then start the application in a JAC master server in a distributed mode.

cd <jac_dir>

## LINUX ##
java -jar org.objectweb.jac.jar -R . 
     -Djava.security.policy=<jac_dir>/org.objectweb.jac.policy
     -C <APP_DIR>
     -G default
     -D 
     APP_DIR/calcul.jac

## WINDOWS ##
java -jar org.objectweb.jac.jar -R .
     -Djava.security.policy=<jac_dir>/org.objectweb.jac.policy
     -C <APP_DIR>
     -G default
     -D
     APP_DIR\calcul.jac

This will show a GUI for the master server. You can also launch a GUI for the slave servers.

cd <jac_dir>

java -jar org.objectweb.jac.jar -R . -G calcul@s1:default
java -jar org.objectweb.jac.jar -R . -G calcul@s2:default

Now you can check that if you call any modifier method (add,sub or setValue) on any of the servers, the change of the value attribute will spread to the other servers.

Note that you can change a configuration file and reload it at runtime for any server. For instance, to reload the consistency aspect (in order to change its configuration at runtime).

cd <jac_dir>

java -jar org.objectweb.jac.jar -R . -a calcul consistency s0

Once you have fully understood how it works, you are ready to play with more advanced features. For instance, you can use the load-balancing aspect (see org.objectweb.jac.distribution.aspects.LoadBalancingConf) to increase the load capability of your applications. For instance you can program a load-balanced calculator only by slightly changing the distribution aspects, and by adding a new ACC (load-balancing.acc):

// deployment.acc file
// replicate calcul0 on s1 and s2
replicate ".*s0" "calcul0" ".*s[12]";
// consistency.acc
addStrongPushConsistency "calcul0" "MODIFIERS" ".*[1-2]";
// load-balancing.acc
//                        object    methods  frontend  backends
addRoundTripLoadBalancer "calcul0"   "ALL"    ".*s0"   ".*[1-2]";

With these three configurations, the calcul instance of s0 is a load-balancer that performs a rountrip load-balancing algorithm to dispatch on s1 and s2.

Programming new aspects

With the JAC software, we furnish a bunch of useful aspects that can be advantagely used to program distributed applications. However, since JAC is a young project and that we cannot think in advance of all the possible uses you can make out of such a software, most of the aspects we provide may lack useful configuration method or may not work fine for specific usages.

Next, we show the code for an aspect that checks that the add or sub method invocations on the calcul0 instance so that it raises an error if the added value is greater than 100 or if the substracted value is greater than 50.

// CheckingAC.java
import org.objectweb.jac.core.*;

public class CheckingAC extends AspectComponent {

  // at instantiation-time, you should define the pointcuts
  public CheckingAC() {

    // this pointcut will make the add method of calcul0 
    // wrapped by an instance of checkingWrapper (an 
    // inner wrapper of this aspect), and more specifically 
    // by the wrapping-method "checkAdd"
    pointcut("calcul0","Calcul","add(float):void",
             CheckingWrapper.class.getName(),"checkAdd",
             null,false);
    // same principles for sub...
    pointcut("calcul0","Calcul","sub(float):void",
             CheckingWrapper.class.getName(),"checkSub",
             null,false);
  }

  // then define the wrappers (if you think that these
  // wrappers can be used by other aspect, you can make 
  // them public within a standalone class-file)
  public class CheckingWrapper extends Wrapper {
    public CheckingWrapper(AspectComponent ac) {
       super(ac);
    }
    // see the programmer's guide for details on the 
    // wrapping methods semantics...
    public Object checkAdd(Interaction interaction) throws Error {
      if (((Integer)interaction.args[0]).intValue()>100) {
        throw new Error("bound excedeed when calling add!");
      }
      return proceed(interaction);
    }
    public Object checkSub(Interaction interaction) throws Error {
      if (((Integer)interaction.args[0]).intValue()>50) {
        throw new Error("bound excedeed when calling sub!");
      }
      return proceed(interaction);
    }
  }
}

Note that this aspect is very specific since it can only be applied to the calcul0 instance. To program generic aspects, you may refer to the JAC programmer's Guide. Configuration methods are a first step towards genericity since they allow the system to dynamically create the pointcuts with the interpretation of the Aspect-Component Configuration (ACC) files (*.acc).

In this case, you can parametrize the creation of the pointcuts instead of hardcoding them in the aspect-component constructor. For instance, the following two files have exactly the same effect than the previous hardcoded aspect-component except that a simple change of the object's name in the configuration file allows the user of this aspect component to make it work on other instances of the Calcul class.

// CheckingAC.java:
public class CheckingAC extends AspectComponent {

  // at configuration-time (just after the instantiation),
  // this configuration method can be called to define the 
  // pointcuts
  public void checkCalcul(String name) {

    // this pointcut will make the add method of the 
    // instance named "name" wrapped
    pointcut(name,"Calcul","add(float):void",
             CheckingWrapper.class.getName(),"checkAdd",
             null, false);
    // same principles for sub...
    pointcut(name,"Calcul","sub(float):void",
             CheckingWrapper.class.getName(),"checkSub",
             null, false);
  }

  // then, same as the hardcoded aspect...
  Class CheckingWrapper extends Wrapper {
   (...)
  }
}
// my-checking.acc:
checkCalcul "calcul0";

NOTE: to be able to use and declare your new aspect component in *.jac file, we recommand that you first declare them in the global org.objectweb.jac.prop file located in $JAC_ROOT. Add the following line in the org.objectweb.jac.acs property of org.objectweb.jac.prop(at the end of the file), and do not forget to add a \ at the end the preceding line!!! If you do not declare aspects in org.objectweb.jac.prop, you can still use the fully qualified name of the aspect component's class (<myPackage>.<MyAspectComponent>)

	checking CheckingAC

You should also specify that the CheckingWrapper must be called after the InputWrapper of the GUI aspect because otherwise, when the method is called from the GUI, the check will occur before the user has entered the value. Just add the following line in org.objectweb.jac.prop, in the org.objectweb.jac.comp.wrappingOrder property, just after the org.objectweb.jac.aspects.gui.InputWrapper line.

	CheckingAC$CheckingWrapper \