Primefaces p:media PDF not loading - primefaces

When I try to load my page including a primefaces media pdf the PDF is not loaded.
I generate the PDF in my postconstruct and keep the streamedcontent in a seperate variable.
In my JSF I call the getStream method that returns the streamedcontent.
JSF page:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:p="http://primefaces.org/ui"
xmlns:f="http://xmlns.jcp.org/jsf/core">
<ui:composition template="/templates/header.xhtml">
<ui:define name="content">
<f:metadata>
<f:viewParam name="invoiceID" value="#{invoiceBean.invoiceID}"/>
</f:metadata>
<ui:param name="invoiceID" value="#{invoiceBean.invoiceID}"/>
<h4 style="text-align: center;"><h:outputText
value="#{msgs['invoice.thankYou']}"/></h4>
<div class="card">
<p:media value="#{invoiceBean.stream}" player="pdf" width="100%" height="800px">
Your browser can't display pdf,
<h:outputLink
value="#{invoiceBean.streamedContent}">click
</h:outputLink>
to download pdf instead.
</p:media>
</div>
</ui:define>
</ui:composition>
</html>
Bean:
#Model
#Getter
#Setter
public class InvoiceBean {
#Inject
InvoiceService invoiceService;
#Inject
HttpServletRequest httpServletRequest;
private Invoice invoice;
private String invoiceID;
private StreamedContent streamedContent;
#PostConstruct
public void initInvoice() {
User user = getLoggedInUser();
invoiceID = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("invoiceID");
invoice = invoiceService.getInvoice(Long.parseLong(invoiceID));
PDFGenerator pdf = new PDFGenerator(invoice);
streamedContent = pdf.getStreamedContent();
}
public StreamedContent getStream() throws IOException{
FacesContext context = FacesContext.getCurrentInstance();
if (context.getCurrentPhaseId() == PhaseId.RENDER_RESPONSE) {
return new DefaultStreamedContent();
} else {
return streamedContent;
}
}
}

