2016-12-12 1 views
0

J'ai un problème de code pour télécharger le fichier depuis le serveur. Il ressemble à ceci:Glassfish 3.1.2.2 et OutOfMemoryError

response.reset(); 
    response.setContentType("audio/vnd.wave"); 
    File file = new File(filename); 
    FileInputStream stream = new FileInputStream(file); 
    long toWrite = file.length(); 
    filename = filename.substring(filename.lastIndexOf(File.separator) + 1, filename.length()); 
    response.setHeader("Content-disposition", "attachment; filename=\"" + filename + "\""); 
    //response.setHeader("Content-Length", String.valueOf(toWrite)); 
    response.setContentLength((int)toWrite); 
    response.getOutputStream().flush(); 
    response.flushBuffer(); 
    //Files.copy(file.toPath(), response.getOutputStream()); 
    byte data[] = new byte[1024*1024]; 
    int len; 
    while ((len = stream.read(data)) > 0) { 
     response.getOutputStream().write(data, 0, len); 
     response.getOutputStream().flush(); 
     response.flushBuffer(); 
     toWrite -= len; 
     System.out.println("left="+toWrite+" "+w.getBufferSize()+" "+w.getBytes().length); 
    } 
    stream.close(); 
    response.getOutputStream().flush(); 
    response.getOutputStream().close(); 
    context.responseComplete(); 

Pour les fichiers plus de 1 Go, il se termine par oome (celui-ci a environ 1,4 Go):

[#|2016-12-12T14:41:40.350+0100|INFO|glassfish3.1.2|javax.enterprise.system.std.com.sun.enterprise.server.logging|_ThreadID=99;_ThreadName=Thread-2;|left=389066752 8192 10737 
41824|#] 

[#|2016-12-12T14:41:41.237+0100|WARNING|glassfish3.1.2|javax.enterprise.resource.webcontainer.jsf.lifecycle|_ThreadID=99;_ThreadName=Thread-2;|#{showContractBean.downloadReco 
rding(item2.recFile)}: java.lang.OutOfMemoryError: Java heap space 
javax.faces.FacesException: #{showContractBean.downloadRecording(item2.recFile)}: java.lang.OutOfMemoryError: Java heap space 
     at com.sun.faces.application.ActionListenerImpl.processAction(ActionListenerImpl.java:118) 
     at javax.faces.component.UICommand.broadcast(UICommand.java:315) 
     at javax.faces.component.UIData.broadcast(UIData.java:1093) 
     at javax.faces.component.UIViewRoot.broadcastEvents(UIViewRoot.java:794) 
     at javax.faces.component.UIViewRoot.processApplication(UIViewRoot.java:1259) 
     at com.sun.faces.lifecycle.InvokeApplicationPhase.execute(InvokeApplicationPhase.java:81) 
     at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101) 
     at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118) 
     at javax.faces.webapp.FacesServlet.service(FacesServlet.java:593) 
     at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1550) 
     at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:343) 
     at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:217) 
     at org.apache.myfaces.webapp.filter.ExtensionsFilter.doFilter(ExtensionsFilter.java:357) 
     at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:256) 
     at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:217) 
     at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:279) 
     at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175) 
     at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:655) 
     at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:595) 
     at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:161) 
     at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:331) 
     at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:231) 
     at com.sun.enterprise.v3.services.impl.ContainerMapper$AdapterCallable.call(ContainerMapper.java:317) 
     at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:195) 
     at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:860) 
     at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:757) 
     at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:1056) 
     at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:229) 
     at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:137) 
     at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:104) 
     at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:90) 
     at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:79) 
     at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:54) 
     at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:59) 
     at com.sun.grizzly.ContextTask.run(ContextTask.java:71) 
     at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:532) 
     at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:513) 
     at java.lang.Thread.run(Thread.java:745) 
Caused by: javax.faces.el.EvaluationException: java.lang.OutOfMemoryError: Java heap space 
     at javax.faces.component.MethodBindingMethodExpressionAdapter.invoke(MethodBindingMethodExpressionAdapter.java:102) 
     at com.sun.faces.application.ActionListenerImpl.processAction(ActionListenerImpl.java:102) 
     ... 37 more 
