Date post: | 20-Jun-2015 |
Category: |
Technology |
Upload: | johnfoldager |
View: | 1,055 times |
Download: | 2 times |
Vi tales vedVi tales ved
iZoneiZone
XPages Binary OutputThe only limitation is your imagination
John Foldager, izone.dkDanNotes November 28th 2013
iZoneiZone
About John Foldager● Born in 1974 and have been working with IT – especially
programming since the age of 7 – at iZone since 1999
● Member of Notesnet.dk – association of approx. 25 independent consultants
● Vice chairman of Eclipse.dk
● Mentor at Egedal CoderDojo
● Pro Cross-platform development (IBM i, Linux, Unix, BSD, Windows, Solaris, AIX, Raspberry Pi, Android, …)
● Pro Java/OSGi (scalability, deployment, extensibility, …)
● Pro HTML5/CSS3/JavaScript
● Follow me on Twitter @JohnFoldager
iZoneiZone
Introduction● Normal use of XPages uses HTML, Dojo, IBM OneUI etc.
● Sometimes other formats/content are needed
● Text output● XML (eXtensible Markup Language), JSON (JavaScript Object Notation), CSV
(Comma Separated Values), SVG (Scalable Vector Graphics), …
● Binary output● Media: images (PNG, JPEG, GIF, …), video (MPEG, …), sound (MP3, Ogg, …)● Document formats: PDF (Portable Document Format), OpenXPS (Open XML
Paper Specification), ODF (Open Document Format), OOXML (Office Open XML), …
● Other: SVG (Scalable Vector Graphics), Archives (ZIP, …), …
● We will show how to...
● use XPages, XAgents, NSF servlets and OSGi servlets
● embed and/or download content
iZoneiZone
XAgents● Who uses XAgents [in the audience]?
● First mentioned by Stefan Wissel on http://www.wissel.net/blog/d6plinks/shwl-7mgfbn
● XAgents are XPages where property rendered is set to false and some code is put into beforeRenderResponse (binary) or afterRenderResponse (text)
● Code is SSJS (Server Side JavaScript)● Easy and quick to write because you are on the same 'page'
● Evaluated at runtime (lower performance)
● Harder to debug and unit test
● Some examples...
iZoneiZone
XAgents – XML example● Create an XPage where property rendered is set to false
and put the following code in the afterRenderResponse (SSJS)
● var external = facesContext.getExternalContext();var writer = facesContext.getResponseWriter();var response = external.getResponse();
response.setContentType("text/xml");response.setHeader("Cache-Control", "no-cache");
writer.write("<?xml version='1.0' encoding='utf-8'?>\r\n");writer.write("<say>Hello World!</say>");
writer.endDocument();facesContext.responseComplete();
iZoneiZone
XAgents – JSON example● Create an XPage where property rendered is set to false
and put the following code in the afterRenderResponse (SSJS)
● var external = facesContext.getExternalContext();var writer = facesContext.getResponseWriter();var response = external.getResponse();
response.setContentType("application/json");response.setHeader("Cache-Control", "no-cache");
writer.write("{\r\n");writer.write(" 'say':'Hello World!'\r\n");writer.write("}\r\n");
writer.endDocument();facesContext.responseComplete();
iZoneiZone
XPages – Other formats● Who [in the audience] have tried to deliver non-standard HTML
from an XPage (without using XAgents) and having 100% control of all content?
● First mentioned by John Foldager on http://xpages.dk/?p=83
● XPages can be set to create non-HTML content very easily● NOTE: Several guides on the Internet describes various ways of removing Dojo,
OneUI etc. – but none of them gives you absolutely full control of the entire content. For the most part you overrule everything for all XPages inside the NSF, even though you might only want to do so for a single XPage.
● Only thing you need to do is set the rendererType to javax.faces.Text and set createForm to false
● Some examples...
iZoneiZone
XPages – Custom output (1)● Create a Hello World XPage
iZoneiZone
XPages – Custom output (2)● Change DOCTYPE to HTML5 compliant (globally inside NSF)
iZoneiZone
XPages – Custom output (2)● Change DOCTYPE to HTML5 compliant (globally inside NSF)
iZoneiZone
XPages – Custom output (3)● Expand includes (globally inside NSF)
iZoneiZone
XPages – Custom output (4)● Remove Dojo (globally inside NSF)
iZoneiZone
XPages – Custom output (5)● Remove form and fields (locally to current XPage)
iZoneiZone
XPages – Custom output (6)● Remove the rest (locally to current XPage)
iZoneiZone
XPages – Custom output (7)● Your own HTML5 content (locally to current XPage)
iZoneiZone
XPages – HTML5 example● Create an XPage with the following source
● <?xml version="1.0" encoding="UTF-8"?><xp:view xmlns:xp="http://www.ibm.com/xsp/core" createForm="false" rendererType="javax.faces.Text">
<xp:this.afterRenderResponse><![CDATA[#{javascript:var external = facesContext.getExternalContext();var response = external.getResponse();response.setContentType("text/html");response.setHeader("Cache-Control", "no-cache");response.setHeader("Pragma", "no-store");}]]></xp:this.afterRenderResponse>
<xp:text escape="false" disableTheme="true"><xp:this.value><![CDATA[#{javascript:'<!DOCTYPE html>\n'}]]></xp:this.value></xp:text>
<html lang="en"><head> <content encoding="utf-8"/> <title>My HTML5 page</title></head><body> <header><h1>My HTML5 page delivered from an XPage</h1></header></body>
</xp:view>
iZoneiZone
XPages – XML example #1● Create an XPage with the following source
● <?xml version="1.0" encoding="UTF-8"?><xp:view xmlns:xp="http://www.ibm.com/xsp/core" createForm="false" rendererType="javax.faces.Text">
<xp:this.afterRenderResponse><![CDATA[#{javascript:var external = facesContext.getExternalContext();var response = external.getResponse();response.setContentType("text/xml");response.setHeader("Cache-Control", "no-cache");response.setHeader("Pragma", "no-store");}]]></xp:this.afterRenderResponse>
<xp:text escape="false" disableTheme="true"><xp:this.value><![CDATA[#{javascript:'<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n'}]]></xp:this.value></xp:text>
<say>Hello World!</say>
</xp:view>
iZoneiZone
XPages – XML example #2● Create an XPage with the following source
● <?xml version="1.0" encoding="UTF-8"?><xp:view xmlns:xp="http://www.ibm.com/xsp/core" createForm="false" rendererType="javax.faces.Text">
<xp:this.afterRenderResponse><![CDATA[#{javascript:var external = facesContext.getExternalContext();var response = external.getResponse();response.setContentType("text/xml");response.setHeader("Cache-Control", "no-cache");response.setHeader("Pragma", "no-store");}]]></xp:this.afterRenderResponse>
<xp:text escape="false" disableTheme="true"><xp:this.value><![CDATA[#{javascript:'<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n'}]]></xp:this.value></xp:text>
<xp:repeat id="repeat" rows="30" var="dataentry" removeRepeat="true"> <xp:this.facets> <xp:text disableTheme="true" xp:key="header" escape="false"> <xp:this.value><![CDATA[<customers>]]></xp:this.value> </xp:text> <xp:text disableTheme="true" xp:key="footer" escape="false"> <xp:this.value><![CDATA[</customers>]]></xp:this.value> </xp:text> </xp:this.facets>
<xp:this.value><![CDATA[#{javascript:[1,2,3,4]}]]></xp:this.value>
<xp:text escape="false" disableTheme="true"> <xp:this.value><![CDATA[#{javascript:"<customer>" + dataentry + "</customer>\n"}]]></xp:this.value> </xp:text></xp:repeat>
</xp:view>
iZoneiZone
What did we learn so far?● Now we know how to create our own content from an XPage
(disabling all defaults) and from an XAgent (XPage)
● So what exactly did we learn?● We learned how to overrule whatever XPage engine is normally generating
● We learned how to use XPages repeat-control and Data Source
● We learned how to set the Content Type
● We learned how to set headers (fx. Caching)
● We basically learned that XPages can be used for sooooooo much more than what we normally use it for
iZoneiZone
Download?● How can we make the browser download the content?
● This is actually pretty easy. We just need to add another HTTP Header to the response
● <?xml version="1.0" encoding="UTF-8"?><xp:view xmlns:xp="http://www.ibm.com/xsp/core" createForm="false" rendererType="javax.faces.Text">
<xp:this.afterRenderResponse><![CDATA[#{javascript:var external = facesContext.getExternalContext();var response = external.getResponse();response.setContentType("text/plain");response.setHeader("Cache-Control", "no-cache");response.setHeader("Pragma", "no-store");response.setHeader("Content-Disposition", "attachment; filename=MyFilename.txt");}]]></xp:this.afterRenderResponse>
Hello World!
</xp:view>
iZoneiZone
Even more control?● So can we get even more control?
● YES!
● We can use servlets either from inside the NSF or using an OSGi bundle, but before we get to that...
● We will try to create a Java class that can be called from a button or link on a normal XPage to download some content
● An example...
iZoneiZone
Download from XPage (1)● Steps to follow
● Create a Java Managed Bean class to deliver content
● Create entry for bean in faces-config.xml
● Create button or link on XPage to call bean
Remember Per Henrik Lausten's presentation earlier today?
iZoneiZone
Download from XPage (2)● Steps to follow
● Create a Java Managed Bean class to deliver content● package dk.izone.demos.download;
import java.io.IOException;import java.io.OutputStream;import java.io.Serializable;import javax.faces.context.ExternalContext;import javax.faces.context.FacesContext;import com.ibm.xsp.webapp.XspHttpServletResponse;import dk.izone.demos.utils.io.FileIO;
public class DownloadBean implements Serializable { private static final long serialVersionUID = 1L; public DownloadBean() {}
public void download() { try { byte[] file = FileIO.readFile("C:\\temp\\MyArchive.zip"); FacesContext context = FacesContext.getCurrentInstance(); ExternalContext external = context.getExternalContext(); XspHttpServletResponse response = (XspHttpServletResponse) external.getResponse(); response.setContentType("application/zip"); response.setHeader("Content-Disposition", "attachment; filename=MyArchive.zip"); response.setHeader("Content-Length", String.valueOf(file.length)); OutputStream os = response.getOutputStream(); os.write(file); os.close(); context.responseComplete(); } catch (IOException e) { e.printStackTrace(); } }
}
iZoneiZone
Download from XPage (3)● Steps to follow
● Create a Java Managed Bean class to deliver content
● Create entry for bean in faces-config.xml● <?xml version="1.0" encoding="UTF-8"?>
<faces-config>
<managed-bean> <managed-bean-name>MyBean</managed-bean-name> <managed-bean-class>dk.izone.demos.download.DownloadBean</managed-bean-class> <managed-bean-scope>application</managed-bean-scope> </managed-bean>
</faces-config>
iZoneiZone
Download from XPage (4)● Steps to follow
● Create a Java Managed Bean class to deliver content
● Create entry for bean in faces-config.xml
● Create button or link on XPage to call bean● <xp:button id="button1" value="Download">
<xp:eventHandler event="onclick" submit="true" refreshMode="complete"> <xp:this.action><![CDATA[#{javascript:MyBean.download();}]]></xp:this.action> </xp:eventHandler></xp:button>
● <xp:link id="link1" text="Download"> <xp:eventHandler event="onclick" submit="true" refreshMode="complete"> <xp:this.action><![CDATA[#{javascript:MyBean.download();}]]></xp:this.action> </xp:eventHandler></xp:link>
iZoneiZone
Acknowledgement● The previous example is a rewrite of an example by Jakob
Majkilde which can be found on http://xpages.dk/?p=1396
iZoneiZone
Standard Java? #1● Can we get even more control and use standard Java?
● YES!
● We can use Java Servlets either from inside the NSF or using an OSGi bundle. We will start by showing the NSF way...
● We will show a Java Servlet that
● will reside inside the NSF so that it can be deployed like we “use to”
● looks “a little bit” like a real standard Java Servlet
● core Java developers should be able to work from template
● An example...
iZoneiZone
Standard Java? #1● Depend on Extension Library
● Create Java class that extends DefaultServletFactory
● Create file META-INF/services/com.ibm.xsp.adapter.servletFactory and put Java class package and name in
● An example...
iZoneiZone
Standard Java? #2● Can we create standard Java Servlets using Eclipse IDE (or
any other IDE based on Eclipse) and deploy to the Domino server as an OSGi bundle?
● YES! We can even do it using an Update Site :-)
● We can create servlets to either an Equinox HTTP Service or Expeditor Web Container (J2EE)
● We will show a Java servlet that
● is an Eclipse OSGi plugin project
● is a real standard Java Servlet
● core Java developers should be able to work right away
● An example...
iZoneiZone
Standard Java? #2● An example...
iZoneiZone
3rd Party Java API Deployment● There are plenty of Java APIs that can be downloaded on the
Internet and used for various purposes
● Examples● Apache Software Foundation (apache.org)
● Images
● Barcodes (Barcode4J, …)
● Office Files (Apache POI, ODF Toolkit, OOXML, …)
● PDFs (Apache PDF Box, iText, …)
● etc.
● So lets see how we can deploy these 3rd party Java APIs using OSGi bundles
iZoneiZone
Need Help?● You are more than welcome to contact “Gang of Four”
● Jakob Majkilde, majkilde.dk
● Per Henrik Lausten, phl-consult.dk
● John Dalsgaard, dalsgaard-data.dk
● John Foldager, izone.dk
iZoneiZone
Links● Here are some links that refer to related information
● DOCTYPE – http://www.dominoguru.com/pages/change_xpage_doctype.html
● Domino OSGi development – http://www.slideshare.net/fiorep/domino-osgi-development
iZoneiZone
Questions? Contact!● You are more than welcome to contact me directly
● Website: http://izone.dk
● Phone: +45 20 22 22 11
● Email: [email protected]
● LinkedIn: http://dk.linkedin.com/in/foldager
● Twitter: @JohnFoldager
● Google+: +JohnFoldager
● http://john.foldager.tel