samedi 3 octobre 2015

Grails 3 : ajouter le plugin bootstrap


Voici un petit tutoriel pour ajouter le plugin bootstrap à un projet  Grails 3.Il y a quelques différences avec Grails 2.x mais pas tant que cela.
La première chose à faire est de chercher son plugin.Ils sont maintenant localisés sur  Bintray.
J'ai récupéré le plugin Bootstrap sur le lien suivant : https://bintray.com/kensiprell/gradle-plugins/bootstrap-framework/view#read


Ajout des dépendances : build.gradle


Les dépendances sont maintenant gérées dans le fichier build.gradle :

buildscript {
    ext {
         //bootstrapFramework = [
         //    version             : "3.3.5",
         //    cssPath             : "grails-app/assets/stylesheets",
         //    jsPath              : "grails-app/assets/javascripts",
         //    useIndividualJs     : false,
         //    useLess             : false,
         //    invalidVersionFails : false,
         //    fontAwesome : [
         //       install             : false
         //       version             : "4.3.0",
         //       useLess             : false
         //       invalidVersionFails : false
         //    ]
         //]
    }
    repositories {
        jcenter()
    }
    dependencies {
        classpath "com.siprell.plugins:bootstrap-framework:1.0.3"
    }
}


apply plugin: "com.siprell.plugins.bootstrap-framework"


Utilisation dans une page GSP


Ensuite, une fois la configuration du build.gradle effectuée, il suffit de faire une GSP et d'inclure les dépendances jquery, bootstrap dans votre GSP.
Voici un exemple classique de navbar :


<html lang="en" class="no-js">
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <title><g:layoutTitle default="Grails"/></title>
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <asset:javascript src="jquery-2.1.3.js"/>
        <asset:javascript src="bootstrap-all.js"/>
        <asset:stylesheet src="bootstrap-all.css"/>
        <asset:stylesheet src="font-awesome-all.css"/>
        <g:layoutHead/>
    </head>
    <body>
    <nav class="navbar navbar-default">
                <div class="container-fluid">
                  <!-- Brand and toggle get grouped for better mobile display -->
                  <div class="navbar-header">
                    <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
                      <span class="sr-only">Toggle navigation</span>
                      <span class="icon-bar"></span>
                      <span class="icon-bar"></span>
                      <span class="icon-bar"></span>
                    </button>
                    <a class="navbar-brand" href="#">Brand</a>
                  </div>

                  <!-- Collect the nav links, forms, and other content for toggling -->
                  <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
                    <ul class="nav navbar-nav">
                      <li class="active"><a href="#">Link <span class="sr-only">(current)</span></a></li>
                      <li><a href="#">Link</a></li>
                      <li class="dropdown">
                        <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Dropdown <span class="caret"></span></a>
                        <ul class="dropdown-menu">
                          <li><a href="#">Action</a></li>
                          <li><a href="#">Another action</a></li>
                          <li><a href="#">Something else here</a></li>
                          <li role="separator" class="divider"></li>
                          <li><a href="#">Separated link</a></li>
                          <li role="separator" class="divider"></li>
                          <li><a href="#">One more separated link</a></li>
                        </ul>
                      </li>
                    </ul>
                    <form class="navbar-form navbar-left" role="search">
                      <div class="form-group">
                        <input type="text" class="form-control" placeholder="Search">
                      </div>
                      <button type="submit" class="btn btn-default">Submit</button>
                    </form>
                    <ul class="nav navbar-nav navbar-right">
                      <li><a href="#">Link</a></li>
                      <li class="dropdown">
                        <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Dropdown <span class="caret"></span></a>
                        <ul class="dropdown-menu">
                          <li><a href="#">Action</a></li>
                          <li><a href="#">Another action</a></li>
                          <li><a href="#">Something else here</a></li>
                          <li role="separator" class="divider"></li>
                          <li><a href="#">Separated link</a></li>
                        </ul>
                      </li>
                    </ul>
                  </div><!-- /.navbar-collapse -->
                </div><!-- /.container-fluid -->
            </nav>
        <g:layoutBody/>
    </body>

   

Running Gradle task

