I have an MP3 audio file outside of the application context, in C:/platform/musig.mp3.
I'm using the below servlet to serve it.
public class AudioServlet extends HttpServlet {
#Override
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
ServletOutputStream stream = null;
BufferedInputStream buf = null;
try {
stream = response.getOutputStream();
File mp3 = new File("C:/platform/music.mp3");
response.setContentType("audio/mpeg");
response.addHeader("Content-Disposition", "attachment; filename=" + fileName);
response.setContentLength((int) mp3.length());
FileInputStream input = new FileInputStream(mp3);
buf = new BufferedInputStream(input);
int readBytes = 0;
while ((readBytes = buf.read()) != -1) {
stream.write(readBytes);
}
} finally {
if (stream != null) {
stream.close();
}
if (buf != null) {
buf.close();
}
}
}
}
<servlet>
<servlet-name>audioServlet</servlet-name>
<servlet-class>servlet.AudioServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>audioServlet</servlet-name>
<url-pattern>/audio/*</url-pattern>
</servlet-mapping>
I'm referencing it in <p:media> as below:
<p:media id="media"
value="/audio"
player="quicktime"
width="200"
height="40">
<f:param name="autoPlay" value="false" />
</p:media>
The problem is that I am unable to run the sound. If I put the audio file within the application context (in /resources for example), it works. But out of context, it does not work at all.
The below exception appears in the console when the servlet is invoked:
ClientAbortException: java.net.SocketException: Software Caused connection abort: socket write error
Does anyone have any idea what might be happening? Or is there another way to perform MP3 with the "media" component PrimeFaces I do not know?
I managed to solve :) ... I used to address the response of 0x5a4d and Balusc, with the code 0x5a4d was released a scope error, I'm using in my application the 'Conversation Scope' and launched an exception ... the Balusc commented that the answer was incomplete and could be released this mistake, and that's what happened ...
Then I create a separate Bean only to process the request to MP3 with the 'Default Scope', and it worked ... my class was so.
.
#Named
public class AudioBean {
private StreamedContent media;
public AudioBean() throws FileNotFoundException {
InputStream stream = new FileInputStream("C:\\plataforma\\music.mp3");
media = new DefaultStreamedContent(stream, "audio/mpeg");
}
public StreamedContent getMedia() { return media; }
}
and *.xhtml
<p:media value="#{audioBean.media}"
width="250"
height="225"
player="quicktime"/>
Thank you guys for the help!
like this code skeleton:
*.xhtml
<p:media value="#{mediaBean.media}" width="250" height="225" player="quicktime"/>
#Bean
public class MediaBean {
private StreamedContent media;
public MediaController() {
InputStream stream = new FileInputStream("C://filename.mp3");
media = new DefaultStreamedContent(stream, "audio/mpeg");
}
public StreamedContent getMedia() { return media; }
}
In this example i remove other code for simplify:
#ManagedBean(name = "mediaBean")
#RequestScoped
public class MediaBean{
public StreamedContent getMedia() throws FileNotFoundException{
return new DefaultStreamedContent(new FileInputStream("PATH_TO_MEDIA_FILE"),"audio/mpeg");
}
}
}
Choose the scope you based on your requirement, in my case it was request.
As explanation About
java.net.SocketException: Broken pipe
and not close stream help this and this posts.
Related
I created a fileupload dialog and a image gallery on a jsf page. After each image upload the gallery should show all so far uploaded images. The images will be stored in a backend bean and should be fetched by the gallery dynamically from the backend bean. For some reason the gallery shows the image labels uploaded but not the referring image since the image resource could not be found.
I use spring, primefaces on tomcat. Thanks for any help in advance!
My JSF Page:
<p:fileUpload id="imageUpldoad" update="galleryPanel" fileUploadListener="#{wizzardBean.handleFileUpload}" mode="advanced" dragDropSupport="true"
sizeLimit="10000000" multiple="true" auto="false" fileLimit="100" allowTypes="/(\.|\/)(gif|jpe?g|png)$/" />
<p:panel id="galleryPanel">
<p:galleria id="gallery" value="#{wizzardBean.getHotelImages()}" var="img" panelWidth="500" panelHeight="313" showCaption="true" rendered="#{wizzardBean.showGallery()}">
<p:graphicImage name="#{img.name}" value="#{wizzardBean.hotelImage}" alt="Image Description for #{img.name}" title="#{img}">
<f:param id="imgId" name="imgId" value="#{img.id}" />
</p:graphicImage>
</p:galleria>
My Backend Bean:
public class WizzardBean extends BaseBean {
private List<HotelImage> hotelImages;
public void handleFileUpload(FileUploadEvent event) throws IOException {
if (event.getFile() != null) {
HotelImage hotelImage = new HotelImage(hotelImages.size(), event.getFile().getFileName(), event.getFile());
hotelImages.add(hotelImage);
}
}
public StreamedContent getHotelImage() {
ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
String photoId = externalContext.getRequestParameterMap().get("imgId");
if (photoId == null || photoId.equals("")) {
return null;
} else {
int parsedId = Integer.parseInt(photoId);
return hotelImages.get(parsedId).getImage();
}
}
}
The HotelImage class:
public class HotelImage {
private int id;
private String name;
private StreamedContent image;
public HotelImage(int id, String name, UploadedFile file) {
this.id = id;
this.name = name;
try {
image = new DefaultStreamedContent(file.getInputstream(), "image/jpg");
} catch (IOException e) {
}
}
public int getId() {
return id;
}
public String getName() {
return name;
}
public StreamedContent getImage() {
return image;
}
The browser says:
<img id="mainFormId:j_idt52:j_idt55" src="RES_NOT_FOUND" alt="Image Description for twitter.png" title="twitter.png">
There are several problems with this approach. Those boil down to the incorrect assumption that an uploaded file, an InputStream and StreamedContent can be read and reused multiple times. This is incorrect. The uploaded file will be sent only once and only be available during the original request, and the streams can be read only once after they are created.
Moreover, having a PrimeFaces-specific StreamedContent or even UploadedFile as a bean property is wrong. The bean property should at least be a File referring the physical file on server's local disk file system, or a byte[] representing the raw content in server memory or a Long representing the insert ID of blob entry in database.
You need to adjust your code to save the uploaded file content to a permanent storage location as soon as possible it comes in and then assign the result as a bean property of type File or byte[] or Long. Then, let the rest of the code use that bean property instead to create a StreamedContent within the getter method. Do absolutely not assign that StreamedContent to another bean property.
You can find concrete and elaborate examples in the answer of the questions linked below.
How to save uploaded file in JSF
Display dynamic image from database or remote source with p:graphicImage and StreamedContent
I have an application, which uses PrimeFaces Mobile to display images.
Sometimes, but not always, the image is not displayed fully - only the top part.
The XHTML code of the page with that image looks like this:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui"
xmlns:pm="http://primefaces.org/mobile">
<f:view renderKitId="PRIMEFACES_MOBILE"/>
<h:head>
</h:head>
<f:event listener="#{main.loadFirstImage}" type="preRenderView" />
<h:body id="body">
<pm:page id="page">
<pm:header title="myapp">
</pm:header>
<pm:content id="content">
<h:form>
<p:graphicImage id="image" rendered="false" value="#{main.currentImage()}"
cache="false">
</p:graphicImage>
[...]
</h:form>
</pm:content>
<pm:footer title="m.myapp.com"></pm:footer>
</pm:page>
</h:body>
</html>
And the main bean has following code:
#ManagedBean(name = "main")
#SessionScoped
public class MainView {
private byte[] currentImageData;
private byte[] productId;
private byte[] imageId;
public void loadFirstImage()
{
// This method initializes currentImageData
fetchNextImage();
}
[...]
public StreamedContent currentImage()
{
FacesContext context = FacesContext.getCurrentInstance();
if (context.getCurrentPhaseId() == PhaseId.RENDER_RESPONSE) {
return new DefaultStreamedContent();
}
else {
return new DefaultStreamedContent(new ByteArrayInputStream(currentImageData));
}
}
[...]
}
How can I fix this error?
Update 1 (03.11.2014 23:21 MSK):
I've tried following to fix the error:
1) Disabling cache for all elements of that Primefaces page.
2) Disabling response chunking by setting maxExtensionSize and maxTrailerSize (server.xml) to -1.
3) Adding a filter with following doFilter:
#Override
public void doFilter(final ServletRequest aServletRequest,
final ServletResponse aServletResponse,
final FilterChain aFilterChain) throws IOException, ServletException {
System.out.println("aServletRequest instanceof HttpServletRequest: " +
(aServletRequest instanceof HttpServletRequest));
if (aServletRequest instanceof HttpServletRequest)
{
final HttpServletRequest request = (HttpServletRequest) aServletRequest;
final String requestURI = request.getRequestURI().toLowerCase();
if (!requestURI.endsWith("/javax.faces.resource/dynamiccontent.properties"))
{
aFilterChain.doFilter(aServletRequest, aServletResponse);
}
}
}
4) Changing the currentImage method to
public StreamedContent currentImage()
{
FacesContext context = FacesContext.getCurrentInstance();
if (context.getCurrentPhaseId() == PhaseId.RENDER_RESPONSE) {
// So, we're rendering the view. Return a stub StreamedContent so that it will generate right URL.
return new DefaultStreamedContent();
}
else {
String mimeType = null;
if (imageFileName.toLowerCase().endsWith(".png"))
{
mimeType = "image/png";
}
else if (imageFileName.toLowerCase().endsWith(".jpeg") || imageFileName.toLowerCase().endsWith(".jpg"))
{
mimeType = "image/jpeg";
}
// So, browser is requesting the image. Return a real StreamedContent with the image bytes.
return new DefaultStreamedContent(new ByteArrayInputStream(currentImageData), mimeType);
}
}
But it still doesn't work. I wrote a piece of code in another web application and using different framework (Vaadin), which displays images from the same source.
I get the same error (images are displayed only partially).
From this I conclude that the error must occur
when images are retrieved from a particular and/or
when images are saved in MongoDB.
Code for retrieving images from URL
If the error occurs during reading the image, it occurs in the following method:
protected Binary readImage(final String viewItemURL) {
InputStream inputStream = null;
Binary image = null;
try
{
inputStream = new URL(viewItemURL).openStream();;
byte bytes[] = new byte[inputStream.available()];
inputStream.read(bytes);
image = new Binary(bytes);
}
catch (final IOException exception)
{
LOGGER.error("", exception);
}
finally
{
IOUtils.closeQuietly(inputStream);
}
return image;
}
viewItemURL is the URL of the image.
Code for saving image in MongoDB
If the problem is with saving images in the database, it occurs in the following method:
protected void saveProductImages(final byte[] aNewProductId, final List<String> aPictureUrls,
final IMongoPersistenceState aPersistenceState) {
final DB db = aPersistenceState.getDb();
final DBCollection productImagesColl = db.getCollection(
MyAppPersistenceAction.COLLECTION_USER_PRODUCT_IMAGES);
for (final String curPictureUrl : aPictureUrls)
{
final Binary imageData = readImage(curPictureUrl);
final Map<String,Object> map = new HashMap<String, Object>();
map.put(FIELD_COLLECTION_USER_PRODUCT_IMAGES_CREATOR_EMAIL, CREATOR_EMAIL);
map.put(FIELD_COLLECTION_USER_PRODUCT_IMAGES_PRODUCT_ID, aNewProductId);
map.put(FIELD_COLLECTION_USER_PRODUCT_IMAGES_DATA, imageData);
final String fileName = extractFileName(curPictureUrl);
map.put(FIELD_COLLECTION_USER_PRODUCT_IMAGES_FILE_NAME, fileName);
map.put(FIELD_COLLECTION_USER_PRODUCT_IMAGES_MIME_TYPE, getMimeType(fileName));
map.put(FIELD_COLLECTION_USER_PRODUCT_IMAGES_IS_DELETED, Boolean.FALSE);
productImagesColl.insert(WriteConcern.SAFE, createRecordObject(map));
}
}
Your readImage() method has a major bug:
byte bytes[] = new byte[inputStream.available()];
The InputStream#available() doesn't do what you think it does. It doesn't return the total content length which is what the remainder of the code is expecting. It returns the amount of bytes available for reading without blocking all other threads (i.e. bytes which are currently already put in hardware buffer). This totally explains why you get only that part of the image to display.
No need to be ashamed. Practically all Java starters make the same mistake. The right way to read an InputStream fully is to invoke any read() method on it as long as until it returns -1 indicating EOF (end of file). You can find a bunch of examples and utility library shortcuts in this related question: Convert InputStream to byte array in Java.
Here's a full rewrite of readImage() method doing the right thing, making use of IOUtils which you appear to already have at your hands (and Java 7's try-with-resources with AutoCloseable):
protected Binary readImage(final String viewItemURL) {
try (InputStream inputStream = new URL(viewItemURL).openStream()) {
return new Binary(IOUtils.toByteArray(inputStream));
}
catch (final IOException exception) {
LOGGER.error("", exception);
return null;
}
}
I'm trying insert a download in my webApplication.
First of all the page which contains the form where there is the is on
citizen/createparty.xhtml
And the folder where i'd like to upload the file is
partysymbols/ ..
Then i show to you the XHTML code:
<h:form enctype="multipart/form-data">
<p:fileUpload value="#{partyCreationBean.file}" mode="simple" />
<p:commandButton value="Submit" ajax="false" actionListener="#{partyCreationBean.upload}" />
Then the partyCreationBean
private UploadedFile file;
public UploadedFile getFile() {
return file;
}
public void setFile(UploadedFile file) {
this.file = file;
}
....
public void handleFileUpload() {
File target = new File(FacesContext.getCurrentInstance().getApplication().get);
System.out.println("handle file upload: " + file.getFileName());
InputStream inputStream;
try {
inputStream = file.getInputstream();
OutputStream out = new FileOutputStream(file.getFileName()
);
int read = 0;
byte[] bytes = new byte[1024];
while ((read = inputStream.read(bytes)) != -1) {
out.write(bytes, 0, read);
}
inputStream.close();
out.flush();
out.close();
System.out.println("done");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void upload() {
if(file != null) {
FacesMessage message = new FacesMessage("Succesful", file.getFileName() + " is uploaded.");
FacesContext.getCurrentInstance().addMessage(null, message);
handleFileUpload();
}
}
In my web.xml
<filter>
<filter-name>PrimeFaces FileUpload Filter</filter-name>
<filter-class>
org.primefaces.webapp.filter.FileUploadFilter
</filter-class>
<init-param>
<param-name>thresholdSize</param-name>
<param-value>51200</param-value>
</init-param>
<init-param>
<param-name>uploadDirectory</param-name>
<param-value>partysymbols</param-value>
</init-param>
</filter>
The problem is that I reach the
System.out.println("done")
but I have no idea of where the file is uploaded.
then also, if i understood well the "uploadDirectory" parameter in the web.xml is not to set the directory where the file is setted.
I don't really understand how to do this stuff, also because it's first time that i work for a webapplication, and i use glassfish, and i have no idea about how the file system should work... I mean... i don't know where in reality are the pages and all the stuff... i just know where they are inside eclipse :/
Thankyou a lot in advance
Samuele
I guess there is an error in your handleFileUpload() method:
The line
OutputStream out = new FileOutputStream(file.getFileName());
should probably be:
OutputStream out = new FileOutputStream(target.getAbsolutePath() + file.getFileName());
This should also be the path where the file finally is stored, you can print it with:
System.out.println("Path: " + target.getAbsolutePath() + file.getFileName());
The line where the target var is initialized in your code seems to miss something but I guess it retrieves the uploadDirectory param from the web.xml.
You may have to set up an absolute path for the uploadDirectory param like "c:\\tmp\\partysymbols" (Windows) or "/home/user/partysymbols" (Unix) in your web.xml.
See also:
Where does p:fileUpload save my file?
j2ee primefaces fileupload file saving destination
I'm using Primefaces
p:fileDownload
to download a file which is not in class path.
So I'm passing FileInputStream as parameter to DefaultStreamedContent.
Every thing works fine when my bean is kept at #SessionScoped...,
But
java.io.NotSerializableException: java.io.FileInputStream
is thrown when I keep my bean in #Viewscoped.
My Code:
DownloadBean.java
#ManagedBean
#ViewScoped
public class DownloadBean implements Serializable {
private StreamedContent dFile;
public StreamedContent getdFile() {
return dFile;
}
public void setdFile(StreamedContent dFile) {
this.dFile = dFile;
}
/**
* This Method will be called when download link is clicked
*/
public void downloadAction()
{
File tempFile = new File("C:/temp.txt");
try {
dFile = new DefaultStreamedContent(new FileInputStream(tempFile), new MimetypesFileTypeMap().getContentType(tempFile));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
index.xhtml
<h:form>
<h:commandLink action="#{downloadBean.downloadAction}">
Download
<p:fileDownload value="#{downloadBean.dFile}"/>
</h:commandLink>
</h:form>
Isn't there any method to make it work?
The NotSerializableException is thrown because the view scope is represented by the JSF view state which can in turn be serialized to HTTP session in case of server side state saving or a HTML hidden input field in case of client side state saving. The FileInputStream can in no way be represented in a serialized form.
If you absolutely need to keep the bean view scoped, then you should not be declaring StreamedContent as an instance variable, but instead recreate it in the getter method. True, doing business logic in a getter method is usually frowned upon, but the StreamedContent is a rather special case. In the action method, you should then only prepare serializable variables which are later to be used during DefaultStreamedContent construction.
#ManagedBean
#ViewScoped
public class DownloadBean implements Serializable {
private String path;
private String contentType;
public void downloadAction() {
path = "C:/temp.txt";
contentType = FacesContext.getCurrentInstance().getExternalContext().getMimeType(path);
}
public StreamedContent getdFile() throws IOException {
return new DefaultStreamedContent(new FileInputStream(path), contentType);
}
}
(note that I also fixed your way to get the content type; you have this way much more freedom to configure mime types via <mime-mapping> entries in web.xml)
The <p:graphicImage> has by the way exactly the same problem with StreamedContent. See also among others Display dynamic image from database with p:graphicImage and StreamedContent.
#BalusC, for p:fileDownload, is there a way to offload the creation of the StreamedContent to another object which could then be called directly from JSF? Similar to the way you offload p:graphicImage here. If so what would be the scope of this special object? I'm guessing RequestScoped since there would be no connection between initDownload and getDownload. ApplicationScoped would not be able to keep track of all downloads within a single session, right? I also wonder if creating a new Apache FOP object in every Request is too expensive?
Here's an example:
jsf:
<h:commandButton value="print/download" action="#{streamhelper.initDownload()}">
<p:fileDownload value="#{streamhelper.download}"/>
<f:param name="html" value="#{bean.html}" />
<f:param name="idNum" value="#{bean.idNum}" />
</h:commandButton>
special object:
#Named("streamhelper") #RequestScoped #Getter #Setter #Slf4j
public class StreamedContentHelper
{
#PostConstruct #SneakyThrows({NamingException.class})
public void init(){
fop = util.getLocator().getObject(util.getLocator().prependPortableName(FOPEngineImpl.class.getSimpleName()));
}
public void initDownload() throws Exception
{
FacesContext context = FacesContext.getCurrentInstance();
log.trace("context PhaseID: {}", context.getCurrentPhaseId());
String html = context.getExternalContext().getRequestParameterMap().get("html");
String idNum = context.getExternalContext().getRequestParameterMap().get("idNum");
byte[] attachBytes = fop.getPDFBytes(html);
InputStream stream = new ByteArrayInputStream(attachBytes);
stream.mark(0); //remember to this position!
String filename = String.format("%s-download.pdf", loadNum);
download = new DefaultStreamedContent(stream, "application/pdf", filename);
}
private StreamedContent download;
private FOPEngineLocal fop;
private #Inject Util util;
}
I'm trying to dynamically display an image in primefaces using the p:graphicImage tag as follows:
<p:graphicImage value="#{submissionBean.contestImage}">
<f:param name="imageName"
value="#{contestBean.createContest.submissions[0].fileName}" />
</p:graphicImage>`
The managed bean is as follows:
#ManagedProperty("#{param.imageName}")
private String imageName;
public String getImageName()
{
return imageName;
}
public void setImageName(String imageName)
{
this.imageName = imageName;
}
private StreamedContent contestImage;
public StreamedContent getContestImage()
{
FacesContext context = FacesContext.getCurrentInstance();
if (imageName == null)
imageName = Constants.SUBMISSION_FILE_DIR + "/" + "sacxzx_asdsdaas_icon.png";
if (context.getRenderResponse())
{
// So, we're rendering the view. Return a stub StreamedContent so
// that it will generate right URL.
return new DefaultStreamedContent();
}
else
{
return new DefaultStreamedContent(this.getClass().getResourceAsStream(Constants.SUBMISSION_FILE_DIR + "/" + imageName));
}
}
I'm always getting the error of "SEVERE: Error in streaming dynamic resource."
Checking the URL for the image seems just fine:
http://localhost:8080/mashup/javax.faces.resource/dynamiccontent.xhtml?ln=primefaces&pfdrid=pfdrid_4290aa0c-8eef-45ea-a281-638e460e33bf&imageName=sacxzx_asdsdaas_icon.png
Any idea why this is?
Thanks!
Should be SessionScoped. As method getContestImage() is called multiple times during page processing, it is better to create the stream only once.