After a break and a new try I could reach the complete goal, to create a pdf document with multiple pages in vaadin. As I promised I will give a complete summary of how to do that.
In my szeanrio I need to create a dynamic pdf document which contains one ore more authetification datas for users. That means if there is only one user a pdf document with one page will be created, if there are more users one pdf document with multiple pages will be created. As paramter I give a list which contains all users each user represented by a user object. Now let us start:
- We write a class which will create the pdf document in future.
@SuppressWarnings("serial")
public class PDFStreamSource implements StreamResource.StreamSource {
private static Logger log = Logger.getLogger(PDFStreamSource.class);
private List<ADUser> users;
public PDFStreamSource(List<ADUser> users){
this.users = users;
}
public PDFStreamSource(ADUser user){
this.users = new ArrayList<ADUser>();
this.users.add(user);
}
@Override
public InputStream getStream() {
try {
log.debug("Called getStream() method");
PipedInputStream in = new PipedInputStream();
final PipedOutputStream out = new PipedOutputStream(in);
new Thread(new Runnable() {
@Override
public void run() {
try {
writePdf(out);
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
}).start();
return in;
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
protected void writePdf(PipedOutputStream out) {
PdfReader reader;
ByteArrayOutputStream baos;
PdfStamper stamper;
Document document = new Document();
try {
PdfCopy copy = new PdfCopy(document, out);
document.open();
for (int i = 0; i < users.size(); i++) {
InputStream templateStream = getClass().getClassLoader().getResourceAsStream("ntavorlage.pdf");
reader = new PdfReader(templateStream);
baos = new ByteArrayOutputStream();
// set fields
stamper = new PdfStamper(reader, baos);
stamper.getAcroFields().setField("name", this.users.get(i).getName());
stamper.getAcroFields().setField("username", this.users.get(i).getUsername());
stamper.getAcroFields().setField("password", this.users.get(i).getPassword());
stamper.getAcroFields().setField("email", this.users.get(i).getEmail());
stamper.getAcroFields().setField("comment", "Benutzerdaten gilten für alle Dienste die die Benutzervalidierung verwenden");
stamper.close();
stamper.setFormFlattening(true);
stamper.close();
// add page
reader = new PdfReader(baos.toByteArray());
copy.addPage(copy.getImportedPage(reader, 1));
log.debug("Page "+i+" of "+users.size()+" created");
}
}
catch (DocumentException de) {
System.err.println(de.getMessage());
}
catch (IOException ioe) {
System.err.println(ioe.getMessage());
}
document.close();
}
}
I this class I use a template for the layout of the pdf document. This layout must be stored in the src folder of the project hierachy. this.users.get(i).getUsername() is one element of the list.
- We need a method which will create an object of this class and which we can call if we want to create a document. As far as I understood this method can be everywhere. I inserted the method in the main class of my application.
// A method to open a pdf document
public void openPdf(StreamSource streamSource, final String filename) {
StreamResource streamResource = new StreamResource(streamSource, filename + ".pdf", this); //$NON-NLS-1$
streamResource.setCacheTime(5000); // no cache (<=0) does not work with IE8
streamResource.setMIMEType("application/pdf"); //$NON-NLS-1$
this.getMainWindow().open(streamResource, "_blank"); //$NON-NLS-1$
}
- Last step is to call this method from somewhere in the application, e.g. in a click handler of a button
Button confirmButton = new Button("Confirm");
confirmButton.setWidth("200px");
confirmButton.addListener(new ClickListener() {
private static final long serialVersionUID = 1641713157343451455L;
@Override
public void buttonClick(ClickEvent event) {
//modalWindow.getParent().open(new ExternalResource("../../../pdf/"), "_blank");
PasswordGenerator generator = new PasswordGenerator();
user.setPassword(generator.returnPassword());
// Creating the pdf servlet
final PDFStreamSource streamSource = new PDFStreamSource(user);
String now = new SimpleDateFormat("yyyy-MM-dd_HHmmss").format(new Date());
AdmanagerApplication app = (AdmanagerApplication)modalWindow.getApplication();;
app.openPdf(streamSource, "pdf_" + now);
ADPasswordReset reset = new ADPasswordReset(user);
if(reset.resetPassword() == true){
modalWindow.getParent().removeComponent(modalWindow);
}
else {
error.setValue("Password reset was not successfull");
}
}});
You can probably add the last two methods into a seperated class, this would enhance the usability.
Now everything is done and you can try it.