Question

In my application I use JSF2.2 and Primefaces 4.0. I have a functionality that uploads the new image and needs to update the existing one. Sometimes after new image is uploaded, the old one might still be shown, it may happen because of cache or re-rendering problems. I can see that this especially usual happens with high resolution images like 2500x1600. This can be reproduced in IE, Chrome and Firefox. Here are my Primefaces components:

<h:panelGroup id="mr-img-panel">
    <h:outputLink id="mr-image-link" target="_blank" process="@this"
                  value="#{myBean.image}"
                  rendered="#{myBean.image ne null}">
        <p:graphicImage id="mr-image" value="#{myBean.image}"
                        cache="false"
                        title="Title" styleClass="image-preview" />
    </h:outputLink>
</h:panelGroup>

<h:panelGroup styleClass="upload-view">
    <p:fileUpload id="mr-upload"
                  fileUploadListener="#{myBean.handleFileUpload}"
                  mode="advanced"
                  auto="true"
                  label="Upload new image"
                  dragDropSupport="true"
                  invalidFileMessage="#{msg['msg.invalid.filetype']}"
                  messageTemplate=" "
                  invalidSizeMessage="#{msg['msg.invalid.filesize']}"
                  update="mr-upload-messages, mr-img-panel"
                  sizeLimit="2097152"
                  allowTypes="/(\.|\/)(gif|jpe?g|png)$/"
                  styleClass="upload-view-button"
                  oncomplete="setTimeout(function() { $('[id$=mr-upload-messages]').hide(1000); }, 2000);">
        <f:attribute name="someId" value="#{some.id}" />
    </p:fileUpload>

    <p:messages id="mr-upload-messages" showDetail="true" showSummary="false" closable="true"/>

At first, I thought that this can happen because of cache problems, so I have written a cache control listener:

public class CacheControlPhaseListener implements PhaseListener {


    @Override
    public void afterPhase(final PhaseEvent event) {

    }

    @Override
    public void beforePhase(final PhaseEvent event) {
        final FacesContext facesContext = event.getFacesContext();
        final HttpServletResponse response = (HttpServletResponse) facesContext
                .getExternalContext().getResponse();
        response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); // HTTP 1.1.
        response.setHeader("Pragma", "no-cache"); // HTTP 1.0.
        // some date in the past
        response.setDateHeader("Expires", 0); // Proxies.
    }

    @Override
    public PhaseId getPhaseId() {
        return PhaseId.RENDER_RESPONSE;
    }
}

But that didn't help. I have tried few different techniques and with some of them I had problem, described in HERE. And as was told in this SOLUTION I wrote this FileUploadRenderer:

public class CustomFileUploadRenderer extends FileUploadRenderer {

    @Override
    public void decode(final FacesContext context, final UIComponent component) {
        if (context.getExternalContext().getRequestContentType().toLowerCase().startsWith("multipart/")) {
            super.decode(context, component);
        }
    }
}

And here is what I added to faces-config.xml for these classes:

<lifecycle>
    <phase-listener id="nocache">com.example.CacheControlPhaseListener</phase-listener>
</lifecycle>

<render-kit>
    <renderer>
        <component-family>org.primefaces.component</component-family>
        <renderer-type>org.primefaces.component.FileUploadRenderer</renderer-type>
        <renderer-class>com.example.CustomFileUploadRenderer</renderer-class>
    </renderer>
</render-kit>

But the problem still exists. After uploading the new image, the old one is not refreshed by AJAX, it can only be seen after refreshing the page.

Was it helpful?

Solution

In case somebody needs this, seems that updating to Primefaces 5.0 has fixed this issue for me.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top