XPages: Use a PhaseListener for global URL commands

One of my customers wanted an easy way for printing XPages in different formats and with different content, depending of the current XPage opened in the browser. It was a requirement to develope a global solution for every XPage-based application in his company. That is why I created a global Java class which does not require to modify the existing applications at all. But it allows to customize and configure the output for the different needs of the departments and their required reports and print outs.

I decided to use a special PhaseListener to hook into the different applications. This allows the PDF generation depending on some URL parameters, and only runs if the URI contains a special command for printing the current XPage (but works for thw whole application).

The example code is what I have created:

package ch.hasselba.xpages.util;

import java.util.Map;
import javax.faces.context.FacesContext;
import javax.faces.event.PhaseEvent;
import javax.faces.event.PhaseId;
import javax.faces.event.PhaseListener;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class PhaseListenerPDFGenerator implements PhaseListener {

    private static final long serialVersionUID = 1L;
    private static final String GENERATE_PDF = ".PDF";
    private static final String URL_PARAMETER_FILENAME = "filename";
    private static final String URL_PARAMETER_PDFTYPE = "type";
    private static final String HTTP_HEADER_CONTENTTYPE = "application/pdf";

    public void beforePhase(PhaseEvent event) {}

    public PhaseId getPhaseId() {
        return PhaseId.RESTORE_VIEW;
    }

    public void afterPhase(PhaseEvent event) {

        FacesContext facesContext = event.getFacesContext();

        HttpServletRequest req = (HttpServletRequest) facesContext
                .getExternalContext().getRequest();
        String uri = req.getRequestURI();

        if (uri.endsWith(GENERATE_PDF) == true ) {
            servePDF(facesContext);
        }
    }

    private void servePDF(FacesContext facesContext) {
        Map requestMap = facesContext.getExternalContext()
                .getRequestParameterMap();

        String pdfName = getPDFName(requestMap);
        String pdfType = getPDFType(requestMap);

        HttpServletResponse response = (HttpServletResponse) facesContext
                .getExternalContext().getResponse();

        try {

            response.setContentType( HTTP_HEADER_CONTENTTYPE );
            response.setHeader( "Content-Disposition", "attachment; filename="
                      + pdfName );
            response.setStatus(200);
            ServletOutputStream outputStream = response.getOutputStream();

            // Generate the PDF here
            // and send the data to the outputStream
            //
            //outputStream.write( PDFDATA );
            outputStream.flush();
            outputStream.close();
            facesContext.responseComplete();

        } catch (Exception exception) {
            exception.printStackTrace();
        }
    }

    public static String getPDFName(Map requestMap) {
        String pdfName = (String) requestMap.get( URL_PARAMETER_FILENAME );
        return pdfName;
    }
    public static String getPDFType(Map requestMap) {
        String pdfName = (String) requestMap.get( URL_PARAMETER_PDFTYPE );
        return pdfName;
    }

}

The PhaseListener scans the URI every time a request is sent to the server. As soon the URI ends with .PDF, the parameters fileName and type are extracted. The correct PDF template is identified and the requested PDF can be generated (Code for generating is not included in this example).

After generating the PDF, the output is written, and the response is completed. The file download headers are added to the response. The user receives a file download dialog and can open the generated PDF (and print it if required).

When this PhaseListener is enabled in the faces-config.xml, every XPage can use the URL command. For example if your XPage is named „MyXPage.xsp“ the URL to enable the PDF generation instead the generation of the XPage looks like this:

http://example.com/path/to/db.nsf/MyXPage.xsp/.PDF?filename=test.pdf&type=exportAll

This returns a PDF with the filename test.pdf which is generated from the PDF template exportAll, containing the data of the current XPage. It is easy to add a link like this to your application to enable the PDF generation.

This is how the faces-config.xml has to look like:

<?xml version="1.0" encoding="UTF-8"?>
<faces-config>
  <lifecycle>
      <phase-listener>ch.hasselba.xpages.util.PhaseListenerPDFGenerator</phase-listener>
  </lifecycle>
</faces-config>
Dieser Beitrag wurde unter Infrastruktur, Java, JSF, Web, XPages abgelegt und mit , , , , , , , , , verschlagwortet. Setze ein Lesezeichen auf den Permalink.

4 Antworten zu XPages: Use a PhaseListener for global URL commands

  1. Love it. Creative use of Phase listener!

  2. Toby Samples sagt:

    Great idea! I wanted to come up with a way to generate different content, specifically opensocial gadget definitions for any xpage. I could do this very same thing and then make it global to the server so it works across the server.

  3. Andrew Tjecklowsky sagt:

    How do you deploy this phaselistener globally? I have tried to deploy phaselisteners for each database, but you mention that this is a global phaselistener that does not require any changes to existing applications. The faces-config.xml and phaselistener are they deployed as OSGi plugin and then works on all XPages applications on that server?

  4. vivek sagt:

    Hi sven ,
    Kindly could you help me in generating pdf and when i open a document in x page all the content need to be exported as PDF on click of ‚button‘ in that xpage (more or less similar look of the webpage is ok.)

    Also please let me know what you meant by (The correct PDF template is identified and the requested PDF can be generated (Code for generating is not included in this example)) line.

    Thank you for your help in advance.

    regards,
    Viveknath vyas

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.