You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by Thoralf Rickert <th...@m84.de> on 2003/02/21 09:15:30 UTC

HTTPClient Feature Patch

Hi!

I'm not subribed to the list, so please make a CC to my address...

I'm working on a small WebDAV application based on the org.apache.webdav 
library. For user feedback it is necessary to know how many bytes a Put 
request has already finished (0%...25%...50%...75%...100%) (especially 
for big files). Because the WebDAV PutMethod extends the httpclient 
PutMethod which extends the
     org.apache.commons.httpclient.methods.EntityEnclosingMethod,
I would like to "submit" a small patch, which makes it possible to get 
the number of already sent bytes in a "controlling thread"....Here is 
the code:

package org.apache.commons.httpclient.methods;
[...]
public abstract class EntityEnclosingMethod extends GetMethod {
[...]
   private long writtenBytes = 0;
[...]
   protected boolean writeRequestBody(HttpState state,
                                      HttpConnection conn)
       throws IOException, HttpException {

     [....]
     writtenBytes = 0;
     byte[] tmp = new byte[4096];
     //int total = 0;
     int i = 0;
     while ((i = instream.read(tmp)) >= 0) {
       outstream.write(tmp, 0, i);
       //total += i;
       writtenBytes += i;
     }
     [....]
   }

   /**
    * Returns the Number of Request Body Bytes send to the server
    */
   public long getWrittenRequestBodyBytes() {
     return this.writtenBytes;
   }
}

If I would start the HttpConnection in a subthread I could call the 
getWrittenRequestBodyBytes() method (or however you call it) during 
upload to get the number of transfered bytes. So I can show the user, 
that the application still works...

Do you think, that this small patch is useful for you too or do you know 
another way?

Thanks,
Thoralf Rickert



---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org


Re: HTTPClient Feature Patch

Posted by Jeffrey Dever <js...@sympatico.ca>.

Thoralf Rickert wrote:

> Hi!
>
> I'm not subribed to the list, so please make a CC to my address...
>
> I'm working on a small WebDAV application based on the 
> org.apache.webdav library. For user feedback it is necessary to know 
> how many bytes a Put request has already finished 
> (0%...25%...50%...75%...100%) (especially for big files). Because the 
> WebDAV PutMethod extends the httpclient PutMethod which extends the
>     org.apache.commons.httpclient.methods.EntityEnclosingMethod,
> I would like to "submit" a small patch, which makes it possible to get 
> the number of already sent bytes in a "controlling thread"....Here is 
> the code:
>
> package org.apache.commons.httpclient.methods;
> [...]
> public abstract class EntityEnclosingMethod extends GetMethod {
> [...]
>   private long writtenBytes = 0;
> [...]
>   protected boolean writeRequestBody(HttpState state,
>                                      HttpConnection conn)
>       throws IOException, HttpException {
>
>     [....]
>     writtenBytes = 0;
>     byte[] tmp = new byte[4096];
>     //int total = 0;
>     int i = 0;
>     while ((i = instream.read(tmp)) >= 0) {
>       outstream.write(tmp, 0, i);
>       //total += i;
>       writtenBytes += i;
>     }
>     [....]
>   }
>
>   /**
>    * Returns the Number of Request Body Bytes send to the server
>    */
>   public long getWrittenRequestBodyBytes() {
>     return this.writtenBytes;
>   }
> }
>
> If I would start the HttpConnection in a subthread I could call the 
> getWrittenRequestBodyBytes() method (or however you call it) during 
> upload to get the number of transfered bytes. So I can show the user, 
> that the application still works...
>
> Do you think, that this small patch is useful for you too or do you 
> know another way?
>
> Thanks,
> Thoralf Rickert
>
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: commons-dev-help@jakarta.apache.org
>
>



---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org


Re: HTTPClient Feature Patch

Posted by Jeffrey Dever <js...@sympatico.ca>.
This is a good idea, particularly for updating a JProgressBar.  Can you 
please bring this up on the commons-httpclient-dev@jakarta.apache.org 
mailing list?


Thoralf Rickert wrote:

