3c34ef4742fab3bc37400c0bce1455eca530c542
[pub/Android/ownCloud.git] / oc_framework / src / com / owncloud / android / lib / network / ChunkFromFileChannelRequestEntity.java
1 /* ownCloud Android Library is available under MIT license
2 * Copyright (C) 2014 ownCloud (http://www.owncloud.org/)
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
18 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
19 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 * THE SOFTWARE.
22 *
23 */
24
25 package com.owncloud.android.lib.network;
26
27 import java.io.File;
28 import java.io.IOException;
29 import java.io.OutputStream;
30 import java.nio.ByteBuffer;
31 import java.nio.channels.FileChannel;
32 import java.util.Collection;
33 import java.util.HashSet;
34 import java.util.Iterator;
35 import java.util.Set;
36
37 import org.apache.commons.httpclient.methods.RequestEntity;
38
39
40 import android.util.Log;
41
42
43 /**
44 * A RequestEntity that represents a PIECE of a file.
45 *
46 * @author David A. Velasco
47 */
48 public class ChunkFromFileChannelRequestEntity implements RequestEntity, ProgressiveDataTransferer {
49
50 private static final String TAG = ChunkFromFileChannelRequestEntity.class.getSimpleName();
51
52 //private final File mFile;
53 private final FileChannel mChannel;
54 private final String mContentType;
55 private final long mChunkSize;
56 private final File mFile;
57 private long mOffset;
58 private long mTransferred;
59 Set<OnDatatransferProgressListener> mDataTransferListeners = new HashSet<OnDatatransferProgressListener>();
60 private ByteBuffer mBuffer = ByteBuffer.allocate(4096);
61
62 public ChunkFromFileChannelRequestEntity(final FileChannel channel, final String contentType, long chunkSize, final File file) {
63 super();
64 if (channel == null) {
65 throw new IllegalArgumentException("File may not be null");
66 }
67 if (chunkSize <= 0) {
68 throw new IllegalArgumentException("Chunk size must be greater than zero");
69 }
70 mChannel = channel;
71 mContentType = contentType;
72 mChunkSize = chunkSize;
73 mFile = file;
74 mOffset = 0;
75 mTransferred = 0;
76 }
77
78 public void setOffset(long offset) {
79 mOffset = offset;
80 }
81
82 public long getContentLength() {
83 try {
84 return Math.min(mChunkSize, mChannel.size() - mChannel.position());
85 } catch (IOException e) {
86 return mChunkSize;
87 }
88 }
89
90 public String getContentType() {
91 return mContentType;
92 }
93
94 public boolean isRepeatable() {
95 return true;
96 }
97
98 @Override
99 public void addDatatransferProgressListener(OnDatatransferProgressListener listener) {
100 synchronized (mDataTransferListeners) {
101 mDataTransferListeners.add(listener);
102 }
103 }
104
105 @Override
106 public void addDatatransferProgressListeners(Collection<OnDatatransferProgressListener> listeners) {
107 synchronized (mDataTransferListeners) {
108 mDataTransferListeners.addAll(listeners);
109 }
110 }
111
112 @Override
113 public void removeDatatransferProgressListener(OnDatatransferProgressListener listener) {
114 synchronized (mDataTransferListeners) {
115 mDataTransferListeners.remove(listener);
116 }
117 }
118
119
120 public void writeRequest(final OutputStream out) throws IOException {
121 int readCount = 0;
122 Iterator<OnDatatransferProgressListener> it = null;
123
124 try {
125 mChannel.position(mOffset);
126 long size = mFile.length();
127 if (size == 0) size = -1;
128 long maxCount = Math.min(mOffset + mChunkSize, mChannel.size());
129 while (mChannel.position() < maxCount) {
130 readCount = mChannel.read(mBuffer);
131 out.write(mBuffer.array(), 0, readCount);
132 mBuffer.clear();
133 if (mTransferred < maxCount) { // condition to avoid accumulate progress for repeated chunks
134 mTransferred += readCount;
135 }
136 synchronized (mDataTransferListeners) {
137 it = mDataTransferListeners.iterator();
138 while (it.hasNext()) {
139 it.next().onTransferProgress(readCount, mTransferred, size, mFile.getAbsolutePath());
140 }
141 }
142 }
143
144 } catch (IOException io) {
145 Log.e(TAG, io.getMessage());
146 throw new RuntimeException("Ugly solution to workaround the default policy of retries when the server falls while uploading ; temporal fix; really", io);
147
148 }
149 }
150
151 }