Forums de discussion
Download File from InputStream [resolved]
Marc Stone, modifié il y a 13 années.
Download File from InputStream [resolved]
New Member Publications: 6 Date d'inscription: 07/01/11 Publications récentes
Hi community,
i am running a liferay portal 5.2.3 with portletfaces bridge 2.0 beta3.
I have a form in my application where i want to generate a download from a inputstream. I dont know how to generate a download from my inputstream. To keep it simple I tried an example with reading a MsExcel Doc and I get the following error:
The code in my backing bean is the following:
I dont know what I am doing wrong. The only alternatives are to save a gererated file to disk generate a link to the file. I hope someone can help me.
Thank you very much for help,
Vonso. <_<
i am running a liferay portal 5.2.3 with portletfaces bridge 2.0 beta3.
I have a form in my application where i want to generate a download from a inputstream. I dont know how to generate a download from my inputstream. To keep it simple I tried an example with reading a MsExcel Doc and I get the following error:
java.io.IOException: Unable to call portletResponse.getPortletOutputStream() for portletResponse=[com.liferay.portlet.ActionResponseImpl] because it is not a MimeResponse.
at org.portletfaces.bridge.context.ExternalContextImpl.getResponseOutputStream(ExternalContextImpl.java:1014)
at de.xxxxx.presentation.psv.reporting.ReportingBusinessController.myCalledMethodinBackingBean(ReportingBusinessController.java:137)
The code in my backing bean is the following:
### DO NOT USE THIS CODE - IT DOESNT WORK AND ISNT THE SOLUTION ####
public void myCalledMethodinBackingBean() {
final FacesContext ctx = FacesContext.getCurrentInstance();
final ExternalContext externalContext = ctx.getExternalContext();
try {
final InputStream input = new FileInputStream( "C://testdocument.xls" );
ReadableByteChannel readableByteChannel = null;
WritableByteChannel writableByteChannel = null;
final int bufferSize = 1024;
final ByteBuffer byteBuffer = ByteBuffer.allocate( bufferSize );
try {
// Open an input stream in order to read the resource's contents/data.
if ( input != null ) {
LOGGER.info( " #### input != null !!!!!" );
// Set the response buffer size.
final int responseBufferSize = byteBuffer.capacity();
externalContext.setResponseBufferSize( responseBufferSize );
final String responseContentType = "application/msexcel";
if ( responseContentType != null ) {
externalContext.setResponseContentType( responseContentType );
}
// Copy the bytes in the resource's input stream to the response's output stream.
int responseContentLength = 0;
readableByteChannel = Channels.newChannel( input );
// Here comes the error
writableByteChannel = Channels.newChannel( externalContext.getResponseOutputStream() );
int bytesRead = readableByteChannel.read( byteBuffer );
int bytesWritten = 0;
while ( bytesRead != -1 ) {
byteBuffer.rewind();
byteBuffer.limit( bytesRead );
do {
LOGGER.debug( "bytesWritten: " + bytesWritten );
bytesWritten += writableByteChannel.write( byteBuffer );
} while ( bytesWritten < responseContentLength );
byteBuffer.clear();
responseContentLength += bytesRead;
bytesRead = readableByteChannel.read( byteBuffer );
}
// Now that we know how big the file is, set the response content length.
externalContext.setResponseContentLength( responseContentLength );
externalContext.setResponseStatus( HttpServletResponse.SC_OK );
if ( writableByteChannel != null ) {
writableByteChannel.close();
}
if ( readableByteChannel != null ) {
readableByteChannel.close();
}
if ( input != null ) {
input.close();
}
}
} catch ( final IOException e ) {
LOGGER.info( " ##### IOException ERROR!!!!!!!!!!" );
e.printStackTrace();
externalContext.setResponseStatus( HttpServletResponse.SC_NOT_FOUND );
}
} catch ( final FileNotFoundException e1 ) {
LOGGER.info( " ##### FileNotFoundException ERROR!" );
e1.printStackTrace();
}
ctx.responseComplete();
LOGGER.info( " # ctx.responseComplete()!" );
}
I dont know what I am doing wrong. The only alternatives are to save a gererated file to disk generate a link to the file. I hope someone can help me.
Thank you very much for help,
Vonso. <_<
Neil Griffin, modifié il y a 13 années.
RE: Download File from InputStream
Liferay Legend Publications: 2655 Date d'inscription: 27/07/05 Publications récentes
I recommend checking out the JSF 2 Export PDF example portlet here: http://www.liferay.com/community/liferay-projects/liferay-faces/demos
Marc Stone, modifié il y a 13 années.
RE: Download File from InputStream
New Member Publications: 6 Date d'inscription: 07/01/11 Publications récentes
Hi Neil,
sorry, i forget to say that the code is already based on your PDF example without using the CustomerExportResource, because the InputStream should contains the whole file to download. I used the handleResourceRequest() Method from the Class CustomerResourceHandler and modified it a little bit.
sorry, i forget to say that the code is already based on your PDF example without using the CustomerExportResource, because the InputStream should contains the whole file to download. I used the handleResourceRequest() Method from the Class CustomerResourceHandler and modified it a little bit.
Neil Griffin, modifié il y a 13 années.
RE: Download File from InputStream
Liferay Legend Publications: 2655 Date d'inscription: 27/07/05 Publications récentes
Are you initiating the download by clicking on a Submit button? If so, it might be a full HTTP POST that is participating in the Portlet ACTION_PHASE. The javax.portlet.ActionResponse is not able to participate in a file download, which I think is why you are seeing the error.
Instead, this should be done using the Portlet RESOURCE_PHASE which is is what the example Export PDF portlet shows how to do.
Instead, this should be done using the Portlet RESOURCE_PHASE which is is what the example Export PDF portlet shows how to do.
Marc Stone, modifié il y a 13 années.
RE: Download File from InputStream
New Member Publications: 6 Date d'inscription: 07/01/11 Publications récentes
Hi Neil,
yes, i have a form with a submit button and the button calls a method in my backing bean. In this method i want to flush out/export a file generated from the inputs in the form.
For generating the file i use a external service i call in my method that returns me back a InputStream including a binary ZIP File.
I have no idea how to make the InputStream to a file and send it to the user.
Can i write to the ResponseOutputStream? From the externalContext i can not set it.
I dont understand how the PDF example works exactly. Where is the part you send the file to the user? Is this only possible when i override the handleResourceRequest method?
Thank you very much for your help.
yes, i have a form with a submit button and the button calls a method in my backing bean. In this method i want to flush out/export a file generated from the inputs in the form.
For generating the file i use a external service i call in my method that returns me back a InputStream including a binary ZIP File.
I have no idea how to make the InputStream to a file and send it to the user.
Can i write to the ResponseOutputStream? From the externalContext i can not set it.
I dont understand how the PDF example works exactly. Where is the part you send the file to the user? Is this only possible when i override the handleResourceRequest method?
Thank you very much for your help.
Neil Griffin, modifié il y a 13 années.
RE: Download File from InputStream
Liferay Legend Publications: 2655 Date d'inscription: 27/07/05 Publications récentes
You can only write to the response in the RENDER_PHASE or RESOURCE_PHASE of the portlet lifecycle. In the JSF2 Export PDF example, the CustomerResourceHandler.handleResourceRequest(FacesContext) method writes data to the response output stream. The stream is obtained with the following call:
externalContext.getResponseOutputStream();
externalContext.getResponseOutputStream();
Marc Stone, modifié il y a 13 années.
RE: Download File from InputStream
New Member Publications: 6 Date d'inscription: 07/01/11 Publications récentes
Hi Neil,
thanks again for you help. Now i have a solution for my problem.
The important thing was the the <resource-handler> entry the faces-config.xml, i didn't see at first time.
In my myCalledMethodinBackingBean() Method i now set my bean attributes and then redirect to my url i catch in the registered resource handler.
In the resource handler i now have full access to my bean and can handle the download like in your jsf2exportpdf example.
Kind regards,
Vonso.
thanks again for you help. Now i have a solution for my problem.
The important thing was the the <resource-handler> entry the faces-config.xml, i didn't see at first time.
In my myCalledMethodinBackingBean() Method i now set my bean attributes and then redirect to my url i catch in the registered resource handler.
In the resource handler i now have full access to my bean and can handle the download like in your jsf2exportpdf example.
Kind regards,
Vonso.
VELMURUGAN SUBRAMANIAN, modifié il y a 12 années.
RE: Download File from InputStream
New Member Publications: 5 Date d'inscription: 10/01/11 Publications récentesMarc Stone:
Hi Neil,
thanks again for you help. Now i have a solution for my problem.
The important thing was the the <resource-handler> entry the faces-config.xml, i didn't see at first time.
In my myCalledMethodinBackingBean() Method i now set my bean attributes and then redirect to my url i catch in the registered resource handler.
In the resource handler i now have full access to my bean and can handle the download like in your jsf2exportpdf example.
Kind regards,
Vonso.
Hi Marc,
I'm also facing the same issue like you did and it would be great if you share the outcome solution code with all. I don't understand how did you
"set my bean attributes and then redirect to my url i catch in the registered resource handler. In the resource handler i now have full access to my bean and can handle the download like in your jsf2exportpdf example "
Thanks in advance
Velu
Marc Stone, modifié il y a 12 années.
RE: Download File from InputStream
New Member Publications: 6 Date d'inscription: 07/01/11 Publications récentes
Hi Velu,
the Problem is, that the Resorce Handler and the Backing Bean have a different FacesContext. So if you want to access to the BeanAttributes from the Handler the attribut values are always initial/null.
In my case I now only set the attributes to the session and generate an URL (maybe with some parameters) where i redirect to.
In the called Backing Bean Method i put the needed attributes (or the Stream or a reference to a service who generates the stream) to a object and then i put it in the HttpSession. If the needed attributes are simple u can put it directly to the URL as parameters and read it in the Resource Handler. I prefer the session way. Then you generate a URL like in the PDF example and make a Faces redirect to it
Then you catch the URL in the registered Ressource Handler like in the PDF example and you do all the businesslogic in the Ressource Handler or in the ExportResource -> read the Parameters from the URL or read the attributes from the object in the session -> then generate your stream from the attributes or get it directly out of your HttpSession.object (dont forget to delete it in the session after you get it). Now everything is like in the PDF example.
Sorry but i cant give you my code because it isnt mine.
I hope i helped you anyway.
Good Luck.
PS: Dont use the code from my first post. Its totally wrong.
the Problem is, that the Resorce Handler and the Backing Bean have a different FacesContext. So if you want to access to the BeanAttributes from the Handler the attribut values are always initial/null.
In my case I now only set the attributes to the session and generate an URL (maybe with some parameters) where i redirect to.
In the called Backing Bean Method i put the needed attributes (or the Stream or a reference to a service who generates the stream) to a object and then i put it in the HttpSession. If the needed attributes are simple u can put it directly to the URL as parameters and read it in the Resource Handler. I prefer the session way. Then you generate a URL like in the PDF example and make a Faces redirect to it
Then you catch the URL in the registered Ressource Handler like in the PDF example and you do all the businesslogic in the Ressource Handler or in the ExportResource -> read the Parameters from the URL or read the attributes from the object in the session -> then generate your stream from the attributes or get it directly out of your HttpSession.object (dont forget to delete it in the session after you get it). Now everything is like in the PDF example.
Sorry but i cant give you my code because it isnt mine.
I hope i helped you anyway.
Good Luck.
PS: Dont use the code from my first post. Its totally wrong.
VELMURUGAN SUBRAMANIAN, modifié il y a 12 années.
RE: Download File from InputStream
New Member Publications: 5 Date d'inscription: 10/01/11 Publications récentes
Thanks Marc for your detailed reply. Your answer helped me a lot to achieve pdf download function with minor approved UI changes.
User has to click 'generate report' button which in turn calls the backing bean method. At this time, I validate the form entries and then set the objects that needs to be exported to pdf as given below and re render a:href link to the user with the below properties.
In my backing bean method,
When the user clicks the resource url, then in my ResourceHandler, i fetch my updated objects from PortletSession,
that needs to be converted to pdf using PDF generator apis and write the input stream back to the response.
I did not mean to get all your code for download resource. I just want to know how you can redirect to resource url from ACTION_PHASE.
Thanks
Velu
User has to click 'generate report' button which in turn calls the backing bean method. At this time, I validate the form entries and then set the objects that needs to be exported to pdf as given below and re render a:href link to the user with the below properties.
<portlet:resourceurl id="myPDF" var="myRenderURL">
<portlet:param name="ln" value="pdfExport" />
<portlet:param name="javax.faces.resource" value="export" />
</portlet:resourceurl>
<h:panelgroup rendered="#{modelBean.exportPDFLink}">
<a href="#{myRenderURL}" target="_blank">Export PDF</a>
</h:panelgroup>
In my backing bean method,
Object objSession = FacesContext.getCurrentInstance().getExternalContext().getSession(false);
try
{
if (objSession instanceof PortletSession)
{
PortletSession portalSession = (PortletSession)objSession;
portalSession.setAttribute("objectListForExport", myArrayList);
}
}catch(Exception we){
we.printStackTrace();
}
When the user clicks the resource url, then in my ResourceHandler, i fetch my updated objects from PortletSession,
Object objSession = FacesContext.getCurrentInstance().getExternalContext().getSession(false);
try
{
if (objSession instanceof PortletSession)
{
PortletSession portalSession = (PortletSession)objSession;
myArrayList = (ArrayList)portalSession.getAttribute("objectListForExport");
}
}catch(Exception we){
we.printStackTrace();
}
that needs to be converted to pdf using PDF generator apis and write the input stream back to the response.
I did not mean to get all your code for download resource. I just want to know how you can redirect to resource url from ACTION_PHASE.
Thanks
Velu
Marc Stone, modifié il y a 12 années.
RE: Download File from InputStream
New Member Publications: 6 Date d'inscription: 07/01/11 Publications récentes
hi Velu,
sorry for my late answer, redirecting is very easy.
Here ist how i did it in my BackingBean:
Thats it. If you now have registered the ResourceHandler in the faces-config.xml, the handleRequest Method will catch the request, like in your example.
sorry for my late answer, redirecting is very easy.
Here ist how i did it in my BackingBean:
final PortletResponse pResponse = (PortletResponse)facesContext.getExternalContext().getResponse();
final String portletName = pResponse.getNamespace().substring( 1, pResponse.getNamespace().length() - 1 );
final String url = "http://serverName:8080/web/guest?_" + portletName + "_javax.faces.resource=export&p_p_id=" + portletName + "&p_p_lifecycle=2";
// set the attributes to the session
// then redirect
FacesContext.getCurrentInstance().getExternalContext().redirect( url );
Thats it. If you now have registered the ResourceHandler in the faces-config.xml, the handleRequest Method will catch the request, like in your example.