Personal tools

You are reading the articles stored in Tutorial

Mar 08, 2013

Merging odf files using XDocReport and XPages

LET'S MERGE TOGHETER!

Merging odf files using XDocReport and XPages

Filed Under:

Often there is the need to create documents from templates, and the need to fill these templates with data available from other sources: let's take a look at this brief solution

In this scenario, we have a odf template to merge with data.

Working in the Lotus Domino environment, one way to achieve this goal could be a server-side component invoked by an XPagdies, to make the casting process: first, I need something in Java that could do the job for me, and after some search I came across XDocReport.

XDocReport means XML Document reporting

XDocReport provides Java API to merge XML document created with MS Office (docx, pptx) or OpenOffice (odt), LibreOffice (odt) with a Java model to generate report and convert it in another format (PDF, XHTML...).

Basicly, to make the template, main steps are:

  1. create a template document with MS Word (docx) or OpenOffice (odt, ods)
  2. compose the body of the document itself with variables to fill in
  3. use Velocity or Freemarker syntax to set variables to replace.


In this case, I opted to use Velocity inside an ODF file.

Now let's start by explaining how to set up the whole project.

Installing server libraries

External libraries (.jar) that serve the purpose have been installed in the installation directory of the Domino server (jvm/lib/ext path).

These are the files:

commons-collections-3.2.1.jar
commons-lang-2.4.jar
fr.opensagres.xdocreport.converter-1.0.0.jar
fr.opensagres.xdocreport.converter.odt.odfdom-1.0.0.jar
fr.opensagres.xdocreport.core-1.0.0.jar
fr.opensagres.xdocreport.document-1.0.0.jar
fr.opensagres.xdocreport.document.odt-1.0.0.jar
fr.opensagres.xdocreport.itext.extension-1.0.0.jar
fr.opensagres.xdocreport.template-1.0.0.jar
fr.opensagres.xdocreport.template.velocity-1.0.0.jar
itext-2.1.7.jar
odfdom-java-0.8.7.jar
org.odftoolkit.odfdom.converter-0.9.0.jar
org.odftoolkit.odfdom.converter.core-1.0.0.jar
org.odftoolkit.odfdom.converter.pdf-1.0.0.jar
org.odftoolkit.odfdom.converter.xhtml-1.0.0.jar
oro-2.0.8.jar
velocity-1.7.jar

Dont' forget an important security setting in java.policy file:

grant {
permission java.lang.RuntimePermission "getClassLoader";
permission java.lang.RuntimePermission "setContextClassLoader";
}

After that, restart HTTP server.

Server-side tools

To manage the whole process I used an HTML page with a button that calls (via Ajax) an XPages, that deals with the fusion of the data (HTML string) in the template. At the end, I create the PDF file using iText libraries.

Related to XPages, it only call the servlet in the afterPageLoad event:

com.redturtle.XDocReport.mergeAndPDF(
	facesContext.getExternalContext().getRequest(), 
	facesContext.getExternalContext().getResponse()
);

This is how it looks the package, which includes the servlet:

package

Finally, this is the servlet code:

package com.redturtle;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.odftoolkit.odfdom.converter.pdf.PdfConverter;
import org.odftoolkit.odfdom.converter.pdf.PdfOptions;
import org.odftoolkit.odfdom.doc.OdfTextDocument;

import fr.opensagres.xdocreport.core.document.SyntaxKind;
import fr.opensagres.xdocreport.document.IXDocReport;
import fr.opensagres.xdocreport.document.registry.XDocReportRegistry;
import fr.opensagres.xdocreport.template.IContext;
import fr.opensagres.xdocreport.template.TemplateEngineKind;
import fr.opensagres.xdocreport.template.formatter.FieldsMetadata;

import lotus.domino.NotesException;
import lotus.domino.Session;

public class XDocReport {

	private static String VERSION = "XDocReport Version 1.0.0";
	static PrintWriter outClass = null;
	private static Session session = null;

