0

I'm making page using Primefaces with form with ability to ajax-upload image and preview it before submitting whole form.

To achieve this I made dialog outside main form:

<p:dialog id="imageDlg" header="Load Image" modal="true"
          widgetVar="imageUploadWidget">
  <h:form id="imageForm" enctype="multipart/form-data">      
    <p:fileUpload mode="advanced" auto="true" sizeLimit="9999999" 
                  allowTypes="/(\.|\/)(gif|jpe?g|png)$/"
                  fileUploadListener="#{pageBean.imageUploadHandler}">
    </p:fileUpload>
  </h:form>    
</p:dialog>

Inside main form there is p:graphicImage component to display just uploaded image and button to show dialog. Page is backed by view scoped bean (PageBean), but to pass StreamedContent to p:graphicImage value bean should be session or application scoped (because method called multiply times). So I made second application scoped bean (ImageBean) only for this purpose.

<p:graphicImage value="#{imageBean.imageStreamedContent()}"/>
<p:commandButton value="Choose image" type="button" 
                 onclick="imageUploadWidget.show();"/>

Code of ImageBean:

@ApplicationScoped
@ManagedBean
public class ImagesBean implements Serializable {

private byte[] image;
//getter & setter

  public StreamedContent imageStreamedContent() {
      FacesContext context = FacesContext.getCurrentInstance();
      if (context.getCurrentPhaseId() == PhaseId.RENDER_RESPONSE) {
          return new DefaultStreamedContent();
      } else {
          return new DefaultStreamedContent(new ByteArrayInputStream(getImage()));
      }
  }
}

The next part is fileUploadListener. Idea is simple — set corresponding fields of PageBean (to save it later on form submit) of ImageBean (to show it after partial refresh) and update part of main form:

@ManagedBean
@ViewScoped
public class PageBean implements Serializable {

@ManagedProperty(value="#{imageBean}")
ImagesBean imagesBean;
...

public void imageUploadHandler(FileUploadEvent event) {
    getImagesBean().setImage(event.getFile().getContents());
    RequestContext.getCurrentInstance().update("form:tabPanel1");
}

Here comes strange thing. Inside setImage() method everything is OK - field is set, getter works fine. But then page refresh, imageBean.getImage() inside imageBean.imageStreamedContent() returns null.

More accurate — it returns old value, as if setter was never called or was called on another instance of bean. I checked it on another String field: initialized it in ImageBean constructor, in handler invoked setter with another value and refreshed part of main form. Same thing: old value from constructor.

I think, that I'm missing something about bean life cycle or scope specific. Or maybe there is less complicated way to implement this task?

Tloo
  • 21
  • 5
  • is not working? is that your problem??? – Kishor Prakash Sep 18 '13 at 04:32
  • @KishorP yes, visible problem is this. I updated question with imageStreamedContent() method code, if it can be helpful. – Tloo Sep 18 '13 at 08:31
  • You didn't show sufficiently code in order to post an answer, but I believe that your problem has the same grounds as already answered here: http://stackoverflow.com/questions/10073905/display-database-blob-images-in-pgraphicimage-inside-uirepeat/10161878#10161878 – BalusC Sep 18 '13 at 11:38
  • @BalusC what part of code can make problem more clear? Once again, then I replace getImage() method to decoded base64 string and it works as expected. I tried to make 'ImageBean' request scoped instead of application, but had problem of getting value from view scoped `PageBean` then. – Tloo Sep 19 '13 at 11:40
  • Nevemind, it's definitely the same problem. Your bean is view scoped and therefore completely lost when the webbrowser is about to download the image's contents in a separate GET request. Go carefully read that answer. Here's a more detailed one: http://stackoverflow.com/questions/8207325/display-image-from-database-with-pgraphicimage/12452144#12452144 – BalusC Sep 19 '13 at 11:44
  • @BalusC sorry bothering you, but I cant't get it( I understood, that browser will ask bean twice: first for building HTML and second for binary image data itself. But my `imageBean` is application scoped and getter returns different results depending on phaseId. Is there any problem with setting application scoped bean field from view scoped bean method? (updated `ImageBean` code) Thanks a lot. – Tloo Sep 19 '13 at 16:45

1 Answers1

0

There is a problem with using StreamedContent in Primefaces for p:graphicImage and p:media.
You can see Cagatay Civici 's comments on this topic in Primefaces forum here.

In my experience, when I had the slimier(more or less) problem This and This answers by BalusC helped me.

I used a saperate Servlet instead of Managedbean to stream the dynamic content to p:media (in mycase).

Here is my code for your reference(if you need any):

PreviewFileServlet.java

@WebServlet("/PreviewFile")
public class PreviewFileServlet extends HttpServlet {

   public PreviewFileServlet() {
    super();
   }
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        ServletContext context = request.getServletContext();
        String path = request.getParameter("PREVIEW_FILE_PATH");
        logger.info("Received pathe for Preview:"+path);
        try{
        if(null!=path){
            java.io.File f = new java.io.File(path);
            if(f.exists()){
            FileInputStream fin = new FileInputStream(f);
            byte b[] = new byte[(int)f.length()];
            fin.read(b);
            response.setContentLength(b.length);
            response.setContentType(context.getMimeType(path));
            response.getOutputStream().write(b);
            response.getOutputStream().close();
            logger.info("File sent successfully for Preview.");
            }
            else{
                logger.warn("File sepecified by path:-"+path+"-:, NOT found");
            }
        }
        }catch(Exception e){

        }
    }

    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

}

Facelet Code

<p:media value="/PreviewFile?PREVIEW_FILE_PATH=#{fileManager.previewFilePath}" />

Hope this helps. And there are lot of questions on this topic of StreamedContent in stackoverflow itself, go through them once.

Community
  • 1
  • 1
Kishor Prakash
  • 8,011
  • 12
  • 61
  • 92
  • Hm. I'll try, but I don't think, that problem is in `imageStreamedContent()` method. I tried to replace `getImage()` in it to decoded base64 string and it worked as expected. – Tloo Sep 18 '13 at 11:16