Pour télécharger et installer le plugin, j'ai exécuté les task Gradle suivante : clean et assemble.
Pour cela, dans Netbeans, il faut faire clic droit sur le projet et sélectionner Task puis clean ou Assemble.Ensuite, il faut redémarrer votre application.


   
   
   
   

Grails 3 and Netbeans 8.0.2 : warning sur la compatibilité avec Gradle 2.3

J'avais un warning qui apparaissait dans Netbeans IDE 8.0.2 à propos de la compatibilité Gradle 2.3.
Pour résoudre ce petit problème, j'ai juste suivi les étapes suivantes.Dans l'onglet files, j'ai fait un click droit sur mon projet.J'ai sélectionné properties et Gradle project dans les Categories.
Puis j'ai changé  la Gradle home à un répertoire Gradle sur mon poste de travail ( Gradle 2.7 ) :






Et le warning a disparu !

mercredi 30 septembre 2015

windows 10

Quelques trucs un peu pénible sur Windows 10 :

  • La barre de tâche plante souvent.Du coup, pour l'utiliser, il faut redémarrer le PC
  • Avant il y avait un petit outil pas mal pour les captures écran.Maintenant, il faut faire ALT + Imp Ecran puis coller dans Gimp ou autre

samedi 26 septembre 2015

Eclipse plugin : pas de menu dans l'onglet Extension


En ce moment, je regarde un peu le développement de plugin Eclipse et j'ai rencontré le soucis suivant : le menu n'apparaissait pas lorsque je faisais clic droit sur une extension.

J'avais aussi le warning suivant dans la vue  Extensions  : No schema found for the “org.eclipse.ui.menus” extension point

Pour résoudre le problème, j'ai ajouté  RCP Target Components ( voir http://stackoverflow.com/questions/8366303/no-schema-found-for-the-org-eclipse-ui-menus-extension-point )

  1. Dans Eclipse,  Help > Install New Software... 
  2. Initialisez l'update site: http://download.eclipse.org/eclipse/updates/4.5
  3. Choisir"Eclipse RCP Target Components" pusi Next our l'installer
Maintenant le menu apparait :




Eclipse IDE for Java Developers
Version: Mars Release (4.5.0)














dimanche 20 septembre 2015

Grails 3 et les IDE


Cela fait quelques temps que je cherche un IDE qui offre le support de Grails 3.
Pour le moment, voici l'état des lieux :
  • Eclipse : aucun support, le plugin n'est plus disponible sous STS.
  • Intellij : apparemment c'est supporté mais il faut payer la licence ...
  • Netbeans : début de support
Le point posistif, c'est que Netebans 8.0.2 reconnait les projets Grails 3.Ainsi, j'ai pu créer et importer un projet Grails 3.Vous pourrez également démarrer votre projet et il y a une coloration syntaxique pour les GSP.il faut avouer cependant que ce n'est pas encore complet mais au moins on peut commencer à se faire un peu la main dessus.

https://stackoverflow.com/questions/29441503/grails-3-0-support-in-netbeans/32425071#32425071

Une dernière chose, sous Eclipse, vous pouvez importer un projet Grails 3 en tant que projet Gradle comme l'indique la documentation mais ce n'est pas terrible.Je n'ai pas réussi à avoir la coloration syntaxique.A suivre donc ...

vendredi 18 septembre 2015

Mise à jour de Grails 2.5.0 vers 2.5.1

J'ai fait cette mise à jour sans problème.Il suffit juste de mettre à jour les plugins qui sont listés dans la ReleaseNote.

Le seul petit détail qui est un peu perturbant, c'est que vous avez un warning : Script 'Upgrade' not found.
Pour résoudre ce problème, vous devez sélectionner 3 (SetGrailsVersion) dans le menu ci-dessous :

|Running pre-compiled script
|Script 'Upgrade' not found, did you mean:
   1) MigrateDocs
   2) IntegrateWith
   3) SetGrailsVersion
   4) InstallDependency
   5) DependencyReport
Please make a selection or enter Q to quit: 3


A noter également, j'ai résolu le problème suivant en upgradant ma version de Grails : http://stackoverflow.com/questions/32562678/grails-plugin-error-class-path-resource-cannot-be-resolved

mercredi 16 septembre 2015

Comment importer des fichiers avec GRAILS ?

