Keep primefaces socket (push) connection after page refresh - jsf

I'm using Primefaces fileDownload triggered by a commandButton to allow the user to export his work (as a serialized POJO)... which only exists in a view scope (as long as it has not been exported!)
fileDownload XHTML template:
<p:commandButton value="Save worksheet" icon="ui-icon-disk"
ajax="false" onclick="PrimeFaces.monitorDownload(start, stop)">
<p:fileDownload
value="#{applicationManager.applicationController.saveWorksheet()}" />
</p:commandButton>
saveWorksheet() method
#Override
public StreamedContent saveWorksheet() {
StreamedContent worksheetFile = null;
try {
String worksheetFilename = sessionDirectories + sessionId + "/worksheet.wbc";
System.out.println("saveWorksheet");
FileOutputStream fileOut = new FileOutputStream(worksheetFilename);
ObjectOutputStream out = new ObjectOutputStream(fileOut);
out.writeObject(historyList);
out.close();
fileOut.close();
FileInputStream stream = new FileInputStream(worksheetFilename);
worksheetFile = new DefaultStreamedContent(stream, "application/wbc", "worksheet.wbc");
} catch (IOException e) {
e.printStackTrace();
}
return worksheetFile;
}
(historyList is just an ArrayList of history records)
This file downloading feature is working fine. The problem is that I'm using Primefaces push to display the result of the command sent by the user (because I need to display it on every client sharing the same URL fragment). But since fileDownload triggered by a commandButton needs a full page refresh, the socket disconnects on download start.
(note: the socket is connected in the applicationManager bean which is view scoped).
Socket XHTML template:
<p:socket onMessage="handleOutput" channel="/terminalOutput"
widgetVar="subscriber" />
Socket connection:
RequestContext.getCurrentInstance().execute("subscriber.connect('/" + sessionId + "')");
Is there any way to make the socket connection survive a page refresh? is there a way to define the scope of the socket?
Many thanks in advance for your help :)
Regards,
Zim

Related

How to show a printable PDF directl with a loading spinner in the browser in JSF?

I've implemented a mechanism to generate and download a PDF within my JSF page, with the usage a method within my bean. Here are the component to perform this operation:
<p:commandButton title="Stampa" icon="ui-icon-print"
ajax="false" onclick="PrimeFaces.monitorDownload(start, stop);"
rendered="#{productionOrdersView.showMenuOptions()}"
target="_blank"
actionListener="#{productionOrdersView.print(true)}">
</p:commandButton>
And this is the method in the bean:
public StreamedContent generateSelectedPDFFile() {
String fileName = "Bolla_" + selected.getOrderNumber();
InputStream stream = new ByteArrayInputStream(
new GenerateStatusPDF(companyInfo).generate(selected).toByteArray());
StreamedContent file = new DefaultStreamedContent(stream, "application/pdf", fileName + ".pdf");
return file;
}
I want to achieve this pattern:
User click
The dialog with loading process is showed
The bean loads the data
Complete the generation of the PDF
The dialog is dismissed
The printable document is shoed in a new tab
How Can I achieve this?

PrimeFaces uploadFile, trying to upload multiple files and stopping at one

So basically, I have a fileUploader that I want to do multiple files at a time. When I click upload with 2 or more files, it runs the event handler once, and then stops, not running it again for the rest of the files, even though it shows them in queue on the page.
<h:panelGroup>
<h:panelGrid columns="3" >
<h:outputText value="Attach Files:"/>
<p:fileUpload allowTypes="/(\.|\/)(doc|docx|xls|xlsx|pdf)$/" mode="advanced" multiple="true" sizeLimit="30000000" auto="true" fileUploadListener="#{requestPart.handleFileUpload}" update="messages"/>
<p:messages id="mgs" showDetail="true"/>
</h:panelGrid>
</h:panelGroup>
My event handler code is as follows
private List<UploadedFile> uploadedFileList = new ArrayList<UploadedFile>();
public void handleFileUpload(FileUploadEvent event) throws NotSupportedException, SystemException, SQLException
{
System.out.println("Uploading Request Part files....");
UploadedFile file = event.getFile();
uploadedFileList.add(file);
FacesMessage msg = new FacesMessage("File attached successfully.", file.getFileName() + " is uploaded.");
FacesContext.getCurrentInstance().addMessage(null, msg);
}
Could anyone point me in the write direction? As far as I know, the event is just one file at a time and never a list?
Which version of PF?
I had similar problem with PF 5.0.
Try with this:
public static synchronized void addToList{
uploadedFileList.add(file);
}
My solution is:
sequential="true" add in your fileUpload and your bean
private List<UploadedFile> archImagen;
public void handleFileUpload(FileUploadEvent event) {
archImagen.add( event.getFile());
}

