mirror of
				https://github.com/owncloud/android-library.git
				synced 2025-10-31 02:17:41 +00:00 
			
		
		
		
	Improved detection of exceptions in uplaods due to local errors
This commit is contained in:
		
							parent
							
								
									78b9aa6247
								
							
						
					
					
						commit
						0bfc385707
					
				| @ -25,6 +25,7 @@ | |||||||
| package com.owncloud.android.lib.common.network; | package com.owncloud.android.lib.common.network; | ||||||
| 
 | 
 | ||||||
| import java.io.File; | import java.io.File; | ||||||
|  | import java.io.FileNotFoundException; | ||||||
| import java.io.IOException; | import java.io.IOException; | ||||||
| import java.io.OutputStream; | import java.io.OutputStream; | ||||||
| import java.nio.ByteBuffer; | import java.nio.ByteBuffer; | ||||||
| @ -58,7 +59,9 @@ public class ChunkFromFileChannelRequestEntity implements RequestEntity, Progres | |||||||
|     Set<OnDatatransferProgressListener> mDataTransferListeners = new HashSet<OnDatatransferProgressListener>(); |     Set<OnDatatransferProgressListener> mDataTransferListeners = new HashSet<OnDatatransferProgressListener>(); | ||||||
|     private ByteBuffer mBuffer = ByteBuffer.allocate(4096); |     private ByteBuffer mBuffer = ByteBuffer.allocate(4096); | ||||||
| 
 | 
 | ||||||
