RAP et les Jobs – Part 1

Le développement d’une application RAP (Rich Ajax Platform) se fait via les mêmes API que celles d’une application RCP (Rich Client Platform). Cependant derrière les signatures des méthodes se cachent des implémentations totalement différentes. Nous allons regarder dans ce billet les pièges à éviter lors de l’utilisation des Jobs dans RAP. D’autres articles sur cette technologie sont disponibles sur le blog.

Un job permet de décrire un bloc de code dont l’exécution peut être programmée dans un thread séparé.

  1. final Job job = new Job(« Mon Job ») {
  2. protected IStatus run(IProgressMonitor monitor) {
  3. // code à exécuter
  4. return Status.OK_STATUS;
  5. }
  6. };
  7. // priorité (par défaut Job.LONG)
  8. job.setPriority(Job.SHORT);
  9. // lancement dès que possible
  10. job.schedule();

Il est possible de lui ajouter des listeners qui seront notifiés lors de différents évènements comme, par exemple, la fin de son exécution. Ici, l’exécution du job est simplement programmé à nouveau.

  1. job.addJobChangeListener(new JobChangeAdapter() {
  2. public void done(IJobChangeEvent event) {
  3. if (event.getResult().isOK()) {
  4. // le job s’est terminé normalement
  5. job.schedule(6000);
  6. } else
  7. // un problème est survenu
  8. }
  9. }
  10. });

En interne RAP gère le cycle de vie des Jobs d’une manière différente de RCP. En effet RAP utilise un singleton de JobManagerAdapter permettant, entre autres, de gérer les aspects propres aux sessions des utilisateurs. Pour cela, chaque job est stocké lors de son lancement dans une liste, variable de cette classe. Le singleton restant en mémoire tout au long du cycle de vie de l’application, il est très important de vérifier que cette référence disparaisse au moment opportun. Or lorsqu’un job est terminé, son retrait de cette liste n’est pas automatique ; il dépend de sa propre implémentation.

  1. public void done( final IJobChangeEvent event ) {
  2. final ProgressManager[] manager = new ProgressManager[ 1 ];
  3. Display display = null;
  4. synchronized( lock ) {
  5. try {
  6. manager[ 0 ] = findProgressManager( event.getJob() );
  7. display = ( Display )jobs.get( event.getJob() );
  8. if( display != null ) {
  9. display.asyncExec( new Runnable() {
  10. public void run() {
  11. Job job = event.getJob();
  12. String id = String.valueOf( job.hashCode() );
  13. UICallBack.deactivate( id );
  14. }
  15. } );
  16. }
  17. } finally {
  18. Job job = event.getJob();
  19. if( !job.shouldSchedule() ) {
  20. jobs.remove( job );
  21. }
  22. }
  23. }
  24. if( display != null ) {
  25. display.asyncExec( new Runnable() {
  26. public void run() {
  27. manager[ 0 ].changeListener.done( event );
  28. }
  29. } );
  30. }
  31. }

Comme vous pouvez le constater, le Job est retiré si et seulement si il n’est plus programmable, c’est à dire si la méthode shouldSchedule() répond faux. Or par défaut, son implémentation retourne systématiquement vrai. Pour un Job à exécution unique, il est alors important de bien penser à redéfinir cette méthode afin d’éviter les fuites mémoires. Par exemple en créant sa propre sous classe de Job redéfinissant les méthodes suivantes :

  1. private boolean shouldSchedule;
  2. @Override
  3. protected final IStatus run(IProgressMonitor monitor)
  4. {
  5. shouldSchedule = false;
  6. return doRun(monitor);
  7. }
  8. /**
  9.   * Do the run action.
  10.   */
  11. protected abstract IStatus doRun(IProgressMonitor monitor);
  12. @Override
  13. public boolean shouldSchedule()
  14. {
  15. return shouldSchedule;
  16. }

Pour un Job re-programmable, il peut également s’avérer très pertinent de mettre en place un système similaire afin d’optimiser la gestion de la mémoire de votre application. Ceci est plus particulièrement vrai pour une application devant supporter un grand nombre d’utilisateurs. Pour cela il suffit de continuer à utiliser la sous classe redéfinit précédemment et de lui ajouter les méthodes suivantes :

  1. public void scheduleAgain()
  2. {
  3. shouldSchedule = true;
  4. schedule();
  5. }
  6. public void scheduleAgain(long delay)
  7. {
  8. shouldSchedule = true;
  9. schedule(delay);
  10. }

Il convient d’appeler ces méthodes scheduleAgain() ou scheduleAgain(long delay) en lieu et place de schedule() et schedule(long delay) sinon le Job ne s’exécutera pas la seconde fois.
Pour terminer, l’équipe RAP a considéré ce comportement comme une anomalie qui sera résolue en version 1.3 prévue pour l’été 2010.

Laisser un commentaire

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.

%d blogueurs aiment cette page :