Send HTTP POST request to external site using <h:form>

I want to send a HTTP post request to another server using <h:form> component.
I can send a POST request to an external site using HTML <form> component, but <h:form> component does not support this.
<form action="http://www.test.ge/get" method="post">
<input type="text" name="name" value="test"/>
<input type="submit" value="CALL"/>
</form>
How can I achieve this with <h:form>?
It's not possible to use <h:form> to submit to another server. The <h:form> submits by default to the current request URL. Also, it would automatically add extra hidden input fields such as the form identifier and the JSF view state. Also, it would change the request parameter names as represented by input field names. This all would make it insuitable for submitting it to an external server.
Just use <form>. You can perfectly fine use plain HTML in a JSF page.
Update: as per the comments, your actual problem is that you have no idea how to deal with the zip file as obtained from the webservice which you're POSTing to and for which you were actually looking for the solution in the wrong direction.
Just keep using JSF <h:form> and submit to the webservice using its usual client API and once you got the ZIP file in flavor of InputStream (please, do not wrap it a Reader as indicated in your comment, a zip file is binary content not character content), just write it to the HTTP response body via ExternalContext#getResponseOutputStream() as follows:
public void submit() throws IOException {
InputStream zipFile = yourWebServiceClient.submit(someData);
String fileName = "some.zip";
FacesContext fc = FacesContext.getCurrentInstance();
ExternalContext ec = fc.getExternalContext();
ec.responseReset();
ec.setResponseContentType("application/zip");
ec.setResponseHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
OutputStream output = ec.getResponseOutputStream();
try {
byte[] buffer = new byte[1024];
for (int length = 0; (length = zipFile.read(buffer)) > 0;) {
output.write(buffer, 0, length);
}
} finally {
try { output.close(); } catch (IOException ignore) {}
try { zipFile.close(); } catch (IOException ignore) {}
}
fc.responseComplete();
}
See also:
How to provide a file download from a JSF backing bean?

JSF PrimeFaces FileDownload problem

