Export massif de rapports avec BIRT đź”—

Posted by MĂ©dĂ©ric Ribreux 🗓 In projects/birt/

#cat #dev #java #reporting #tomcat

Production massive de rapports

Introduction

BIRT nous a permit d'élaborer nos modèles de rapports avec la mise en page qui nous convient. Nous sommes à même de produire un rapport sur une commune donnée. Néanmoins, il reste à générer des rapports pour toutes les communes du département. Il est clair qu'on ne va pas le faire à la main car ça signifie faire au moins 360 clics pour le département de Maine-et-Loire.

Il faut donc trouver un moyen d'automatiser le processus.

Une solution consiste à utiliser le viewer BIRT qui est disponible dans le fichier de runtime de BIRT. Il s'agit d'une application J2EE qui génère un rapport en fonction des paramètres d'entrées et du fichier de modèle de rapport. L'intérêt de ce viewer est qu'on peut l'interroger par un script.

Une autre solution consiste à développer un script qui utilise le moteur de rapport de BIRT. En effet, ce dernier permet à toute application Java de produire des rapports. C'est une solution tout à fait envisageable et qui serait d'ailleurs préférrable: les personnes qui utilisent BIRT utilisent également Eclipse qui est prévu pour faire du développement JAVA. De plus, avec le script sous la main, les personnes peuvent gérer elles-même leurs productions...

Méthode avec développement

La démarche

BIRT dispose d'un moteur de rapport (BIRT Report Engine). il est possible d'utiliser ce moteur de rapport directement dans une application JAVA. Nos besoins sont ultrasimples:

D'un point de vue algorithme, on a vu plus complexe. Nous allons donc développer un script en Java qui utilise le moteur de rapport de BIRT. Ca tombe finalement assez bien car BIRT est basé sur Eclipse qui est une plateforme de développement initialement créée pour coder en Java !!!

Pré-requis: installation du runtime

Vous devez d'abord télécharger le paquet du runtime BIRT sur la page de téléchargement de BIRT. Ce fichier est une archive compressée de près de 100Mo. Ca peut paraître surprenant car nous disposons déjà de ce moteur dans Eclipse lors de l'installation de BIRT. Néanmoins, notre script va s'appuyer sur ce moteur et vous devez, non seulement, disposer des bonnes bibliothèques (JAR) mais aussi d'indiquer, dans la configuration du moteur de rapport, où sont situées ces bibliothèques.

Vous devez donc télécharger et décompresser cette archive dans un répertoire donné. Pour la suite, ce répertoire sera /opt/BIRT_RE/. La démarche est la même sous MS-Windows mais le nom du répertoire sera différent.

La décompression extrait l'arborescence suivante:

birt-runtime-3_7_2
|
\-------------------ReportEngine
|           |
|           \-----lib
|           \-----samples
|
|
\-------------------WebViewerExample

Globalement, ce qui nous intéresse est dans le répertoire ReportEngine. Nous verrons qu'il sera utilisé dans le source du script de génération massive.

Source du script

Voici le code source d'un script qui est à minima paramétrable. Attention, ça juste marche dans Eclipse et je ne suis pas un développeur Java très expérimenté. En plus, j'avais moins d'une demi-journée à consacrer à ce travail donc c'est du code pas très propre (pas très bien organisé) mais ça correspond à mes besoins simples et c'est facilement récupérable, même pour un non développeur Java (typiquement un simple utilisateur de BIRT).

L'idée principale est de disposer d'une fonction paramétrable qui permet de produire des rapports:

// Script pour générer autant de documents que de valeurs de paramètre différent
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.logging.Level;
import org.eclipse.birt.core.framework.Platform;
import org.eclipse.birt.report.engine.api.EngineConfig;
import org.eclipse.birt.report.engine.api.EngineException;
import org.eclipse.birt.report.engine.api.IGetParameterDefinitionTask;
import org.eclipse.birt.report.engine.api.IParameterDefnBase;
import org.eclipse.birt.report.engine.api.IParameterGroupDefn;
import org.eclipse.birt.report.engine.api.IParameterSelectionChoice;
import org.eclipse.birt.report.engine.api.IRenderOption;
import org.eclipse.birt.report.engine.api.IReportEngine;
import org.eclipse.birt.report.engine.api.IReportEngineFactory;
import org.eclipse.birt.report.engine.api.IReportRunnable;
import org.eclipse.birt.report.engine.api.IRunAndRenderTask;
import org.eclipse.birt.report.engine.api.RenderOption;
import org.eclipse.birt.report.engine.api.IScalarParameterDefn;
import org.eclipse.birt.report.model.api.CascadingParameterGroupHandle;
import org.eclipse.birt.report.model.api.ScalarParameterHandle;

public class MassiveBirt {