Dans les sites métiers, nous avons souvent besoin d'importer des fichiers de configuration.
Il y a plusieurs méthodes pour le faire.Je vais vous en présenter deux : avec un  formulaire ou avec une url.Dans cet article, je n'aborderai pas la question sur les batchs car ,dans mon cas, cela ne fonctionne pas avec la version GRAILS 2.5.



Une IHM pour importer des fichiers


Si vous avez seulement quelques fichiers à importer manuellement, le plus simple est de réaliser un formulaire.

Exemple de formulaire form.gsp


Dans ce formulaire, on appelle l'action init du controlleur admin.La balise input file avec le paramêtre multiple va permettre d'uploader plusieurs fichiers.


<g:uploadForm action="init" controller="admin">
    <form role="form">
        <div class="form-group">
            <label for="files">Choix du fichier à parser</label>
            <input type="file" id="files" name="files[]" multiple>
            <p class="help-block">Vous devez choisir un fichier httpd.conf</p>
        </div>
        <div class="form-group">
            <label for="machinename">Nom de la machine</label>
            <input type="text" class="form-control" id="machinename" name="machinename" placeholder="....ac-limoges.fr" value="">
        </div>
        <button type="submit" class="btn btn-info">Submit</button>
    </form>
</g:uploadForm>


Controller


Le tableau files[] va contenir tous les fichiers à Importer.Attention au type de file, il s'agit de org.springframework.web.multipart.MultiPartFile et non de java.io.File.Donc par exemple, vous pouvez traiter les fichiers de la manière suivante :
      
class AdminController {
  