	public static void mergeAndPDF (HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException, InterruptedException, NotesException {

                // NO DIIOP
		session=DominoAccess.getCurrentSession();
		try {			
			// 1) Load ODT file by filling Velocity template engine
			InputStream in = new FileInputStream("/tmp/template.odt");

			IXDocReport report = XDocReportRegistry.getRegistry().loadReport(in,TemplateEngineKind.Velocity);

			FieldsMetadata metadata = report.createFieldsMetadata();
			metadata.addFieldAsTextStyling("comments",SyntaxKind.Html,false);

			// 2) Create context Java model
			IContext context = report.createContext();
			context.put("comments", "<b>hello world</b>");
			
			// 3) Generate report by merging Java model with the ODT
			OutputStream out = new FileOutputStream(new File("/tmp/ODTProjectWithVelocity_Out.odt"));
			report.process(context, out);

			// 1) Load ODT into ODFDOM OdfTextDocument 
			in= new FileInputStream(new File("/tmp/ODTProjectWithVelocity_Out.odt"));
			OdfTextDocument document = OdfTextDocument.loadDocument(in);

			// 2) Prepare Pdf options
			PdfOptions options = PdfOptions.create();
			
			// 3) Convert OdfTextDocument to PDF via IText
			out = new FileOutputStream(new  File("/tmp/ODTProjectWithVelocityList_Out.pdf"));
			PdfConverter.getInstance().convert(document, out, options);
 
                        // Only manage response to Ajax call
		        response.setContentType("text/plain");
		        response.setCharacterEncoding("UTF-8");
			outClass = new PrintWriter(response.getWriter());
			printAgent("OK");
			return;
		} catch (IOException e) {
			e.printStackTrace();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	protected static void printAgent(String string) {
		outClass.println(string);
	}
}

Pay attention to these points:

  1. comments - variable name inside ODF template
  2. metadata.addFieldAsTextStyling("comments",SyntaxKind.Html,false); - fill variable with something in HTML syntax
  3. <b>hello world</b> - HTML string to merge

NOTE: DominoAccess and JSFUtil are two very helpful classes written by Karsten Lehmann: see the full code. Thanks to them, DIIOP process for communication is not required.

Pro & Cons.

I think that it's a very powerful approach; the only limitation I've found is the restricted set of styles supported by the merge process (see there for details). Feel free to make some test using this approach, and let me know what you think :-)

read more

Feb 26, 2013

Creazione di plugin per gestire gruppi virtuali in Plone

Plone e i gruppi virtuali

Creazione di plugin per gestire gruppi virtuali in Plone

Filed Under:

Una funzionalità Plone che sfrutto pochissimo è il meccanismo dei gruppi virtuali, quello che sta dietro al gruppo "Authenticated User". Analizziamolo!

Poche sono state le volte in cui ho avuto bisogno di sfruttare il gruppo che in Plone è chiamato "Authenticated Users". Si tratta di un gruppo virtuale creato in modo tale per cui ogni utente autenticato risulta appartenere, fra gli altri, a questo gruppo in modo automatico.

read more

Feb 25, 2013

How to transform a dexterity Item in to a dexterity Container

Sometimes instructions are missing ;)

How to transform a dexterity Item in to a dexterity Container

Filed Under:

The use case of adding container capabilities to content types is common in the Plone world. I show a nifty solution that applies to dexterity content types


This is a rather technical post, full of code. Faint of hearth you are advised!

The story

Not all the content types are designed from the beginning with a container behaviour, a feature that can become a requirement in consequence of specification changes.

It happened also to me and in my case I had to deal with dexterity based content types. I started googling around and found this unresolved question on the dexterity mailing list.

Starting from the suggestions in the thread, I managed to find out a nifty solution that reveals some interesting aspects of the software we work with.

read more

Feb 12, 2013

Migrazione a Plone 4: alcuni utili tips and tricks

Manuale di sopravvivenza a una migrazione a Plone 4

Migrazione a Plone 4: alcuni utili tips and tricks

Filed Under:

Devi migrare un sito a Plone 4? Hai paura di non riuscirci? Ecco una breve guida che può aiutarti a uscire (quasi) indenne da questa avventura

Con l’uscita di versioni aggiornate di un software (Plone nel nostro caso), ci si ritrova spesso a dover aggiornare le vecchie installazioni per tenerle al passo con le ultime versioni rilasciate e godere delle migliorie apportate e delle nuove funzionalità.

Negli ultimi mesi, il mio lavoro è stato principalmente quello di “aggiornare” dei vecchi siti e migrarli da Plone 3 a Plone 4 (lo so, in ritardo di un paio d'anni).

Esistono sostanzialmente due modalità per migrare un sito Plone:

  • esportazione dei soli contenuti dal vecchio sito (per esempio con strumenti come transmogrifier) e importazione di questi in un nuovo ambiente immacolato.
  • migrazione del portale così com'è mediante il tool interno fornito da Plone stesso.

La migrazione con transmogrifier, di cui abbiamo già parlato precedentemente, in linea di massima è consigliata in quei casi in cui il vecchio portale potrebbe avere diverso “sporco” al suo interno, dovuto a svariati motivi (errori di gioventù dei programmatori, prodotti installati e mai utilizzati o mal rimossi, ecc.), oppure se si decide che parte dei contenuti attuali non servono più e si vuole portare dietro solo alcune sezioni.

Nel nostro caso avevamo degli ambienti abbastanza controllati, dove conoscevamo bene i prodotti installati (in parte sviluppati da noi e in parte trovati su pypi ma utilizzati da tempo) e il livello di sporcizia era minimo, ma soprattutto i portali dovevano essere migrati per intero.

read more

Feb 08, 2013

Come gestire e distribuire i vostri prodotti Plone?

Gestire il proprio codice in... relax!

Come gestire e distribuire i vostri prodotti Plone?

Filed Under:

Un'esplorazione di tutti i (bizzarri) metodi con cui ho visto gestire il codice Plone (ma non solo), alla ricerca di una soluzione per ogni problema

Come gestire e distribuire i vostri prodotti Plone?

Sarà perché nella mia esperienza ho affrontato vari corsi di formazione per sviluppatori Plone, sarà perché non tutto il codice è sempre pronto per essere rilasciato, una cosa è certa: il rapporto tra il neofita e il codice da lui sviluppato è piuttosto combattuto.

Partiamo con una carrellata di quello che potete fare (ma in gran parte non dovete) fino ad arrivare alla soluzione dei casi più delicati.

read more