Caused by: java.lang.OutOfMemoryError: Java heap space 
     at java.util.Arrays.copyOf(Arrays.java:2271) 
     at java.io.ByteArrayOutputStream.grow(ByteArrayOutputStream.java:118) 
     at java.io.ByteArrayOutputStream.ensureCapacity(ByteArrayOutputStream.java:93) 
     at java.io.ByteArrayOutputStream.write(ByteArrayOutputStream.java:153) 
     at org.apache.myfaces.webapp.filter.ExtensionsResponseWrapper$MyServletOutputStream.write(ExtensionsResponseWrapper.java:141) 
     at com.agreeya.telekonferencje.web.ShowContractBean.downloadRecording(ShowContractBean.java:1569) 
     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) 
     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
     at java.lang.reflect.Method.invoke(Method.java:606) 
     at javax.el.BeanELResolver.invokeMethod(BeanELResolver.java:779) 
     at javax.el.BeanELResolver.invoke(BeanELResolver.java:528) 
     at javax.el.CompositeELResolver.invoke(CompositeELResolver.java:257) 
     at com.sun.el.parser.AstValue.invoke(AstValue.java:248) 
     at com.sun.el.MethodExpressionImpl.invoke(MethodExpressionImpl.java:302) 
     at com.sun.faces.facelets.el.TagMethodExpression.invoke(TagMethodExpression.java:105) 
     at javax.faces.component.MethodBindingMethodExpressionAdapter.invoke(MethodBindingMethodExpressionAdapter.java:88) 
     at com.sun.faces.application.ActionListenerImpl.processAction(ActionListenerImpl.java:102) 
     at javax.faces.component.UICommand.broadcast(UICommand.java:315) 
     at javax.faces.component.UIData.broadcast(UIData.java:1093) 
     at javax.faces.component.UIViewRoot.broadcastEvents(UIViewRoot.java:794) 
     at javax.faces.component.UIViewRoot.processApplication(UIViewRoot.java:1259) 
     at com.sun.faces.lifecycle.InvokeApplicationPhase.execute(InvokeApplicationPhase.java:81) 
     at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101) 
     at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118) 
     at javax.faces.webapp.FacesServlet.service(FacesServlet.java:593) 
     at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1550) 
     at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:343) 
     at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:217) 
     at org.apache.myfaces.webapp.filter.ExtensionsFilter.doFilter(ExtensionsFilter.java:357) 
     at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:256) 
     at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:217) 

serveur dispose d'une mémoire fixe de 4 Go pour le domaine, NewRatio est réglé sur 2 (la valeur par défaut).
Comme vous pouvez le voir, je l'ai essayé jusqu'à présent:
1. Plus de mémoire pour GlassFish
2. réseau de tampon plus petit/plus grand
3. Réponse Flush et flux de sortie après chaque écriture
4. Set ContentLength à déposer size
5. Copier les flux directement (FileStream -> OutputStream)
6. Définissez Content-Length directement comme en-tête
sans chance. La sortie devrait être streamée mais ce n'est pas le cas.

Y at-il autre chose que dois-je essayer?

Pour l'instant, la mise à jour de GF à 4 n'est pas possible, j'ai peur.

|| EDIT

Enfin, il fonctionne comme prévu:

FacesContext context = FacesContext.getCurrentInstance(); 
HttpServletResponse response = (HttpServletResponse) context.getExternalContext().getResponse(); 
ExtensionsResponseWrapper responseWrapper = (ExtensionsResponseWrapper)response; 
HttpServletResponse delegateResponse = responseWrapper.getDelegate(); 

try { 
    response.reset(); 
    response.setContentType("audio/vnd.wave"); 
    File file = new File(filename); 
    long toWrite = file.length(); 
    filename = filename.substring(filename.lastIndexOf(File.separator) + 1, filename.length()); 
    response.setHeader("Content-disposition", "attachment; filename=\"" + filename + "\""); 
    response.setHeader("Content-Length", String.valueOf(toWrite)); 
    response.setContentLength((int)toWrite); 
    ServletOutputStream out = delegateResponse.getOutputStream(); 
    out.flush(); 
    response.flushBuffer(); 
    Files.copy(file.toPath(), out); 
    response.getOutputStream().flush(); 
    response.getOutputStream().close(); 
    context.responseComplete(); 
} catch (IOException ex) { 
    log.log(Level.SEVERE, ex.getMessage(), ex); 
} 

Répondre

0

La raison en est que la classe ExtensionsResponseWrapper écrit la sortie dans un ByteArrayOutputStream, voir le code here.

Je ne sais pas s'il s'agit de la réponse MyFaces standard, ou si elle est utilisée en raison d'une certaine configuration dans votre application/GlassFish. Passez en revue le code qui crée/reçoit l'objet response.

+0

On dirait que ByteArrayOutputStream.flush() est non-op et il n'y a aucun moyen de le rendre en streaming. Et il me manquait [ce post] (http://stackoverflow.com/questions/24505635/buffering-response-in-heap-space-cause-problems-for-large-files). Merci pour l'aide. – 13Homer