   def init() {
        if (request instanceof MultipartHttpServletRequest) {
            ...
            request.getFiles("files[]").each { file ->
                log.info("init() file to parse:" + file.originalFilename)
                       InputStream inputStream = file.inpustream
                       BufferedReader = new BufferedReader(new InputStreamReader(inputStream))

                        try {
                            String ldapUser = EMPTY
                            String ldapPwd = EMPTY
                            String ldapHost = EMPTY
                            String ldapPort = EMPTY

                            while ((line = br.readLine()) != null) {
                            ...
                            }
                        }
            }
            ...
        }
    }
...


Import de fichier de manière automatique


Une autre façon de faire est d'utiliser une méthode du controlleur.Cela permet d'importer des fichiers automatiquement :

class AdminController {
    def reloadData() {
        def path = "E:\\projet\\toolprod\\import\\"

        log.info("reloadData() Initializing application from httpd.conf files in machine directory ...")
        new File(path).listFiles().findAll{
            if (it.isDirectory()) {
                log.info("reloadData() Machine name ( Directory name ) :" + it.name)
                String machineName = it.name
                log.debug("reloadData() files list:" + it.listFiles())
                for (File f : it.listFiles()) {
                ...

            }

        }
...



Ensuite, il vous suffit d'accéder à l'url : http://localhost:8080/appli/admin/reloadData
Après cela, il est facile de faire un curl et de le mettre dans une crontab.


lundi 14 septembre 2015

Passage à Windows 10

Hier je suis passé à Windows 10.La mise à jour est passée sans problème.
Mes premières impressions sont bonnes.Je le trouve mieux que Windows 8.1 ( Par exemple, je ne suis plus embêter avec les mouvements de la souris qui ouvre des fenêtres non désirée ).
A noter,  petit truc pénible, il faut faire CTRL + ALT + AROBASE pour faire un @. Mais bon, on ne change pas Windows ;-)
Bon bien sûr cela ne vaut pas une bonne Gentoo mais Windows reste obligatoire dans beaucoup d'entreprise ...
De plus, il faut je pense faire un peu de ménages.Pour cela, voici un lien intéressant : http://korben.info/windows-10-est-il-un-systeme-dexploitation-diabolique.html

vendredi 11 septembre 2015

Podcast en fançais

Sur le forum de HumanCoders, je suis tombé sur une discussion intéressante : https://forum.humancoders.com/t/connaissez-vous-des-podcasts-en-francais/1752

J'ai appris l'existence de podcasts sur le développement que je ne connaissais pas :
Apparemment les podcast ci-dessus sont plutôt orientés développement web.Je vais tester pour voir ...
Et bien entendu, il y a aussi l'incontournable https://lescastcodeurs.com/
  

jeudi 10 septembre 2015

Amazon introduit un nouveau modèle de monétisation pour les Apps Android

Voici une petite news qui interessera les développeurs d'application sous Android.



Avec ce système, c'est le temps passé sur l'application qui est pris en compte !



Plus d'infos sur ce lien :



Amazon introduit un nouveau modèle de monétisation pour les Apps Android

mardi 21 juillet 2015

NFP108 : Specification et modelisation Informatique


Dans le cadre des cours du CNAM, j'ai suivi l'unité NFP108 sur la spécification et modélisation informatique ( CNAM Champagne Ardennes ). Il s'agit essentiellement une unité de mathématiques.Cet article donne un aperçu de cette unité.Si vous voulez avoir une idée plus précise, vous pouvez consulter le devoir à la maison que j'ai réalisé (cf ci-dessous ).


Les différents chapitres

Chaque chapitre fait l'objet d'une ou plusieurs visioconférence ( rythme de 1 par semaine ). La visioconférence est partagée en deux ( 1/2 heure correction des exercices et 1/2 de cours ).

Partie 1


Chapitre01 : Problèmes et langages
Chapitre02 : Automates finis
Chapitre03 : Opérations sur les automates
Chapitre04 : Les expressions régulières
Chapitre05 : Automates et expressions régulières
Chapitre06 : Application des expressions régulières
Chapitre07 : exemple

Partie 2


Chapitre08 : logique des propositions
Chapitre 09 : logique des prédicats
Chapitre10 : démonstrations
Chapitre11 : Le calcul des séquents
Chapitre12 : égalité et théorie des ensembles


Les Examens

Il y a une note pour le devoir à la maison et une note pour l'examen final.

Devoir à la maison



Le devoir à la maison est à rendre une semaine avant l'examen.Il porte sur la partie 1 et compte pour 1/3 de la note si la note est supérieur au devoir.Ce devoir à la maison est accessible et il est possible d'avoir 20.De mon point de vue, avoir une bonne à ce devoir est indispensable pour réussir l'unité.

Voici le devoir que j'ai réalisé :  Devoir_a_la_maison



Examens


L'examen porte sur les deux parties.Il est très long et quasiment impossible à faire en entier ( voir même la première partie ). Il n'y a pas beaucoup d'annales sur cette unité mais je pense que le format reste le même d'année en année.
A noter :
  •  la dernière séance est une vidéo sur un examen corrigé.

Quelques conseils

  • Il y a beaucoup de définition à savoir par chapitre.
  • Il faut s'appliquer sur le devoir à la maison.
  • Il faut éviter de prendre de retard et bien suivre les cours chaque semaine.
  • Le jour du devoir on a le droit au cours.Cela peut aider mais vu que l'examen est très long, il ne faut pas trop compter dessus.

Conclusion

C'est une unité qui peut paraître difficile au premier abord car il s'agit essentiellement d'une unité de mathématique.Cependant, si on suit les cours régulièrement, on comprend bien.Seule une petite partie est plus difficile d'accès mais pas impossible.Le format de visio rend difficile le fait de pouvoir poser des questions à cause des symboles des formules.




samedi 11 juillet 2015

UA5A12 Examen d'admission à l'école d'ingénieur


Cette unité n'est pas vraiment un examen.C'est plus une présentation de votre cursus, votre projet et de vos motivations.Il faut tout d'abord remplir un dossier écrit puis faire une présentation orale.Dans cet article, je vais vous présenter ces différents points.


Remplir un dossier


Pour chaque question, il faut écrire soit 1/2 page soit 1 page excepté pour la dernière question où il faut 5 pages.Au total, mon dossier comptait environ 15 pages. Il ne faut donc pas si prendre à la dernière minute...
Le dossier est à rendre de préférence 10 jours avant la présentation.

Voici quelques exemples de questions :

1.Décrivez votre emploi actuel
2.Décrivez l'évolution de votre fonction durant les années
3.Indiquez vos motivations à devenir ingénieur, votre vision du statut et du métier d'ingénieur
4.Indiquez si vous souhaitez vous orienter plutôt vers des fonctions d'ingénieur dans le domaine : Production, Maintenance,Suivi de projets,Gestion d'affaires,Essais,Marketing,Services,Recherche et développement
5.Pour évoluer à partir de vos fonctions actuelles quels vous semblent être vos points forts et les points à améliorer pour remplir des fonctions d'ingénieur
6.Précisez votre projet de formation
7.Dossier professionnelle


La présentation


Il faut faire une présentation de 10 à 15 mn qui se base sur le dossier écrit.Ensuite les examinateurs vous interroge et vous conseille.Cela dure environ 15 mn. Il vous donne en même temps le résultat mais il n'y a pas vraiment de surprise.


Retour d'expérience


Le dossier était un peu long à remplir.Par contre, l'oral était très enrichissant.Les examinateurs m'ont donné pleins de conseils ( choix d'UV ) et une autre vision des choses.J'ai également pu leur demander des précisions sur le mémoire et sa réalisation.


samedi 4 juillet 2015

TET102 : cours du CNAM sur le management social


Voici un billet qui sort un peu de l'ordinaire.Dans le cadre des cours du CNAM, j'ai suivi le cours TET102 sur le management social en entreprise.L'objectif de cet article est de vous présenter ce cours pour vous aider à faire votre choix et vous donnez quelques conseils pour réussir l'examen.

Résumé

Durant ce cours, vous allez apprendre à connaître les différentes instances sociales ( CHSCT, Comité d'Entreprise ...) et leurs fonctionnements.Vous verrez comment le rôle du manager et comment il interagit avec celles-ci. 

Déroulement du cours
 
Ce cours est composé de 8 chapitres.A la fin de chaque chapitre, les élèves doivent effectuer des exercices par écrit et les rendre au professeur.Le professeur ouvre alors le chapitre suivant.

Pour suivre ce cours, vous devez également assister à 4 cours en présentielle.Pour ma part, c'était le soir de 18h à 21h au Lycée benjamin Franklin d' Orleans. Durant ces séances, vous effectuerez des exercices pratiques en groupe ( gestion de conflits, conduite de réunion ... ) .

Les différents chapitres


Chap I L'entreprise et son organisation
Chap II L'ingénieur et le management humain
Chap III Les conditions du travail humain
Chap IV La fonction "Ressources Humaines"
Chap V Hygiène et sécurité dans le travail
Chap VI Les relations de travail
Chap VII Évaluation des compétences et besoin en formation
Chap VIII Conduite d'équipes et résolution de conflit

A noter :
  • Les 4 derniers chapitres sont les plus importants en terme de contenus ( 300 à 500 pages )
  • Il y a beaucoup de choses à apprendre.

Les points forts

  • Ce cours présente les différentes instances sociales, leur rôle.Cela donne une bonne vision du fonctionnement social de l'entreprise.J'aurais aimé avoir ce cours avant de commencer en entreprise.
  • Les ateliers lors des point de regroupement permettent de prendre conscience du rôle de manager et apportent des conseils utiles pour son application en entreprise.

L'examen

Voici quelques remarques : 
  • Ne négligez pas le dernier chapitre.
  • Des notes manuscrites étaient autorisées.
  • Vers la fin de la session, le professeur ouvre les annales.

 

En résumé, ce cours exige pas mal de travail. Il apporte des connaissances essentielles sur le fonctionnement des instances sociales en entreprises.Les regroupements en présentielles sont intéressant et vivant ( c'est important le soir après le travail ! ) .

 

vendredi 24 avril 2015

Grails et la création de pdf

Je réalise actuellement une application métier et dans ce cadre, j'ai eu besoin d'afficher des rapports au format pdf. Avant la version de Grails 2.5.0, j'utilisais le plugin export et il fonctionnait très bien.Par contre, avec la version Grails 2.5.0, j'ai eu des erreurs de compilation.J'ai aussi essayé le plugin rendering mais sans succès ( cf http://stackoverflow.com/questions/29694796/null-pointer-exception-with-grails-rendering-plugin ).
Par conséquent, j'ai décidé de le faire moi même avec une librairie :

org.apache.pdfbox

Dans le fichier BuildConfig.groovy, j'ai ajouté la dépendance :

   dependency {  
     ...  
     compile "org.apache.pdfbox:pdfbox:1.8.9"  
     ...  
   }  

Voici le code dans mon controlleur :

 class AppRetailController {  
   ...  
   def renderFormPDF(){  
     List<App> apps = new ArrayList<>()  
     String title = ""  
     String param = params.get("serverSelect")  
     ...  
     Fill the list apps  
     ...  
           title= "Liste de toutes les applications sur " + param  
           title += " (" + apps.size() + ")"  
           // Create all needed for Pdf document  
     PDDocument document = new PDDocument();  
     PDPage page = new PDPage();  
     PDPageContentStream contentStream;  
           // Here I want 30 rows by page  
     int pageNumber = apps.size()/30 + 1  
     log.info("Page number :" + pageNumber)  
     int countApp = 0  
           // for each page I draw table with datas  
     for (int i=1; i<=pageNumber; i++) {  
       log.info("countApp :" + countApp)  
       page = new PDPage();  
       contentStream = new PDPageContentStream(document, page);  
       int max = countApp + 30  
       if (max > apps.size()) {  
         max = apps.size() - 1  
       }  
       drawTable(page, contentStream, 700, 100, apps[countApp..max], title);  
       countApp = countApp + 30 + 1  
       contentStream.close();  
       document.addPage(page);  
     }  
     document.save("report.pdf");  
     document.close();  
     render( file:new File("report.pdf"), fileName: "report.pdf")  
   }  
   /**  
    * @param page  
    * @param contentStream  
    * @param y the y-coordinate of the first row  
    * @param margin the padding on left and right of table  
    * @param content a 2d array containing the table data  
    * @throws IOException  
    */  
   def drawTable(PDPage page, PDPageContentStream contentStream,  
                  float y, float margin,  
                  List<App> apps, String title) throws IOException {  
     final int rows = apps.size() + 1;  
     final int cols = 3;  
     final float rowHeight = 20f;  
     final float tableWidth = page.findMediaBox().getWidth()-(2*margin);  
     final float tableHeight = rowHeight * rows;  
     final float colWidth = tableWidth/(float)cols;  
     final float cellMargin=5f;  
     //draw the rows  
     float nexty = y ;  
     for (int i = 0; i <= rows; i++) {  
       contentStream.drawLine(margin,nexty,(float)(margin+tableWidth),nexty);  
       nexty-= rowHeight;  
     }  
     //draw the columns  
     float nextx = margin;  
     for (int i = 0; i <= cols; i++) {  
       contentStream.drawLine(nextx,y,nextx,(float)(y-tableHeight));  
       nextx += colWidth;  
     }  
     //now add the text  
     contentStream.setFont(PDType1Font.HELVETICA_BOLD,14);  
     contentStream.beginText();  
     contentStream.moveTextPositionByAmount((float)margin+cellMargin+10,(float)(y+20));  
     contentStream.drawString(title);  
     contentStream.endText();  
     contentStream.setFont(PDType1Font.HELVETICA_BOLD,12);  
     float textx = margin+cellMargin;  
     float texty = y-15;  
     //Define colunm title  
     contentStream.beginText();  
     contentStream.moveTextPositionByAmount(textx,texty);  
     contentStream.drawString("Nom");  
     contentStream.endText();  
     textx += colWidth;  
     contentStream.beginText();  
     contentStream.moveTextPositionByAmount(textx,texty);  
     contentStream.drawString("Description");  
     contentStream.endText();  
     textx += colWidth;  
     contentStream.beginText();  
     contentStream.moveTextPositionByAmount(textx,texty);  
     contentStream.drawString("Chemin dans ARENA");  
     contentStream.endText();  
     textx += colWidth;  
     texty-=rowHeight;  
     textx = margin+cellMargin;  
     contentStream.setFont(PDType1Font.HELVETICA,11);  
     apps.each {  
       contentStream.beginText();  
       contentStream.moveTextPositionByAmount(textx,texty);  
       contentStream.drawString(it.name);  
       contentStream.endText();  
       textx += colWidth;  
       contentStream.beginText();  
       contentStream.moveTextPositionByAmount(textx,texty);  
       String desc = it.description  
       if (desc.equals("EMPTY")) {  
         desc = ""  
       }  
       contentStream.drawString(desc);  
       contentStream.endText();  
       textx += colWidth;  
       contentStream.beginText();  
       contentStream.moveTextPositionByAmount(textx,texty);  
       String path = it.arenaPath  
       if (path == null) {  
         path = ""  
       }  
       contentStream.drawString(path);  
       contentStream.endText();  
       textx += colWidth;  
       texty-=rowHeight;  
       textx = margin+cellMargin;  
     }  
   }  
 }  


En conclusion, on peut dire que ce n'est pas la meilleur solution car il faut tout faire à la main et à mon avis il vaut mieux regarder des solutions telles que le plugin rendering.Par contre, ça fait le job et lorsque vous êtes pressé par le temps, cela fonctionne.
Un grand merci à ce blog pour l'utilisation de la librairie : http://fahdshariff.blogspot.fr/2010/10/creating-tables-with-pdfbox.html 

Hope this help,

Voir aussi : http://grails.github.io/grails-doc/2.5.x/ref/Controllers/render.html

mardi 31 mars 2015

Upgrade de Grails 2.4.4 vers la version 2.5.0


Voici un petit retour d'expérience pour ceux qui souhaiteraient mettre à jour leur version de Grails.
Cette mise à jour ne m'a posé aucun problème.Il suffit de bien suivre la Release Version ( https://github.com/grails/grails-core/releases/tag/v2.5.0 )

Pour résumé, j'ai seulement mis à jour les plugins suivants dans le fichier BuildConfig.groovy :
  • build ':tomcat:7.0.55.2'
  • compile ':cache:1.1.8'
  • compile ':scaffolding:2.1.2'
  • compile ':asset-pipeline:2.1.5'

J'ai eu une exception au démarrage de Grails car j'avais oublié de changer la valeur de region.factory_class dans le fichier Datasource.groovy ( cf Release Version ).
Voici l'exception que j'ai eu :

2015-03-31 16:28:39,590 [localhost-startStop-1] ERROR context.GrailsContextLoaderListener  - Error initializing the application: Error creating bean with name 'transactionManagerPostProcessor': Initialization of bean failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'transactionManager': Cannot resolve reference to bean 'transactionManager_lookup' while setting constructor argument with key [1]; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'transactionManager_lookup': Cannot resolve reference to bean 'sessionFactory_lookup' while setting bean property 'sessionFactory'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sessionFactory_lookup': Invocation of init method failed; nested exception is org.hibernate.cache.CacheException: net.sf.ehcache.CacheException: Another unnamed CacheManager already exists in the same VM. Please provide unique names for each CacheManager in the config or do one of following:
1. Use one of the CacheManager.create() static factory methods to reuse same CacheManager with same name or create one if necessary
2. Shutdown the earlier cacheManager before creating new one with same name.
The source of the existing CacheManager is: DefaultConfigurationSource [ ehcache.xml or ehcache-failsafe.xml ]
...
Et la solution pour résoudre ce problème :
hibernate {
    ...
    cache.region.factory_class = 'org.hibernate.cache.SingletonEhCacheRegionFactory'
}

mardi 13 janvier 2015

Grails Mise à jour de Grails 2.3.11 vers Grails 2.4.4

J'ai réussi à mettre à jour à l'aide de https://grails.org/2.4.4+Release+Notes et http://grails.org/doc/latest/guide/upgradingFrom23.html . Ce n'est pas une mise à jour trivial et j'ai eu des exceptions au démarrage de mon appli web ainsi que pas mal de modification à faire pour que cela fonctionne à nouveau. (site assez important). Je vous recommande de bien suivre le lien de mise à jour
Voici quelques pistes pour vous aider :

Montée de version des plugins

Pour que cela fonctionne, j'ai du faire un upgrade des plugins suivants : cache, hibernate, jquery.
Si vous ne le faites pas, vous aurez des erreurs ...

Plugin asset-pipeline remplace le  plugin ressource

Cela implique de changer les répertoires de place et de les réorganiser dans le répertoire assets/.
Cela implique également la modification des includes dans vos pages GSP et aussi quelques surprises ( voir http://stackoverflow.com/questions/27906139/grails-assets-directory-management )

Plugin export:1.6

Ce plugin ne fonctionne plus.

Templates

J'ai effacé le répertoire templates puis relancer la commande grails install templates


Autre


Il faut noter l'ajout d'annotation @Validateable(nullable = true).
Cela implique la modification de quelques beans.