Glassfish 4, JSF 2.2 and PrimeFaces FileUploadEvent not working together - file-upload

After upgrading to GlassFish 4 and JSF 2.2 Primefaces FileUploadEvent stop working. With JSF 2.1 it was working with no problem. Everything is working fine except file uploading. Is there something that I am missing?
GlassFish 4
JSF 2.2
PrimeFaces 3.4.2 and 3.5
Commons io version: 2.4
Commons fileupload version: 1.3
Controller side
public void handleFileUpload(FileUploadEvent event) {
System.out.println("HandleFileUpload");
byte[] file = event.getFile().getContents();
newFieldset.setData(file);
FacesMessage msg = new FacesMessage("Succesful", event.getFile().getFileName() + " is uploaded.");
FacesContext.getCurrentInstance().addMessage(null, msg);
}
View
<h:form enctype="multipart/form-data">
<p:fieldset legend="Create new feed" toggleable="true" collapsed="true" >
<p:fileUpload fileUploadListener="#{adminHomeController.handleFileUpload}" style="margin-top: 20px;"
mode="advanced"
update="messages"
sizeLimit="1000000"
multiple="false"
allowTypes="/(\.|\/)(gif|jpe?g|png)$/"/>
<p:inputText label="Baslik" style="margin-top: 20px;" required="true" value="#{adminHomeController.newFieldset.legend}" />
<p:editor style="margin-top: 20px;"
value="#{adminHomeController.newFieldset.content}" />
<p:commandButton style="margin-top: 20px;" value="#{msg['common.save']}" update="messages" icon="ui-icon-disk" actionListener="#{adminHomeController.saveFieldset()}"/>
</p:fieldset>
<p:growl id="messages" showDetail="true"/>
</h:form>

I was finally able to figure it out. Commons-fileuploads method parseRequest(httpServletRequest) tries to read the request's inputStream. Since the container already read it, it is empty. So what can be done to solve this? The answer is a bit more complicated than I initially thought it would be. First you will need your own FileUploadFilter which could look like this:
public class FileUploadFilter implements Filter
{
private final static Logger LOGGER = LoggerFactory.getLogger(FileUploadFilter.class);
/*
* (non-Javadoc)
*
* #see javax.servlet.Filter#init(javax.servlet.FilterConfig)
*/
#Override
public void init(FilterConfig filterConfig) throws ServletException
{
}
/*
* (non-Javadoc)
*
* #see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest,
* javax.servlet.ServletResponse, javax.servlet.FilterChain)
*/
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException
{
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
boolean isMultipart = (httpServletRequest.getContentType() == null) ? false : httpServletRequest.getContentType().toLowerCase().startsWith("multipart/");
if (isMultipart)
{
MultipartRequest multipartRequest = new MultipartRequest(httpServletRequest);
LOGGER.info("File upload request parsed succesfully, continuing with filter chain with a wrapped multipart request");
filterChain.doFilter(multipartRequest, response);
}
else
{
filterChain.doFilter(request, response);
}
}
/*
* (non-Javadoc)
*
* #see javax.servlet.Filter#destroy()
*/
#Override
public void destroy()
{
LOGGER.info("Destroying UploadFilter");
}
Next: Register this filter in your web.xml and remove/replace the Primefaces filter. This should look something like this:
<filter>
<filter-name>FileUpload Filter</filter-name>
<filter-class><YourPackage>.FileUploadFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>FileUpload Filter</filter-name>
<servlet-name>Faces Servlet</servlet-name>
</filter-mapping>
Unfortunately thats not it. You will need your own MultipartRequest since you have to assemble the list of FileItems by yourself. But Stop. We have to work with the javax.servlet.Part classes which are not compatible with the FileItem. So i wrote a new class which bridges these two. You can find this class here: http://pastebin.com/JcfAYjey
The last piece of the puzzle is the mentioned MultipartRequest which links the PartItem and the FileUploadFilter. I took this class from the Primefaces-Repository and changed it according to out needs (see http://pastebin.com/Vc5h2rmJ). The difference is between lines 47 and 57.
So what do you have to do:
1. Create the three classes FileUploadFilter, MultipartRequest and PartItem
2. Register the FileUploadFilter in your web.xml
3. Enjoy!
PLEASE NOTE: This is not intended as a solve-all-problems solution but a merely a direction you may take in further implementations. The MultipartRequest for example will only work for parts with content-type image/*. You may need to change this.
Feel free to change the code ;) Hope it helps!
EDIT: I forgot to mention one important step. You will additionally need your Own FileIUploadRenderer. The one Primefaces implemented uses an instanceof check to find the MultipartRequest. Since you are now using a different one the import has to be changed. The rest of the class can stay the same (http://pastebin.com/rDUkPqf6). Don't forget to register it inside of your faces-config.xml :
<render-kit>
<renderer>
<component-family>org.primefaces.component</component-family>
<renderer-type>org.primefaces.component.FileUploadRenderer</renderer-type>
<renderer-class><YourPackage>.FileUploadRenderer</renderer-class>
</renderer>
</render-kit>

Answer lies in UploadFile getInputstream() method. Don't rely on getContents() method.
This is my simple solution which worked with the below dependencies in glassfish 4
Primefaces 4.0.RC1
jsf 2.2
commons-fileupload 1.3
private byte[] getFileContents(InputStream in) {
byte[] bytes = null;
try {
// write the inputStream to a FileOutputStream
ByteArrayOutputStream bos = new ByteArrayOutputStream();
int read = 0;
bytes = new byte[1024];
while ((read = in.read(bytes)) != -1) {
bos.write(bytes, 0, read);
}
bytes = bos.toByteArray();
in.close();
in = null;
bos.flush();
bos.close();
bos = null;
logger.debug("New file created!");
} catch (IOException e) {
System.out.println(e.getMessage());
}
return bytes;
}
getFileContents(getFile().getInputstream());

Try to delete beans.xml (CDI configuration file) and use JSF beans.

I saw on PrimeFaces blog that full JSF 2.2 support will be as of version 4.0.

See 3.5 is missing dependency - so won't launch

I think it's a commons-fileupload issue. When I debug through the code, the PrimeFaces' UploadFilter triggers correctly the commons-fileupload's FileUploadBase.parseRequest method (identically flow when I use GlassFish 3.1.22 or GlassFish 4), but the check on FileItemIterator.hasNext returns false.

Related

NullPointerException when using CXF SSE by #Context SseEventSink

I am trying to use JAX-RS SSE(Server-sent event) feature in Tomcat 8.0.45 and Apache CXF 3.2.8, but always get a NullPointerException when send the GET request from browser via javascript new EventSource(url). Following is the code:
#Path("/sse")
public class SSEService {
#GET
#Path("/test")
#Produces(MediaType.SERVER_SENT_EVENTS)
public void test(#Context Sse sse, #Context SseEventSink eventSink) {
try (SseEventSink sink = eventSink) {
sink.send(sse.newEvent("Hello world"));
}
}
}
The exception:
Caused by: java.lang.NullPointerExecption
at org.apache.cxf.jaxrs.impl.AsyncResponseImpl.initContinuation(AsyncResponseImpl.java:306)
at org.apache.cxf.jaxrs.impl.AsyncResponseImpl.<init>(AsyncResponseImpl.java:68)
at org.apache.cxf.jaxrs.sse.SseEventSinkContextProvider.createContext(SseEventSinkContextProvider.java:47)
......
Thanks for your help!

JSF 2.2.10 file upload not working [duplicate]

This question already has an answer here:
Upgrade JSF / Mojarra in JBoss AS / EAP / WildFly
(1 answer)
Closed 5 years ago.
Issue: Action method and setter for file not getting called on file upload.
I did see the link for JSF 2.2 not working, but it is over 4 years old and I thought the problem should have been resolved. I am posting this since I am facing it today!
I am using JSF 2.2.10, JBoss 6.4; I have mojarra set up in JBoss config as follows: (in \modules\system\layers\base\org\jboss\weld\core\main and \modules\system\layers\base\org\jboss\as\weld\main)
I have set up my xhtml and Controller as follows. Would greatly appreciate if you could point out what I am missing. Been stuck with this for more than a day now!
<h:form id="massUpload" enctype="multipart/form-data">
<div class="col-xs-3 col-md-3">
<h:inputFile id="file" value="#{controller.uploadedFile}" />
<h:commandButton value="Upload"
action="#{controller.massUploadBranchGLInfoViaFile}"/>
</div>
</h:form>
Controller As follows:
#Named("controller")
#ViewScoped
public class MyController
extends AccessController
implements Serializable
{
private Part uploadedFile;
public String massUploadBranchGLInfoViaFile() throws IOException {
InputStream stream = uploadedFile.getInputStream();
addSuccessInfoToFlash("update-gl-success");
return "Success";
}
public void setUploadedFile(Part file){
this.uploadedFile = file;
}
public Part getUploadedFile(){
return this.uploadedFile;
}
}
Thank you very much
Karthik
Found (at least part of) the issue: Had to add the multipart-config to servlet configuration in my web.xml. That resolved calling the action and set methods. Am getting a NULLPointerException now. But one issue at a time I guess :)

How can i add response header to a pdf in CQ5

I am trying add canonical tags to PDF and for that i have to update response header when PDF is loaded. I was able to add header for cq:page very easily:
#SlingServlet(
resourceTypes = "cq:Page",
extensions = "html",
methods = "GET")
#Properties({
#Property(name = "service.description", value = "Servlet to handle all incoming widget modification")
})
public class canocalizePDF extends SlingAllMethodsServlet {
private static final long serialVersionUID = 1L;
#Override
protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) throws ServletException, IOException {
response.addHeader(“canonical", “test");
}
#Override
protected void doPost(SlingHttpServletRequest request, SlingHttpServletResponse response) throws ServletException, IOException {
}
}
But when i try to same for PDF, it is not working. I have tried dam:Asset, dam:AssetContent as resourceTypes, but nothing seems to be working.
Any help would be great.
Thanks,
Vishal
The servlet that you've written is not handling your asset requests. If you want to handle this in AEM, you will need to override the OOTB AEM's AssetDownloadServlet with your own servlet implementation. You can then add the canonical link header in your servlet response.
How to override this is explained in detail in this blog post. They've also included a link to sample code for this customization.
However, if you have a webserver (e.g. Apache) in your setup, you should really handle this there. This is shown in this Moz blog post. Moz is the pinnacle of SEO best practices. I will recommend that.

JAX-RS Client API async request

I am trying to use the JAX-RS Client API to request a resource through HTTP GET, by using the following code: (I used jersey-client v2.12 and also resteasy-client v3.0.8.Final to test the implementation)
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.InvocationCallback;
public class StackOverflowExample {
public static void main(String[] args) {
Client client = ClientBuilder.newClient();
client.target("http://example.com/").request().async().get(new InvocationCallback<String>() {
#Override
public void completed(String s) {
System.out.println("Async got: " + s);
}
#Override
public void failed(Throwable throwable) {
System.out.println("Async failure...");
}
});
}
}
As I expected the String is printed almost immediately. But the process keeps running about one minute, although there isn't any code that should be executed.
The JAX-RS spec just says that we should use the InvocationCallback and nothing else that matters to my issue. But even if I use a Future the same effect happens. I also tested, if this has something to do with a timeout, which was very unlikely and wrong. The debugger shows that there are some threads running namely DestroyJavaVM and jersey-client-async-executor-0 or pool-1-thread-1 in the case of resteasy.
Do you have any idea what is going wrong here?
It is allways helpful to consult the JavaDoc. Concerning my issue it says:
Clients are heavy-weight objects that manage the client-side communication infrastructure. Initialization as well as disposal of a Client instance may be a rather expensive operation. It is therefore advised to construct only a small number of Client instances in the application. Client instances must be properly closed before being disposed to avoid leaking resources.
If I close the client properly everything is working as expected.
public class StackOverflowExample {
public static void main(String[] args) {
Client client = ClientBuilder.newClient();
// request here
client.close();
}
}

Notifying user download has finished.

Hi i have a command button.
I am using jsf 1.12 and tomahwak. I also am using jquery on client side.
<h:commandButton type="submit" value="Download Receipt"
onclick="refresh();"
id="downloadDocument"
actionListener="#{transactionPage.downloadReceipt}"
immediate="true"
/>
My jsf backing bean function
public void downloadReciept(final ActionEvent event) {
try{
DocManager docManager = new DocManager();
docManager.printDocs();
}catch (Exception e) {
log.error("Fail to download document!", e);
}
}
print docs would just create a file and stream it by setting the content-type, response, etc.
File sourceFile = createDoc();
Url url = sourceFile.toURI().toURL();
streamDoc(url);
I want to be able to display a message when downloading is starting and message when it finished
Hi thanks found my solution.
I change to commandLink than
set the cookie in backend and use jquery's file download