Because the stream is dynamic, this post from #BalusC is very useful to resolve this issue. In particular "never declare StreamedContent nor any InputStream or even UploadedFile as a bean property; only create it brand-new in the getter of a stateless #ApplicationScoped bean when the webbrowser actually requests the image content."
The p:media tag needs to disable the cache.
<p:media value="#{pdfViewController.pdf}" player="pdf" cache="false"
width="100%" height="500px" >
Your browser can't display pdf.
</p:media>
<br/>
<h:form>
<p:commandButton value="Download" icon="pi pi-arrow-down" ajax="false">
<p:fileDownload value="#{pdfViewController.pdfDownload}" />
</p:commandButton>
</h:form>
The backing bean needs to do all the work in the getter, not in the PostConstruct method. (See the comments in #BalusC's post about this.) I was able to use both Request (per Showcase) and Session beans, but the PrimeFaces documentation warns against ViewScoped.
#Named
#RequestScoped
public class PdfViewController implements java.io.Serializable {
public StreamedContent getPdf() {
return DefaultStreamedContent.builder()
.contentType("application/pdf")
.stream(() -> makePDFStream())
.build();
}
protected ByteArrayInputStream makePDFStream() {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
String dt = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd-HHmmss-n"));
makePDF(baos, "This message was created at " + dt);
return new ByteArrayInputStream(baos.toByteArray());
}
// use iText to create a PDF document "on the fly"
protected void makePDF(OutputStream os, String message) {
PdfDocument pdf = new PdfDocument(new PdfWriter(os));
try (Document document = new Document(pdf)) {
String line = "Hello! Welcome to iTextPdf";
document.add(new Paragraph(line));
document.add(new LineSeparator((new SolidLine())));
PdfFont font = PdfFontFactory.createFont(StandardFonts.TIMES_ITALIC);
Text msgText = new Text(message).setFont(font).setFontSize(10);
document.add(new Paragraph().add(msgText));
} catch (IOException ex) {
LOG.log(Level.SEVERE, "PDF document creation error", ex);
}
// os is automatically written and closed when document is autoclosed
}
}
In order to support the download option and because the bean is #request, the stream is recreated when needed. It was also necessary to include the .name("...)", whereas the p:media value= tag failed if name is specified, hence it needs a separate method.
public StreamedContent getPdfDownload() {
return DefaultStreamedContent.builder()
.name("temp.pdf")
.contentType("application/pdf")
.stream(() -> makePDFStream())
.build();
}
Tested with PrimeFaces v8 and Wildfly v21 (w/Mojarra).

Related

How can i implement upload file in struts2 with hibernate

I m developping a web app ( Electronic Document Managemen) and i need file upload in strurts 2 and store it to mysql using hibernate, can anybody give better idea. advance thanks
Post edited :
I have start with this :
in pojo class i have:
#Entity
#Table(name="Documents")
public class Documents {
#Id
#GeneratedValue
#Column(name="idDocument")
private Integer idDocument;
#Column(name="content")
#Lob
private byte[] content;
#Column(name="description")
private String description;
in class documentsDaoimpl i have :
public class DocumentsDaoImpl implements DocumentsDao{
#SessionTarget
Session session;
#TransactionTarget
Transaction transaction;
#Override
public void saveOrUpdateDocuments(Documents Document) {
try {
session.saveOrUpdate(Document);
} catch (Exception e) {
transaction.rollback();
e.printStackTrace();
}
} .......
In action class i have :
public class DocumentAction extends ActionSupport implements ModelDriven<Documents>{
private Documents document=new Documents();
private DocumentsDao documentdao=new DocumentsDaoImpl();
#Override
public Documents getModel() {
// TODO Auto-generated method stub
return document;
}
public String saveOrUpdate(){
documentdao.saveOrUpdateDocuments(document);
list();
return SUCCESS;
}
.......
And the JSP i have a form :
<s:form action="saveOrUpdateDocuments" method="post">
<s:hidden name="document.idDocument" />
<s:textfield name="document.description" label="document File " required="true" />
<s:file name="document.content" value="Add Document"/>
<s:submit value="upload" />
</s:form>
I don't Know how can i progressed
Are you planning to store files in database as blob type? Declare your column as BLOB type in database and in your model class declare a variable of type byte[].
//userFile is the file submitted from JSP
byte[] bFile = new byte[(int) userFile.length()];
try {
FileInputStream fileInputStream = new FileInputStream(userFile);
//convert file into array of bytes
fileInputStream.read(bFile);
fileInputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
Now, you can save the bFile into your database. Code taken from this tutorial.
If you simply want to save your image on disk you can follow this code. It also shows how to submit file from JSP using struts 2 form.

Adding custom attribute (HTML5) support to Primefaces (3.4)

In trying to implement the simple html5 attribute 'autofocus' in my JSF/Primefaces web-application, I was alerted to the fact that the components do not pass all unknown attributes on to the final markup. I can understand reasonings for this, as components can be complex combinations of html markup and it would not be clear where to place the attributes if they are not already well-defined by the component.
But the best solution for me is to have support for autofocus (and any other possible types of attributes I may want to support in my application that primefaces has not defined).
I have seen Adding custom attribute (HTML5) support to JSF 2.0 UIInput component, but that seems to apply for the basic JSF components and does not work for PrimeFaces components.
How do I extend the component/rendering of Primefaces to support this?
Instead of homegrowing a custom renderer for every single individual component, you could also just create a single RenderKit wherein you provide a custom ResponseWriter wherein the startElement() method is overriden to check the element name and/or component instance and then write additional attributes accordingly.
Here's a kickoff example of the HTML5 render kit:
public class Html5RenderKit extends RenderKitWrapper {
private RenderKit wrapped;
public Html5RenderKit(RenderKit wrapped) {
this.wrapped = wrapped;
}
#Override
public ResponseWriter createResponseWriter(Writer writer, String contentTypeList, String characterEncoding) {
return new Html5ResponseWriter(super.createResponseWriter(writer, contentTypeList, characterEncoding));
}
#Override
public RenderKit getWrapped() {
return wrapped;
}
}
The HTML5 response writer:
public class Html5ResponseWriter extends ResponseWriterWrapper {
private static final String[] HTML5_INPUT_ATTRIBUTES = { "autofocus" };
private ResponseWriter wrapped;
public Html5ResponseWriter(ResponseWriter wrapped) {
this.wrapped = wrapped;
}
#Override
public ResponseWriter cloneWithWriter(Writer writer) {
return new Html5ResponseWriter(super.cloneWithWriter(writer));
}
#Override
public void startElement(String name, UIComponent component) throws IOException {
super.startElement(name, component);
if ("input".equals(name)) {
for (String attributeName : HTML5_INPUT_ATTRIBUTES) {
String attributeValue = component.getAttributes().get(attributeName);
if (attributeValue != null) {
super.writeAttribute(attributeName, attributeValue, null);
}
}
}
}
#Override
public ResponseWriter getWrapped() {
return wrapped;
}
}
To get it to run, create this HTML5 render kit factory:
public class Html5RenderKitFactory extends RenderKitFactory {
private RenderKitFactory wrapped;
public Html5RenderKitFactory(RenderKitFactory wrapped) {
this.wrapped = wrapped;
}
#Override
public void addRenderKit(String renderKitId, RenderKit renderKit) {
wrapped.addRenderKit(renderKitId, renderKit);
}
#Override
public RenderKit getRenderKit(FacesContext context, String renderKitId) {
RenderKit renderKit = wrapped.getRenderKit(context, renderKitId);
return (HTML_BASIC_RENDER_KIT.equals(renderKitId)) ? new Html5RenderKit(renderKit) : renderKit;
}
#Override
public Iterator<String> getRenderKitIds() {
return wrapped.getRenderKitIds();
}
}
And register it as follows in faces-config.xml:
<factory>
<render-kit-factory>com.example.Html5RenderKitFactory</render-kit-factory>
</factory>
The JSF utility library OmniFaces has also such a render kit, the Html5RenderKit (source code here) which should theoretically also work fine on PrimeFaces components. However, this question forced me to take a second look again and I was embarrassed to see that the component argument in ResponseWriter#startElement() is null in <p:inputText> (see line 74 of InputTextRenderer, it should have been writer.startElement("input", inputText) instead). I'm not sure if this is intentional or an oversight in the design of the PrimeFaces renderer or not, but you could use UIComponent#getCurrentComponent() instead to get it.
Update: this is fixed in OmniFaces 1.5.
Noted should be that the upcoming JSF 2.2 will support defining custom attributes in the view via the new passthrough namespace or the <f:passThroughAttribute> tag. See also What's new in JSF 2.2? - HTML5 Pass-through attributes.
Thus, so:
<html ... xmlns:p="http://java.sun.com/jsf/passthrough">
...
<h:inputText ... p:autofocus="true" />
(you may want to use a instead of p as namespace prefix to avoid clash with PrimeFaces' default namespace)
Or:
<h:inputText ...>
<f:passThroughAttribute name="autofocus" value="true" />
</h:inputText>
The solution that I found was to extend and re-implement the encodeMarkup methods for the input renderers. I wanted a more general solution, but after looking at the Primefaces source code, I did not see any generic hooks for the component renderers to add custom attributes. The markup is written out in the encodeMarkup(FacesContext context, InputText inputText) methods of the renderers. It calls up the class-hierarchy to renderPassThruAttributes(FacesContext context, UIComponent component, String[] attributes) but it only feeds in static final String[] arrays from org.primefaces.util.HTML.
In my case I wanted support for the 'autofocus' attribute on InputMask, InputText, InputTextarea, and Password components. Furthermore, the implementation is the same for each component, so I will walk through implementing 'autofocus' on the InputText component, but it should be obvious how it can be extended to support more attributes and more components.
To extend/override a renderer, you will need to have the Primefaces source available and find the encodeMarkup method and copy its contents. Here is the example for InputTextRenderer:
protected void encodeMarkup(FacesContext context, InputText inputText) throws IOException {
ResponseWriter writer = context.getResponseWriter();
String clientId = inputText.getClientId(context);
writer.startElement("input", null);
writer.writeAttribute("id", clientId, null);
writer.writeAttribute("name", clientId, null);
writer.writeAttribute("type", inputText.getType(), null);
String valueToRender = ComponentUtils.getValueToRender(context, inputText);
if(valueToRender != null) {
writer.writeAttribute("value", valueToRender , null);
}
renderPassThruAttributes(context, inputText, HTML.INPUT_TEXT_ATTRS);
if(inputText.isDisabled()) writer.writeAttribute("disabled", "disabled", null);
if(inputText.isReadonly()) writer.writeAttribute("readonly", "readonly", null);
if(inputText.getStyle() != null) writer.writeAttribute("style", inputText.getStyle(), null);
writer.writeAttribute("class", createStyleClass(inputText), "styleClass");
writer.endElement("input");
}
Extending/Overriding the renderer with your own (see comments for important code):
public class HTML5InputTextRenderer extends InputTextRenderer {
Logger log = Logger.getLogger(HTML5InputTextRenderer.class);
//Define your attributes to support here
private static final String[] html5_attributes = { "autofocus" };
protected void encodeMarkup(FacesContext context, InputText inputText) throws IOException {
ResponseWriter writer = context.getResponseWriter();
String clientId = inputText.getClientId(context);
writer.startElement("input", null);
writer.writeAttribute("id", clientId, null);
writer.writeAttribute("name", clientId, null);
writer.writeAttribute("type", inputText.getType(), null);
String valueToRender = ComponentUtils.getValueToRender(context, inputText);
if (valueToRender != null) {
writer.writeAttribute("value", valueToRender, null);
}
renderPassThruAttributes(context, inputText, HTML.INPUT_TEXT_ATTRS);
//Make an extra call to renderPassThruAttributes with your own attributes array
renderPassThruAttributes(context, inputText, html5_attributes);
if (inputText.isDisabled())
writer.writeAttribute("disabled", "disabled", null);
if (inputText.isReadonly())
writer.writeAttribute("readonly", "readonly", null);
if (inputText.getStyle() != null)
writer.writeAttribute("style", inputText.getStyle(), null);
writer.writeAttribute("class", createStyleClass(inputText), "styleClass");
writer.endElement("input");
}
}
Configuring the rendering override in faces-config.xml
<?xml version='1.0' encoding='UTF-8'?>
<faces-config xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd"
version="2.0">
<!-- snip... -->
<render-kit>
<renderer>
<component-family>org.primefaces.component</component-family>
<renderer-type>org.primefaces.component.InputTextRenderer</renderer-type>
<renderer-class>com.mycompany.HTML5InputTextRenderer</renderer-class>
</renderer>
</render-kit>
<!-- snip... -->
</faces-config>
and just-in-case if you didn't have the faces-config configured in your web.xml add:
<context-param>
<param-name>javax.faces.CONFIG_FILES</param-name>
<param-value>
/WEB-INF/faces-config.xml, /faces-config.xml
</param-value>
</context-param>
Then to use this in some markup:
<p:inputText id="activateUserName" value="${someBean.userName}"
autofocus="on">
</p:inputText>
Note: JSF is not happy with attributes that do not have values. While autofocus in HTML5 does not use a value, JSF will throw an error if one is not given, so make sure to define some throw-away value when adding such attributes.
JSF 2.2 also provides pass through attributes feature designed for HTML5 and beyond so when PrimeFaces officially supports JSF 2.2, you can pass any attribute from components to html elements.

inserting an image in the database with a BLOB datatype

entity:
#Lob
#Column(name = "logo")
private byte[] logo;
form:
<h:form enctype="multipart/form-data">
<p:messages showDetail="true"/>
<p:fileUpload value="#{testController.file}"
update="messages"
mode="simple"
sizeLimit="1048576"
allowTypes="/(\.|\/)(gif|jpe?g|png)$/"/>
<p:growl id="messages" showDetail="true"/>
<p:commandButton value="Submit" ajax="false"
actionListener="#{testController.upload}"/>
</h:form>
bean:
private testEntity current;
private UploadedFile file;
public UploadedFile getFile() {
return file;
}
public void upload() {
if (file != null) {
try {
byte[] data = file.getContents();
current.setLogo(data);
getFacade().edit(current);
JsfUtil.addSuccessMessage("Successful! " + file.getFileName() + " is uploaded.");
} catch (Exception e) {
}
}
}
when i try to upload files like 80kb picture, it will give me this exception
Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.3.2.v20111125-r10461): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: com.mysql.jdbc.MysqlDataTruncation: Data truncation: Data too long for column 'logo' at row 1
but if i upload a mere < 10kb pictures, the code works.
using JSF 2.0, Primefaces 3.5, most codes are auto generated using CRUD.
The problem is that your database column is set to stored less than what you are trying to store. That's what truncating means.
You will need to change your database column definition to LONGBLOB.

How to use toolbar button as download link

I'm writing a RCP/RAP-App with rap 1.4 as target platform for the rap part. In rcp I have a save button configured via menuContribution in the plugin.xml and an according SaveHandler for the save command.
Now I like to use this button as a download button in my rap app.
I've got it.
I wrote a DownloadServiceHandler and created an unvisible Browser with the download-URL in my handler of the save-command.
All the work step by step:
The save-button in the toolbar is configured in the plugin.xml:
<extension
point="org.eclipse.ui.commands">
<command
id="pgui.rcp.command.save"
name="Save">
</command>
</extension>
<extension
point="org.eclipse.ui.menus">
<menuContribution
allPopups="false"
locationURI="toolbar:org.eclipse.ui.main.toolbar">
<toolbar
id="pgui.rcp.toolbar1">
<command
commandId="pgui.rcp.command.save"
icon="icons/filesave_16.png"
id="pgui.rcp.button.save"
style="push"
</command>
</toolbar>
</menuContribution>
</extension>
<extension
point="org.eclipse.ui.handlers">
<handler
class="pgui.handler.SaveHandler"
commandId="pgui.rcp.command.save">
</handler>
</extension>
I created a DownloadServiceHandler:
public class DownloadServiceHandler implements IServiceHandler
{
public void service() throws IOException, ServletException
{
final String fileName = RWT.getRequest().getParameter("filename");
final byte[] download = getYourFileContent().getBytes();
// Send the file in the response
final HttpServletResponse response = RWT.getResponse();
response.setContentType("application/octet-stream");
response.setContentLength(download.length);
final String contentDisposition = "attachment; filename=\"" + fileName + "\"";
response.setHeader("Content-Disposition", contentDisposition);
response.getOutputStream().write(download);
}
}
In the method postWindowCreate of the ApplicationWorkbenchWindowAdvisor I registered the DownloadServiceHandler:
private void registerDownloadHandler()
{
final IServiceManager manager = RWT.getServiceManager();
final IServiceHandler handler = new DownloadServiceHandler();
manager.registerServiceHandler("downloadServiceHandler", handler);
}
In the execute-method of the SaveHandler I created an unvisible Browser and set the url with the filename and the registered DownloadServiceHandler.
final Browser browser = new Browser(shell, SWT.NONE);
browser.setSize(0, 0);
browser.setUrl(createDownloadUrl(fileName));
.
.
private String createDownloadUrl(final String fileName)
{
final StringBuilder url = new StringBuilder();
url.append(RWT.getRequest().getContextPath());
url.append(RWT.getRequest().getServletPath());
url.append("?");
url.append(IServiceHandler.REQUEST_PARAM);
url.append("=downloadServiceHandler");
url.append("&filename=");
url.append(fileName);
return RWT.getResponse().encodeURL(url.toString());
}

How to provide JSON data to Dojo tree using Struts2 framework

I'm currently developing a web application using Struts2 framework. This application requires to dynamically update the objects on the screen based on data received from another application.
At the moment, I would like to implement a dynamic tree view which nodes are updated periodically with data provided by an Action class. I’m trying to do so using the dojo.dijit.tree object from the dojo toolkit. I’m aware that I can do so using the dojo tags which are part of the struts framework, however, it lacks much of the functionality that I need (persistence, open and close branches dynamically, etc) therefore, I have opted for using the dojo toolkit instead.
My problem with the dojo.dijit.tree is that I don’t know how to provide its data using a JSON result type. I have already created a class which returns a JSON result type with the same structure needed by the dojo tree component. I have tested the generation of a dojo tree using a file “test.txt” which was generated by the class and it works as expected. However, I would like to pass the JSON data directly to the dojo.dijit.tree component without saving a file on disk. When I execute the application I get a “save as” window to save the returned JSON result.
This is my struts.xml file:
<struts>
<constant name="struts.devMode" value="true" />
<package name="default" namespace="/" extends="struts-default">
<action name="devResult" class="gui.JsonAction">
<result name="success">/start1.jsp</result>
</action>
</package>
<package name="example" namespace="/" extends="json-default">
<result-types>
<result-type name="json" class="org.apache.struts2.json.JSONResult"></result-type>
</result-types>
<action name="getJSONResult" class="gui.JsonAction">
<result type="json"/>
</action>
</package>
This is the jsp file which displays the tree:
<head>
<title>Testing Tree</title>
<style type="text/css">
#import "js/dojo/dojo/resources/dojo.css";
#import "js/dojo/dijit/themes/nihilo/nihilo.css";
</style>
<script src="http://ajax.googleapis.com/ajax/libs/dojo/1.6/dojo/dojo.xd.js"
djConfig="isDebug: true,parseOnLoad: true">
</script>
<script type="text/javascript">
dojo.require("dojo.data.ItemFileReadStore");
dojo.require("dijit.Tree");
dojo.require("dojo.parser");
</script>
<body class="nihilo">
The Tree:<br><br>
<s:url id="devResult" action="jsonAction.action"></s:url>
<div dojoType="dojo.data.ItemFileReadStore" href="%{devResult}" jsid="popStore" />
<div dojoType="dijit.Tree" store="popStore" labelAttr="sname" label="Tree" />
</body>
This is the Action class which produces the JSON result:
public class JsonAction extends ActionSupport {
private static final long serialVersionUID = 7392602552908646926L;
private String label = "name";
private String identifier = "name";
private List<ChildrenClass> items = new ArrayList<ChildrenClass>();
public JsonAction() {
ChildrenClass item1 = new ChildrenClass("name1", "cat");
ChildrenClass item2 = new ChildrenClass("name2", "cat");
ChildrenClass item3 = new ChildrenClass("name3", "cat");
ChildrenClass item4 = new ChildrenClass("name4", "cat");
items.add(item1);
items.add(item2);
items.add(item3);
items.add(item4);
}
public String execute() {
return SUCCESS;
}
public void setLabel(String label) {
this.label = label;
}
public String getLabel() {
return label;
}
public void setIdentifier(String identifier) {
this.identifier = identifier;
}
public String getIdentifier() {
return identifier;
}
public void setItems(List<ChildrenClass> lists) {
this.items = lists;
}
public List<ChildrenClass> getItems() {
return items;
}
}
This is the ChildrenClass which is used in the class above:
public class ChildrenClass {
private String name;
private String type;
private ChildrenClass[] children;
public ChildrenClass() {
name = "DefaultName";
type = "DefaultType";
}
public ChildrenClass(String aName, String aType) {
name = aName;
type = aType;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setType(String type) {
this.type = type;
}
public String getType() {
return type;
}
public void setChildren(ChildrenClass[] children) {
this.children = children;
}
public ChildrenClass[] getChildren() {
return children;
}
}
I would like to ask to the stackoverflow reader to please indicate me how to do to read the JSON data in the jsp file in order to populate the dojo tree. In addition, I would like to ask how can I refresh the content of it periodically.
PS: If somebody has a better method to implement something similar to this, I would be glad to receive your comments.
Thanks in advance.
I have found out a way to pass data directly from a JSON result to a dojo.dijit.tree component. Setting the "url" parameter to the action name which returns the json result type.
This is my new body of the .jsp file:
Simple Tree:<br><br>
<div dojoType="dojo.data.ItemFileReadStore" url=getJSONResult handleAs="json" jsid="popStore" />
<div dojoType="dijit.Tree" store="popStore" labelAttr="sname" label="PID 512" />