[ 
https://issues.apache.org/jira/browse/CXF-4356?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13289477#comment-13289477
 ] 

Gonçalo Rodrigues commented on CXF-4356:
----------------------------------------

I found a workaround. If we keep the instance of the created 
{{FileInputStream}} in {{CachedOutputStream#getInputStream()}}, it prevents the 
GC to collect the {{FileInputStream}} instance too early and therefore to 
delete the temp file.

The temp file is still deleted but "later".

The {{CachedOutputStream}} (v.2.6) code change:
{code:java}
private FileInputStream fileInputStream; // <-- The instance we keep

public InputStream getInputStream() throws IOException {
    flush();
    if (inmem) {
        if (currentStream instanceof LoadingByteArrayOutputStream) {
            return ((LoadingByteArrayOutputStream) 
currentStream).createInputStream();
        } else if (currentStream instanceof ByteArrayOutputStream) {
            return new ByteArrayInputStream(((ByteArrayOutputStream) 
currentStream).toByteArray());
        } else if (currentStream instanceof PipedOutputStream) {
            return new PipedInputStream((PipedOutputStream) currentStream);
        } else {
            return null;
        }
    } else {
        try {
            fileInputStream = new FileInputStream(tempFile) { // <-- The 
instance we keep
                public void close() throws IOException {
                    super.close();
                    maybeDeleteTempFile(this);
                }
            };
            streamList.add(fileInputStream);
            return fileInputStream;
        } catch (FileNotFoundException e) {
            throw new IOException("Cached file was deleted, " + e.toString());
        }
    }
}
{code} 
                
> Temp file deleted before returning the stream in CachedOutputStream
> -------------------------------------------------------------------
>
>                 Key: CXF-4356
>                 URL: https://issues.apache.org/jira/browse/CXF-4356
>             Project: CXF
>          Issue Type: Bug
>    Affects Versions: 2.5, 2.6
>            Reporter: Gonçalo Rodrigues
>
> I’m implementing a web service to upload files (from 120 Kb to 1 Mb). Most of 
> the time everything works fine, but sometimes (randomly) the uploaded file is 
> empty (size == 0) in the target platform. 
> After some debugging I found that the problem comes from the temp file 
> created by the {{CachedOutputStream}} that is deleted during the process of 
> getting the cached stream. In fact, {{maybeDeleteTempFile}} is called before 
> {{getInputStream}} which returns an empty {{LoadingByteArrayOutputStream}}. 
> The {{finalize}} method of {{FileInputStream}} calls its {{close}} method 
> which is overridden in {{CachedOutputStream#getInputStream}} to delete the 
> temp file.
> I tried to synchronize all the methods dealing with {{tempFile}} but it 
> didn’t resolve my problem.
> The stack: 
> {code}
> Daemon System Thread [Finalizer] (Suspended (breakpoint at line 490 in 
> CachedOutputStream))   
>       CachedOutputStream.maybeDeleteTempFile(Object) line: 490        
>       CachedOutputStream.access$000(CachedOutputStream, Object) line: 43      
>       CachedOutputStream$1.close() line: 469  
>       CachedOutputStream$1(FileInputStream).finalize() line: 381      
>       Finalizer.invokeFinalizeMethod(Object) line: not available [native 
> method]      
>       Finalizer.runFinalizer() line: 83       
>       Finalizer.access$100(Finalizer) line: 14        
>       Finalizer$FinalizerThread.run() line: 160       
> {code} 
> The {{getInputStream}} method: 
> {code:java}
> public InputStream getInputStream() throws IOException {
>       flush();
>       if (inmem) {
>               if (currentStream instanceof LoadingByteArrayOutputStream) {
>                       return ((LoadingByteArrayOutputStream) 
> currentStream).createInputStream();
>               } else if (currentStream instanceof ByteArrayOutputStream) {
>                       return new 
> ByteArrayInputStream(((ByteArrayOutputStream) currentStream).toByteArray());
>               } else if (currentStream instanceof PipedOutputStream) {
>                       return new PipedInputStream((PipedOutputStream) 
> currentStream);
>               } else {
>                       return null;
>               }
>       } else {
>               try {
>                       FileInputStream fileInputStream = new 
> FileInputStream(tempFile) {
>                               public void close() throws IOException {
>                                       super.close();
>                                       maybeDeleteTempFile(this);
>                               }
>                       };
>                       streamList.add(fileInputStream);
>                       return fileInputStream;
>               } catch (FileNotFoundException e) {
>                       throw new IOException("Cached file was deleted, " + 
> e.toString());
>               }
>       }
> }
> {code} 
> The {{maybeDeleteTempFile}} method: 
> {code:java}
> private void maybeDeleteTempFile(Object stream) {
>       streamList.remove(stream);
>       if (!inmem && tempFile != null && streamList.isEmpty() && 
> allowDeleteOfFile) {
>               if (currentStream != null) {
>                       try {
>                               currentStream.close();
>                               postClose();
>                       } catch (Exception e) {
>                               //ignore
>                       }
>               }
>               tempFile.delete();
>               tempFile = null;
>               currentStream = new LoadingByteArrayOutputStream(1024);
>               inmem = true;
>       }
> }
> {code} 

--
This message is automatically generated by JIRA.
If you think it was sent incorrectly, please contact your JIRA administrators: 
https://issues.apache.org/jira/secure/ContactAdministrators!default.jspa
For more information on JIRA, see: http://www.atlassian.com/software/jira


Reply via email to