I'm using PrimeFaces for a new project and it's quite an impressive set of components.
Anyway, I have problem with "real world" use of filedownload component.
In my page I have a datalist that shows the attachments related to a particular document, and I want provide a link to directly download that file inside the datalist item.
Here's my xhtml code:
<p:dataList id="ListaAllegati" value="#{documentBean.documento.allegati}" type="definition" var="attach" style="border: none" ">
<f:facet name="description">
<h:outputText value="#{attach.name}" />
<p:commandLink ajax="false" title="Download" action="#{documentBean.selectAttach}>
<h:graphicImage style="margin-left: 10px; border: none" value="./images/article.png" height="24" width="24" ></h:graphicImage>
<p:fileDownload value="#{documentBean.downloadFile}"/>
<f:setPropertyActionListener target="#{documentBean.selectedAttach}" value="#{attach}" />
</p:commandLink>
</f:facet>
</p:dataList>
and the relative java bean (request scoped):
private StreamedContent downloadFile;
public StreamedContent getDownloadFile() {
log.info("getter dell'allegato invocato");
InputStream stream = null;
byte[] rawFile = null;
if (selectedAttach == null) {
log.warn("Nessun allegato passato");
return null;
} else {
try {
log.info("Recupero del file " + selectedAttach.getGuid());
rawFile = attachManager.retrieveFile(selectedAttach.getGuid());
} catch (Exception e) {
String msg = "Errore durante il recupero del file";
log.error(msg, e);
FacesMessage fmsg = new FacesMessage(msg, "");
FacesContext.getCurrentInstance().addMessage(null, fmsg);
}
stream = new ByteArrayInputStream(rawFile);
DefaultStreamedContent file = new DefaultStreamedContent(stream,
selectedAttach.getMimeType(), selectedAttach.getName());
return file;
}
}
public void selectAttach() {
log.info("commandLink action invocata");
}
private Allegato selectedAttach;
public Allegato getSelectedAttach() {
return selectedAttach;
}
public void setSelectedAttach(Allegato selectedAttach) {
log.info("Allegato selezionato");
if (selectedAttach==null) log.warn("L'allegato passato รจ nullo");
this.selectedAttach = selectedAttach;
}
So, couple of question:
Am I doing the right thing trying to pass the selected attachment that way? Otherwise, how can I pass a parameter to tell the bean wich attachment has been clicked?
Why the first time I click the command link, nothing happen? It make a roundtrip with server, but nothing happens. Second time, it gives me an exception.
Why documentBean.selectAttach is never called and the documentBean.selectedAttach property is never set (neither the second time)?
Thanks to anyone for any hint
How to get the row object from the datatable is answered in this question:
How can I pass selected row to commandLink inside dataTable?
This answers basically all the three questions.
As to the exception in the second click, that's likely because you didn't return from the catch block when an exception is been thrown in your getDownloadFile() method. You're continuing the remnant of the code flow while the rawFile is still null. Fix it accordingly as well. Add a return null to the end of catch or something. Better yet, you should be posting the entire stacktrace in the question as you don't seem to be able to understand it. It basically already contains the answer :)
Primefaces has its own dedicated servlet for file download and upload components that handle all of this asynchronously.
Try doing something like what I have in my code
<p:commandLink ajax="false" actionListener="#{managedBean.downloadAction(object)}">
<span class="ui-icon icoFolderGo" style="padding-right: 1.5em;" />
<p:fileDownload value="#{managedBean.downloadContentProperty}" />
</p:commandLink>
And in the managed bean,
public void downloadAction(Object object) {
try {
InputStream stream = // get input stream from argument
this.setDownloadContentProperty(new DefaultStreamedContent(stream, "application/pdf", "filename.pdf");
} catch (Exception e) {
log.error(e);
}
}
public void setDownloadContentProperty(StreamedContent downloadContentProperty) {
this.downloadContentProperty = downloadContentProperty;
}
public StreamedContent getDownloadContentProperty() {
return downloadContentProperty;
}

How can I maintain scroll position across postbacks in JSF?

I am using JSF frontend for a page where an image is uploaded or deleted. Clicking on the upload or delete button causes a postback and the page to reload with the updated status. This however, resets the scroll position of the page. How should I go about retaining the scrollback of this page on the postback actions.
You can do that with an actionListener. For example, in your page (page.jsf for example):
<f:view>
<h:form>
<h:commandLink actionListener="#{bean.method}">
<h:outputText value="Submit" />
<f:param name="anchor" value="image" />
</h:commandLink>
</h:form>
<div id='result'>
<h1><a name='image'>Image</a></h1>
</div>
</f:view>
And the managed bean looks like:
public class Bean {
public void method(ActionEvent actionEvent) {
// Get parameter
String ancla = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("anchor");
try {
FacesContext.getCurrentInstance().getExternalContext().redirect("page.jsf#" + anchor);
} catch (IOException e) {
e.printStackTrace();
}
}
}
Hope this helps
If you are using Apache MyFaces Tomahawk, you can set the parameter AUTOSCROLL then make sure AutoScrollPhaseListener is enabled.
I'm not sure this functionality is specified by JSF, but instead is something extra implemented by Apache MyFaces Tomahawk.
Also, be aware that prior to version 1.1.6, there is a cross-site scripting vulnerability in the AUTOSCROLL implementation.
you can use jquery.. Using cookies..
in ready function
$(function(){
//set window scroll position if cookie is set
window.scroll(0,getCookie('myCookie'));
//unset cookie after setting scroll position
deleteCookie('myCookie');
//make this class objects keep page scroll position
jQuery(window).unload(function() {
setCookie('myCookie', getPageScroll());
});
//-------------------
});
after ready function add this functions..
function setCookie(name,value) {
var date = new Date();
date.setTime(date.getTime()+(10*1000));
var expires = "; expires="+date.toGMTString();
document.cookie = name+"="+value+expires+"; path=/";
}
function getCookie(name) {
var nameEQ = name + "=";
var ca = document.cookie.split(';');
for(var i=0;i < ca.length;i++) {
var c = ca[i];
while (c.charAt(0)==' ') c = c.substring(1,c.length);
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
}
return null;
}
function deleteCookie(name) {
setCookie(name,"",-1);
}
i wish this help you..

Resources