|     public ChunkFromFileChannelRequestEntity(final FileChannel channel, final String contentType, long chunkSize, final File file) { |     public ChunkFromFileChannelRequestEntity( | ||||||
|  |         final FileChannel channel, final String contentType, long chunkSize, final File file | ||||||
|  |     ) { | ||||||
|         super(); |         super(); | ||||||
|         if (channel == null) { |         if (channel == null) { | ||||||
|             throw new IllegalArgumentException("File may not be null"); |             throw new IllegalArgumentException("File may not be null"); | ||||||
| @ -119,15 +122,20 @@ public class ChunkFromFileChannelRequestEntity implements RequestEntity, Progres | |||||||
|     public void writeRequest(final OutputStream out) throws IOException { |     public void writeRequest(final OutputStream out) throws IOException { | ||||||
|         int readCount = 0; |         int readCount = 0; | ||||||
|         Iterator<OnDatatransferProgressListener> it = null; |         Iterator<OnDatatransferProgressListener> it = null; | ||||||
|          | 
 | ||||||
|        try { |         try { | ||||||
|             mChannel.position(mOffset); |             mChannel.position(mOffset); | ||||||
|             long size = mFile.length(); |             long size = mFile.length(); | ||||||
|             if (size == 0) size = -1; |             if (size == 0) size = -1; | ||||||
|             long maxCount = Math.min(mOffset + mChunkSize, mChannel.size()); |             long maxCount = Math.min(mOffset + mChunkSize, mChannel.size()); | ||||||
|             while (mChannel.position() < maxCount) { |             while (mChannel.position() < maxCount) { | ||||||
|                 readCount = mChannel.read(mBuffer); |                 readCount = mChannel.read(mBuffer); | ||||||
|                 out.write(mBuffer.array(), 0, readCount); |                 try { | ||||||
|  |                     out.write(mBuffer.array(), 0, readCount); | ||||||
|  |                 } catch (IOException io) { | ||||||
|  |                     // work-around try catch to filter exception in writing | ||||||
|  |                     throw new FileRequestEntity.WriteException(io); | ||||||
|  |                 } | ||||||
|                 mBuffer.clear(); |                 mBuffer.clear(); | ||||||
|                 if (mTransferred < maxCount) {  // condition to avoid accumulate progress for repeated chunks |                 if (mTransferred < maxCount) {  // condition to avoid accumulate progress for repeated chunks | ||||||
|                     mTransferred += readCount; |                     mTransferred += readCount; | ||||||
| @ -139,12 +147,21 @@ public class ChunkFromFileChannelRequestEntity implements RequestEntity, Progres | |||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|              | 
 | ||||||
|         } catch (IOException io) { |         } catch (IOException io) { | ||||||
|             Log_OC.e(TAG, io.getMessage()); |             // any read problem will be handled as if the file is not there | ||||||
|             throw new RuntimeException("Ugly solution to workaround the default policy of retries when the server falls while uploading ; temporal fix; really", io);    |             if (io instanceof FileNotFoundException) { | ||||||
|              |                 throw io; | ||||||
|  |             } else { | ||||||
|  |                 FileNotFoundException fnf = new FileNotFoundException("Exception reading source file"); | ||||||
|  |                 fnf.initCause(io); | ||||||
|  |                 throw fnf; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |         } catch (FileRequestEntity.WriteException we) { | ||||||
|  |             throw we.getWrapped(); | ||||||
|         } |         } | ||||||
|  |              | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
| @ -26,6 +26,7 @@ | |||||||
| package com.owncloud.android.lib.common.network; | package com.owncloud.android.lib.common.network; | ||||||
| 
 | 
 | ||||||
| import java.io.File; | import java.io.File; | ||||||
|  | import java.io.FileNotFoundException; | ||||||
| import java.io.IOException; | import java.io.IOException; | ||||||
| import java.io.OutputStream; | import java.io.OutputStream; | ||||||
| import java.io.RandomAccessFile; | import java.io.RandomAccessFile; | ||||||
| @ -100,12 +101,9 @@ public class FileRequestEntity implements RequestEntity, ProgressiveDataTransfer | |||||||
|      |      | ||||||
|     @Override |     @Override | ||||||
|     public void writeRequest(final OutputStream out) throws IOException { |     public void writeRequest(final OutputStream out) throws IOException { | ||||||
|         //byte[] tmp = new byte[4096]; |  | ||||||
|         ByteBuffer tmp = ByteBuffer.allocate(4096); |         ByteBuffer tmp = ByteBuffer.allocate(4096); | ||||||
|         int readResult = 0; |         int readResult = 0; | ||||||
|          |          | ||||||
|         // TODO(bprzybylski): each mem allocation can throw OutOfMemoryError we need to handle it |  | ||||||
|         //                    globally in some fashionable manner |  | ||||||
|         RandomAccessFile raf = new RandomAccessFile(mFile, "r"); |         RandomAccessFile raf = new RandomAccessFile(mFile, "r"); | ||||||
|         FileChannel channel = raf.getChannel(); |         FileChannel channel = raf.getChannel(); | ||||||
|         Iterator<OnDatatransferProgressListener> it = null; |         Iterator<OnDatatransferProgressListener> it = null; | ||||||
| @ -114,7 +112,12 @@ public class FileRequestEntity implements RequestEntity, ProgressiveDataTransfer | |||||||
|         if (size == 0) size = -1; |         if (size == 0) size = -1; | ||||||
|         try { |         try { | ||||||
|             while ((readResult = channel.read(tmp)) >= 0) { |             while ((readResult = channel.read(tmp)) >= 0) { | ||||||
|                 out.write(tmp.array(), 0, readResult); |                 try { | ||||||
|  |                     out.write(tmp.array(), 0, readResult); | ||||||
|  |                 } catch (IOException io) { | ||||||
|  |                     // work-around try catch to filter exception in writing | ||||||
|  |                     throw new WriteException(io); | ||||||
|  |                 } | ||||||
|                 tmp.clear(); |                 tmp.clear(); | ||||||
|                 transferred += readResult; |                 transferred += readResult; | ||||||
|                 synchronized (mDataTransferListeners) { |                 synchronized (mDataTransferListeners) { | ||||||
| @ -124,14 +127,39 @@ public class FileRequestEntity implements RequestEntity, ProgressiveDataTransfer | |||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|              | 
 | ||||||
|         } catch (IOException io) { |         } catch (IOException io) { | ||||||
|             Log_OC.e("FileRequestException", io.getMessage()); |             // any read problem will be handled as if the file is not there | ||||||
|             throw new RuntimeException("Ugly solution to workaround the default policy of retries when the server falls while uploading ; temporal fix; really", io);    |             if (io instanceof FileNotFoundException) { | ||||||
|              |                 throw io; | ||||||
|  |             } else { | ||||||
|  |                 FileNotFoundException fnf = new FileNotFoundException("Exception reading source file"); | ||||||
|  |                 fnf.initCause(io); | ||||||
|  |                 throw fnf; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |         } catch (WriteException we) { | ||||||
|  |             throw we.getWrapped(); | ||||||
|  | 
 | ||||||
|         } finally { |         } finally { | ||||||
|             channel.close(); |             try { | ||||||
|             raf.close(); |                 channel.close(); | ||||||
|  |                 raf.close(); | ||||||
|  |             } catch (IOException io) { | ||||||
|  |                 // ignore failures closing source file | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     protected static class WriteException extends Exception { | ||||||
|  |         IOException mWrapped; | ||||||
|  | 
 | ||||||
|  |         WriteException(IOException wrapped) { | ||||||
|  |             mWrapped = wrapped; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         public IOException getWrapped() { | ||||||
|  |             return mWrapped; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -25,6 +25,7 @@ | |||||||
| package com.owncloud.android.lib.common.operations; | package com.owncloud.android.lib.common.operations; | ||||||
| 
 | 
 | ||||||
| import java.io.ByteArrayInputStream; | import java.io.ByteArrayInputStream; | ||||||
|  | import java.io.FileNotFoundException; | ||||||
| import java.io.IOException; | import java.io.IOException; | ||||||
| import java.io.InputStream; | import java.io.InputStream; | ||||||
| import java.io.Serializable; | import java.io.Serializable; | ||||||
| @ -260,6 +261,9 @@ public class RemoteOperationResult implements Serializable { | |||||||
|                 mCode = ResultCode.SSL_ERROR; |                 mCode = ResultCode.SSL_ERROR; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|  |         } else if (e instanceof FileNotFoundException) { | ||||||
|  |             mCode = ResultCode.LOCAL_FILE_NOT_FOUND; | ||||||
|  | 
 | ||||||
|         } else { |         } else { | ||||||
|             mCode = ResultCode.UNKNOWN_ERROR; |             mCode = ResultCode.UNKNOWN_ERROR; | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -32,9 +32,11 @@ import java.util.HashSet; | |||||||
| import java.util.Set; | import java.util.Set; | ||||||
| import java.util.concurrent.atomic.AtomicBoolean; | import java.util.concurrent.atomic.AtomicBoolean; | ||||||
| 
 | 
 | ||||||
|  | import org.apache.commons.httpclient.DefaultHttpMethodRetryHandler; | ||||||
| import org.apache.commons.httpclient.HttpStatus; | import org.apache.commons.httpclient.HttpStatus; | ||||||
| import org.apache.commons.httpclient.methods.PutMethod; | import org.apache.commons.httpclient.methods.PutMethod; | ||||||
| import org.apache.commons.httpclient.methods.RequestEntity; | import org.apache.commons.httpclient.methods.RequestEntity; | ||||||
|  | import org.apache.commons.httpclient.params.HttpMethodParams; | ||||||
| 
 | 
 | ||||||
| import com.owncloud.android.lib.common.OwnCloudClient; | import com.owncloud.android.lib.common.OwnCloudClient; | ||||||
| import com.owncloud.android.lib.common.network.FileRequestEntity; | import com.owncloud.android.lib.common.network.FileRequestEntity; | ||||||
| @ -87,8 +89,16 @@ public class UploadRemoteFileOperation extends RemoteOperation { | |||||||
| 	@Override | 	@Override | ||||||
| 	protected RemoteOperationResult run(OwnCloudClient client) { | 	protected RemoteOperationResult run(OwnCloudClient client) { | ||||||
| 		RemoteOperationResult result = null; | 		RemoteOperationResult result = null; | ||||||
|  | 		DefaultHttpMethodRetryHandler oldRetryHandler = | ||||||
|  | 			(DefaultHttpMethodRetryHandler) client.getParams().getParameter(HttpMethodParams.RETRY_HANDLER); | ||||||
| 
 | 
 | ||||||
| 		try { | 		try { | ||||||
|  | 			// prevent that uploads are retried automatically by network library | ||||||
|  | 			client.getParams().setParameter( | ||||||
|  | 				HttpMethodParams.RETRY_HANDLER, | ||||||
|  | 				new DefaultHttpMethodRetryHandler(0, false) | ||||||
|  | 			); | ||||||
|  | 
 | ||||||
| 			mPutMethod = new PutMethod(client.getWebdavUri() + WebdavUtils.encodePath(mRemotePath)); | 			mPutMethod = new PutMethod(client.getWebdavUri() + WebdavUtils.encodePath(mRemotePath)); | ||||||
| 
 | 
 | ||||||
| 			if (mCancellationRequested.get()) { | 			if (mCancellationRequested.get()) { | ||||||
| @ -114,6 +124,12 @@ public class UploadRemoteFileOperation extends RemoteOperation { | |||||||
| 			} else { | 			} else { | ||||||
| 				result = new RemoteOperationResult(e); | 				result = new RemoteOperationResult(e); | ||||||
| 			} | 			} | ||||||
|  | 		} finally { | ||||||
|  | 			// reset previous retry handler | ||||||
|  | 			client.getParams().setParameter( | ||||||
|  | 				HttpMethodParams.RETRY_HANDLER, | ||||||
|  | 				oldRetryHandler | ||||||
|  | 			); | ||||||
| 		} | 		} | ||||||
| 		return result; | 		return result; | ||||||
| 	} | 	} | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user