  @SuppressWarnings("unchecked")
  public void runReport(String path, String filename, String format, String parameter) throws EngineException {
    IReportEngine engine=null;
    EngineConfig config = null;
    IRunAndRenderTask task=null;
    HashMap parmValues = new HashMap();

   try {
     config = new EngineConfig( );
     config.setBIRTHome("/opt/BIRT_RE/birt-runtime-3_7_2/");
     config.setLogConfig(null, Level.OFF);
     Platform.startup( config );
     IReportEngineFactory factory = (IReportEngineFactory) Platform.createFactoryObject( IReportEngineFactory.EXTENSION_REPORT_ENGINE_FACTORY );
     engine = factory.createReportEngine( config );
   } catch( Exception ex){
     ex.printStackTrace();
   }

   IReportRunnable design = null;

   // Ouverture du rapport
   design = engine.openReportDesign("/opt/BIRT_RE/birt-runtime-3_7_2/ReportEngine/rapports/test_RE.rptdesign"); 

   // Récupération de la liste des paramètres
   // Attention, si vos paramètres sont sous forme de groupes, ça ne fonctionnera pas forcément
   IGetParameterDefinitionTask param_task = engine.createGetParameterDefinitionTask( design );
   Collection params = param_task.getParameterDefns( true );
   Iterator iter = params.iterator( );

   while ( iter.hasNext( ) )
   {
     IParameterDefnBase param = (IParameterDefnBase) iter.next( );
     IScalarParameterDefn scalar = (IScalarParameterDefn) param;

     //Si c'est le paramètre qu'on cherche
     if(param.getName().equals(parameter)) {
       // Si le paramètre est une liste déroulante
       if(scalar.getControlType() ==  IScalarParameterDefn.LIST_BOX) {
         Collection selectionList = param_task.getSelectionList( param.getName() );
         //On remplit un HashMap avec les valeurs et les identifiants
         if ( selectionList != null ) {
           for ( Iterator sliter = selectionList.iterator( ); sliter.hasNext( ); ) {
             IParameterSelectionChoice selectionItem = (IParameterSelectionChoice) sliter.next( );
             String value = (String)selectionItem.getValue( );
             String label = selectionItem.getLabel( );
             parmValues.put(value, label);
           } 
         }
       }
     }
   }

   param_task.close();

   // Préparation de la génération du rapport
   IRenderOption options = new RenderOption();
   options.setOutputFormat(format);

   // Boucle de génération
   for (Iterator it = parmValues.keySet().iterator(); it.hasNext();) {
     task = engine.createRunAndRenderTask(design);
     Object key = it.next();
     Object value = parmValues.get(key);
     String fullname=path+filename+key+"-"+value+"."+format;
     System.out.println("Generating "+fullname+" ...");
     options.setOutputFileName(fullname);
     task.setParameterValue(parameter, key);
     task.validateParameters();

     // Lancement de la génération
     task.setRenderOption(options);
     task.run();
     task.close();
  }


  // On ferme tout proprement
  engine.destroy();
  Platform.shutdown();
  System.out.println("Finished in "+path);
  System.exit(0);
}

public static void main(String[] args) {
  try {
    MassiveBirt ex = new MassiveBirt( );
    ex.runReport("/opt/BIRT_RE/birt-runtime-3_7_2/ReportEngine/", "Fiche_Agricole_",
                 "odt","Commune");
  }
  catch ( Exception e ) {
    e.printStackTrace();
  }
}
}

Installer le script

Nous avons donc un fichier source Java (le script ci-dessus) ainsi que le runtime BIRT déployé dans un répertoire (/opt/BIRT_RE/...). Nous devons créer un projet Java dans Eclipse et le compiler.

D'abord, assurez-vous de disposer d'une perspective Java:

perspective Java

Ensuite, créer un nouveau projet:

Création d'un projet JAVA dans Eclipse

Ensuite, il faut ajouter les bibliothèques du ReportEngine:

Ajout bibliothèque ReportEngine

Puis, vous devez créer une nouvelle classe nommée MassiveBirt (vous pouvez la laisser dans le package par défaut) et y copier le code ci-dessus:

Nouvelle classe

Enfin, vous devrez adapter la fin du script avec les paramètres indiqués pour que ça fonctionne chez vous !

Génération des rapports

Attention, la génération de rapports est un processus gourmand en mémoire (en fait c'est le cas avec JAVA en général). Avec 2Go de RAM sur une machine et un rapport de seulement une page, la génération de mes 300 rapports déclenche l'utilisation du swap.

Au delà de cet aspect, si vous avez intégré les bons arguments d'appel du script, vous devriez retrouver tous vos rapports dans le répertoire indiqué.

Références

Voici les références en ligne que j'ai utilisé pour découvrir l'API de BIRT: