{"id":1243,"date":"2013-07-11T22:55:09","date_gmt":"2013-07-11T20:55:09","guid":{"rendered":"http:\/\/hasselba.ch\/blog\/?p=1243"},"modified":"2013-07-11T22:55:09","modified_gmt":"2013-07-11T20:55:09","slug":"xpages-use-a-phaselistener-for-global-url-commands","status":"publish","type":"post","link":"https:\/\/hasselba.ch\/blog\/?p=1243","title":{"rendered":"XPages: Use a PhaseListener for global URL commands"},"content":{"rendered":"<p>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.<\/p>\n<p>I decided to use a special <em>PhaseListener<\/em> 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).<\/p>\n<p>The example code is what I have created:<\/p>\n<pre><code>package ch.hasselba.xpages.util;\r\n\r\nimport java.util.Map;\r\nimport javax.faces.context.FacesContext;\r\nimport javax.faces.event.PhaseEvent;\r\nimport javax.faces.event.PhaseId;\r\nimport javax.faces.event.PhaseListener;\r\nimport javax.servlet.ServletOutputStream;\r\nimport javax.servlet.http.HttpServletRequest;\r\nimport javax.servlet.http.HttpServletResponse;\r\n\r\npublic class PhaseListenerPDFGenerator implements PhaseListener {\r\n\r\n\u00a0\u00a0 \u00a0private static final long serialVersionUID = 1L;\r\n\u00a0\u00a0 \u00a0private static final String GENERATE_PDF = \".PDF\";\r\n\u00a0\u00a0 \u00a0private static final String URL_PARAMETER_FILENAME = \"filename\";\r\n\u00a0\u00a0 \u00a0private static final String URL_PARAMETER_PDFTYPE = \"type\";\r\n\u00a0\u00a0 \u00a0private static final String HTTP_HEADER_CONTENTTYPE = \"application\/pdf\";\r\n\r\n\u00a0\u00a0 \u00a0public void beforePhase(PhaseEvent event) {}\r\n\r\n\u00a0\u00a0 \u00a0public PhaseId getPhaseId() {\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0return PhaseId.RESTORE_VIEW;\r\n\u00a0\u00a0 \u00a0}\r\n\r\n\u00a0\u00a0 \u00a0public void afterPhase(PhaseEvent event) {\r\n\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0FacesContext facesContext = event.getFacesContext();\r\n\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0HttpServletRequest req = (HttpServletRequest) facesContext\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0.getExternalContext().getRequest();\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0String uri = req.getRequestURI();\r\n\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0if (uri.endsWith(GENERATE_PDF) == true ) {\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0servePDF(facesContext);\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0}\r\n\u00a0\u00a0 \u00a0}\r\n\r\n\u00a0\u00a0 \u00a0private void servePDF(FacesContext facesContext) {\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0Map requestMap = facesContext.getExternalContext()\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0.getRequestParameterMap();\r\n\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0String pdfName = getPDFName(requestMap);\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0String pdfType = getPDFType(requestMap);\r\n\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0HttpServletResponse response = (HttpServletResponse) facesContext\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0.getExternalContext().getResponse();\r\n\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0try {\r\n\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0response.setContentType( HTTP_HEADER_CONTENTTYPE );\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0response.setHeader( \"Content-Disposition\", \"attachment; filename=\"\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0 + pdfName );\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0response.setStatus(200);\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0ServletOutputStream outputStream = response.getOutputStream();\r\n\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\/\/ Generate the PDF here\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\/\/ and send the data to the outputStream\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\/\/\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\/\/outputStream.write( PDFDATA );\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0outputStream.flush();\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0outputStream.close();\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0facesContext.responseComplete();\r\n\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0} catch (Exception exception) {\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0exception.printStackTrace();\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0}\r\n\u00a0\u00a0 \u00a0}\r\n\r\n\u00a0\u00a0 \u00a0public static String getPDFName(Map requestMap) {\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0String pdfName = (String) requestMap.get( URL_PARAMETER_FILENAME );\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0return pdfName;\r\n\u00a0\u00a0 \u00a0}\r\n\u00a0\u00a0 \u00a0public static String getPDFType(Map requestMap) {\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0String pdfName = (String) requestMap.get( URL_PARAMETER_PDFTYPE );\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0return pdfName;\r\n\u00a0\u00a0 \u00a0}\r\n\r\n}\r\n<\/code><\/pre>\n<p>The <em>PhaseListener<\/em> scans the URI every time a request is sent to the server. As soon the URI ends with <em>.PDF<\/em>, the parameters <em>fileNam<\/em>e and <em>type<\/em> are extracted. The correct PDF template is identified and the requested PDF can be generated (Code for generating is not included in this example).<\/p>\n<p>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).<\/p>\n<p>When this <em>PhaseListener<\/em> is enabled in the <em>faces-config.xml<\/em>, every XPage can use the URL command. For example if your XPage is named &#8222;MyXPage.xsp&#8220; the URL to enable the PDF generation instead the generation of the XPage looks like this:<\/p>\n<pre>http:\/\/example.com\/path\/to\/db.nsf\/MyXPage.xsp\/.PDF?filename=test.pdf&amp;type=exportAll<\/pre>\n<p>This returns a PDF with the filename <em>test.pdf<\/em> which is generated from the PDF template <em>exportAll,<\/em> containing the data of the current XPage. It is easy to add a link like this to your application to enable the PDF generation.<\/p>\n<p>This is how the <em>faces-config.xml<\/em> has to look like:<\/p>\n<pre>&lt;?xml version=\"1.0\" encoding=\"UTF-8\"?&gt;\r\n&lt;faces-config&gt;\r\n\u00a0 &lt;lifecycle&gt;\r\n\u00a0 \u00a0\u00a0 \u00a0&lt;phase-listener&gt;ch.hasselba.xpages.util.PhaseListenerPDFGenerator&lt;\/phase-listener&gt;\r\n\u00a0 &lt;\/lifecycle&gt;\r\n&lt;\/faces-config&gt;<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>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 &hellip; <a href=\"https:\/\/hasselba.ch\/blog\/?p=1243\">Weiterlesen <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[18,89,26,81,74],"tags":[34,33,47,7,11,31,86,32,12,3],"class_list":["post-1243","post","type-post","status-publish","format-standard","hentry","category-infrastruktur","category-java","category-jsf","category-web","category-xpages","tag-8-5-2","tag-8-5-3","tag-9-0","tag-domino","tag-http","tag-java","tag-jsf","tag-tipp","tag-web","tag-xpages"],"_links":{"self":[{"href":"https:\/\/hasselba.ch\/blog\/index.php?rest_route=\/wp\/v2\/posts\/1243","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/hasselba.ch\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/hasselba.ch\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/hasselba.ch\/blog\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/hasselba.ch\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1243"}],"version-history":[{"count":6,"href":"https:\/\/hasselba.ch\/blog\/index.php?rest_route=\/wp\/v2\/posts\/1243\/revisions"}],"predecessor-version":[{"id":1249,"href":"https:\/\/hasselba.ch\/blog\/index.php?rest_route=\/wp\/v2\/posts\/1243\/revisions\/1249"}],"wp:attachment":[{"href":"https:\/\/hasselba.ch\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1243"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/hasselba.ch\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1243"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/hasselba.ch\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1243"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}