1 /* ownCloud Android client application 
   2  *   Copyright (C) 2012-2013 ownCloud Inc. 
   4  *   This program is free software: you can redistribute it and/or modify 
   5  *   it under the terms of the GNU General Public License version 2, 
   6  *   as published by the Free Software Foundation. 
   8  *   This program is distributed in the hope that it will be useful, 
   9  *   but WITHOUT ANY WARRANTY; without even the implied warranty of 
  10  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
  11  *   GNU General Public License for more details. 
  13  *   You should have received a copy of the GNU General Public License 
  14  *   along with this program.  If not, see <http://www.gnu.org/licenses/>. 
  18 package eu
.alefzero
.webdav
; 
  21 import java
.io
.IOException
; 
  22 import java
.io
.OutputStream
; 
  23 import java
.nio
.ByteBuffer
; 
  24 import java
.nio
.channels
.FileChannel
; 
  25 import java
.util
.Collection
; 
  26 import java
.util
.HashSet
; 
  27 import java
.util
.Iterator
; 
  30 import org
.apache
.commons
.httpclient
.methods
.RequestEntity
; 
  32 import com
.owncloud
.android
.Log_OC
; 
  33 import com
.owncloud
.android
.network
.ProgressiveDataTransferer
; 
  36 import eu
.alefzero
.webdav
.OnDatatransferProgressListener
; 
  40  * A RequestEntity that represents a PIECE of a file. 
  42  * @author David A. Velasco 
  44 public class ChunkFromFileChannelRequestEntity 
implements RequestEntity
, ProgressiveDataTransferer 
{ 
  46     private static final String TAG 
= ChunkFromFileChannelRequestEntity
.class.getSimpleName(); 
  48     //private final File mFile; 
  49     private final FileChannel mChannel
; 
  50     private final String mContentType
; 
  51     private final long mChunkSize
; 
  52     private final File mFile
; 
  54     private long mTransferred
; 
  55     Set
<OnDatatransferProgressListener
> mDataTransferListeners 
= new HashSet
<OnDatatransferProgressListener
>(); 
  56     private ByteBuffer mBuffer 
= ByteBuffer
.allocate(4096); 
  58     public ChunkFromFileChannelRequestEntity(final FileChannel channel
, final String contentType
, long chunkSize
, final File file
) { 
  60         if (channel 
== null
) { 
  61             throw new IllegalArgumentException("File may not be null"); 
  64             throw new IllegalArgumentException("Chunk size must be greater than zero"); 
  67         mContentType 
= contentType
; 
  68         mChunkSize 
= chunkSize
; 
  74     public void setOffset(long offset
) { 
  78     public long getContentLength() { 
  80             return Math
.min(mChunkSize
, mChannel
.size() - mChannel
.position()); 
  81         } catch (IOException e
) { 
  86     public String 
getContentType() { 
  90     public boolean isRepeatable() { 
  95     public void addDatatransferProgressListener(OnDatatransferProgressListener listener
) { 
  96         synchronized (mDataTransferListeners
) { 
  97             mDataTransferListeners
.add(listener
); 
 102     public void addDatatransferProgressListeners(Collection
<OnDatatransferProgressListener
> listeners
) { 
 103         synchronized (mDataTransferListeners
) { 
 104             mDataTransferListeners
.addAll(listeners
); 
 109     public void removeDatatransferProgressListener(OnDatatransferProgressListener listener
) { 
 110         synchronized (mDataTransferListeners
) { 
 111             mDataTransferListeners
.remove(listener
); 
 116     public void writeRequest(final OutputStream out
) throws IOException 
{ 
 118         Iterator
<OnDatatransferProgressListener
> it 
= null
; 
 121             mChannel
.position(mOffset
); 
 122             long size 
= mFile
.length(); 
 123             if (size 
== 0) size 
= -1; 
 124             long maxCount 
= Math
.min(mOffset 
+ mChunkSize
, mChannel
.size()); 
 125             while (mChannel
.position() < maxCount
) { 
 126                 readCount 
= mChannel
.read(mBuffer
); 
 127                 out
.write(mBuffer
.array(), 0, readCount
); 
 129                 if (mTransferred 
< maxCount
) {  // condition to avoid accumulate progress for repeated chunks 
 130                     mTransferred 
+= readCount
; 
 132                 synchronized (mDataTransferListeners
) { 
 133                     it 
= mDataTransferListeners
.iterator(); 
 134                     while (it
.hasNext()) { 
 135                         it
.next().onTransferProgress(readCount
, mTransferred
, size
, mFile
.getName()); 
 140         } catch (IOException io
) { 
 141             Log_OC
.e(TAG
, io
.getMessage()); 
 142             throw new RuntimeException("Ugly solution to workaround the default policy of retries when the server falls while uploading ; temporal fix; really", io
);