> Hi!
>
> I'm not subribed to the list, so please make a CC to my address...
>
> I'm working on a small WebDAV application based on the 
> org.apache.webdav library. For user feedback it is necessary to know 
> how many bytes a Put request has already finished 
> (0%...25%...50%...75%...100%) (especially for big files). Because the 
> WebDAV PutMethod extends the httpclient PutMethod which extends the
>     org.apache.commons.httpclient.methods.EntityEnclosingMethod,
> I would like to "submit" a small patch, which makes it possible to get 
> the number of already sent bytes in a "controlling thread"....Here is 
> the code:
>
> package org.apache.commons.httpclient.methods;
> [...]
> public abstract class EntityEnclosingMethod extends GetMethod {
> [...]
>   private long writtenBytes = 0;
> [...]
>   protected boolean writeRequestBody(HttpState state,
>                                      HttpConnection conn)
>       throws IOException, HttpException {
>
>     [....]
>     writtenBytes = 0;
>     byte[] tmp = new byte[4096];
>     //int total = 0;
>     int i = 0;
>     while ((i = instream.read(tmp)) >= 0) {
>       outstream.write(tmp, 0, i);
>       //total += i;
>       writtenBytes += i;
>     }
>     [....]
>   }
>
>   /**
>    * Returns the Number of Request Body Bytes send to the server
>    */
>   public long getWrittenRequestBodyBytes() {
>     return this.writtenBytes;
>   }
> }
>
> If I would start the HttpConnection in a subthread I could call the 
> getWrittenRequestBodyBytes() method (or however you call it) during 
> upload to get the number of transfered bytes. So I can show the user, 
> that the application still works...
>
> Do you think, that this small patch is useful for you too or do you 
> know another way?
>
> Thanks,
> Thoralf Rickert
>
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: commons-dev-help@jakarta.apache.org
>
>



---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org


Re: HTTPClient Feature Patch

Posted by Ortwin Glück <or...@nose.ch>.
Thoralf Rickert wrote:
> But what about the #setRequestBody(String body) method. OK, I could use a
>     ProgressInputStream(new ByteArrayInputStream(body.getBytes()))
> as the body.

Note: You should use the String.getBytes(String) method to specify an 
encoding. Otherwise your code will not be portable to some platforms.


---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org


Re: HTTPClient Feature Patch

Posted by Thoralf Rickert <th...@m84.de>.
Hi!

> I would recommend against doing it in this way.  Primarily because it 
> involves polling (the second thread calling getWrittenRequestBodyBytes() 
> repeatedly) and because of the added synchronization overhead.

Yes, I would call it just once a second, but nobody knows what someone 
else does.

> In my experience it is easier and more reusable to handle this at the 
> InputStream level.  This involves adding a wrapper class around the 
> InputStream that is being put/posted.  It would look something like:
> 
> class ProgressInputStream extends FilterInputStream {
 > [...]

So, maybe I don't need a code change in the class EntityEnclosingMethod, 
because I could use the ProgressInputStream instead of a simple 
InputStream in the method
     EntityEnclosingMethod#setRequestBody(InputStream body)
But what about the #setRequestBody(String body) method. OK, I could use a
     ProgressInputStream(new ByteArrayInputStream(body.getBytes()))
as the body.

But especially for my actual problem (the WebDAV client progressbar), I 
don't have (real) access to the Source code and the above changes in the 
httpclient must be added in every implementation that uses the 
#setRequestBody() method.
I think, it would be easier and better to implement a "ProgressObserver" 
at the lowest possible position. To avoid waste of resources, it could 
be possible to add ProgressListener directly to the 
EntityEnclosingMethod. Example:

public abstract class EntityEnclosingMethod extends GetMethod {
   [...]
   private List progressListeners = new ArrayList();
   [...]
   public void addProgressListener(ProgressListener listener) {
     progressListeners.add(listener);
   }

   public List getProgressListeners() { return progressListeners; }

   protected boolean writeRequestBody(
       HttpState state, HttpConnection conn) {
     //...
     if (progressListeners.isEmpty()) {
       InputStream instream = getRequestBody();
     } else {
       InputStream instream = new ProgressInputStream(
                                    getRequestBody(),
                                    getProgressListeners());
     }
     // ...
}

public class ProgressInputStream extends FilterInputStream {
   // ...
   public ProgressInputStream(InputStream is, List progressListeners) {
     //...
   }
   // ...
   private void bytesRead(int count) {
     bytesRead+=count;
     if (progressListeners==null || progressListeners.isEmpty()) return;
     for (int i=0; i<progressListeners.size();i++) {
       ProgressListener l = (ProgressListener)progressListeners.get(i);
       if (bytesRead > l.getThreshold()) {
         totalBytesRead += bytesRead;
         bytesRead = 0;
         l.progressAchieved(totalBytesRead);
       }
     }
   }
}

The EVENT_THRESHOLD value should be part of the ProgressListener, should 
be "setable" and should be checked by the ProgressInputStream. 
(Different values MUST be possible, for example transfering data over a 
slow connection should show the transfer of even 10 Bytes).

public Interface ProgressListener {
   public void progressAchieved(long totalBytesRead);
   public int getThreshold();
}


---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org


Re: HTTPClient Feature Patch

Posted by Michael Becke <be...@u.washington.edu>.
I would recommend against doing it in this way.  Primarily because it 
involves polling (the second thread calling 
getWrittenRequestBodyBytes() repeatedly) and because of the added 
synchronization overhead.

In my experience it is easier and more reusable to handle this at the 
InputStream level.  This involves adding a wrapper class around the 
InputStream that is being put/posted.  It would look something like:

class ProgressInputStream extends FilterInputStream {
	private static final long EVENT_THRESHOLD = 1024;

	private long bytesRead;
	private long totalBytesRead;
	private ProgressListener listener;

	public ProgressInputStream(InputStream is, ProgressListener listener) {
		super(is);
		this.listener = listener;
	}

	private void bytesRead(int count) {
		bytesRead+=count;
		if (bytesRead > EVENT_THRESHOLD) {
			totalBytesRead += bytesRead;
			bytesRead = 0;
			listener.progressAchieved(totalBytesRead);
		}		
	}

	public int read() {
		int byte = super.read();
		if (byte != -1) {
			bytesRead(1);
		}
		return byte;
	}
	
	public int read(byte[] b, int offset, int length) {
		int bytesRead = super.read(b, offset, length);
		if (bytesRead > 0 ) {
			bytesRead(bytesRead);
		}
		return bytesRead;
	}
}

interface ProgressListener {
	void progressAchieved(long totalBytesRead);
}

Then you would want to implement the ProgressListener interface with 
something that updates the progress in the UI, preferably from another 
thread.

Mike

On Friday, February 21, 2003, at 03:15 AM, Thoralf Rickert wrote:

> Hi!
>
> I'm not subribed to the list, so please make a CC to my address...
>
> I'm working on a small WebDAV application based on the 
> org.apache.webdav library. For user feedback it is necessary to know 
> how many bytes a Put request has already finished 
> (0%...25%...50%...75%...100%) (especially for big files). Because the 
> WebDAV PutMethod extends the httpclient PutMethod which extends the
>     org.apache.commons.httpclient.methods.EntityEnclosingMethod,
> I would like to "submit" a small patch, which makes it possible to get 
> the number of already sent bytes in a "controlling thread"....Here is 
> the code:
>
> package org.apache.commons.httpclient.methods;
> [...]
> public abstract class EntityEnclosingMethod extends GetMethod {
> [...]
>   private long writtenBytes = 0;
> [...]
>   protected boolean writeRequestBody(HttpState state,
>                                      HttpConnection conn)
>       throws IOException, HttpException {
>
>     [....]
>     writtenBytes = 0;
>     byte[] tmp = new byte[4096];
>     //int total = 0;
>     int i = 0;
>     while ((i = instream.read(tmp)) >= 0) {
>       outstream.write(tmp, 0, i);
>       //total += i;
>       writtenBytes += i;
>     }
>     [....]
>   }
>
>   /**
>    * Returns the Number of Request Body Bytes send to the server
>    */
>   public long getWrittenRequestBodyBytes() {
>     return this.writtenBytes;
>   }
> }
>
> If I would start the HttpConnection in a subthread I could call the 
> getWrittenRequestBodyBytes() method (or however you call it) during 
> upload to get the number of transfered bytes. So I can show the user, 
> that the application still works...
>
> Do you think, that this small patch is useful for you too or do you 
> know another way?
>
> Thanks,
> Thoralf Rickert
>
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: commons-dev-help@jakarta.apache.org
>


---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org