From: <bsc...@us...> - 2012-10-30 11:38:59
|
Revision: 14832 http://unicore.svn.sourceforge.net/unicore/?rev=14832&view=rev Author: bschuller Date: 2012-10-30 11:38:52 +0000 (Tue, 30 Oct 2012) Log Message: ----------- add a nice client for the http download Modified Paths: -------------- unicorex/trunk/uas-core/src/test/java/de/fzj/unicore/uas/impl/http/TestHttp.java Added Paths: ----------- unicorex/trunk/uas-client/src/main/java/de/fzj/unicore/uas/client/HttpBasicClient.java Added: unicorex/trunk/uas-client/src/main/java/de/fzj/unicore/uas/client/HttpBasicClient.java =================================================================== --- unicorex/trunk/uas-client/src/main/java/de/fzj/unicore/uas/client/HttpBasicClient.java (rev 0) +++ unicorex/trunk/uas-client/src/main/java/de/fzj/unicore/uas/client/HttpBasicClient.java 2012-10-30 11:38:52 UTC (rev 14832) @@ -0,0 +1,234 @@ +package de.fzj.unicore.uas.client; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import org.apache.commons.httpclient.HttpClient; +import org.apache.commons.httpclient.HttpStatus; +import org.apache.commons.httpclient.methods.EntityEnclosingMethod; +import org.apache.commons.httpclient.methods.GetMethod; +import org.apache.commons.httpclient.methods.InputStreamRequestEntity; +import org.apache.commons.httpclient.methods.PostMethod; +import org.apache.commons.httpclient.methods.PutMethod; +import org.apache.log4j.Logger; + +import de.fzj.unicore.uas.fts.ProgressListener; +import eu.unicore.util.Log; +import eu.unicore.util.httpclient.HttpUtils; +import eu.unicore.util.httpclient.IClientConfiguration; + +/** + * Client for getting/putting a file through HTTP + * + * @author schuller + * @since 1.6.0 + */ +public class HttpBasicClient +implements FileTransferClient.IMonitorable, FileTransferClient.SupportsPartialRead +{ + + private static final Logger logger=Log.getLogger(Log.CLIENT, HttpBasicClient.class); + + private final String accessURL; + + private final IClientConfiguration sec; + + private Long totalBytesTransferred=0L; + + private ProgressListener<Long> observer; + + private boolean append=false; + + public HttpBasicClient(String url, IClientConfiguration sec) throws Exception { + accessURL=url; + this.sec=sec; + } + + /** + * read remote data and copy to the given output stream + * @param os - the OutputStream to write the data to + * @throws Exception + */ + public void readAllData(OutputStream os)throws Exception{ + HttpClient client=getClient(); + GetMethod get=new GetMethod(accessURL); + totalBytesTransferred=read(os, get, client); + } + + protected long read(OutputStream os, GetMethod get, HttpClient client)throws IOException{ + InputStream is=null; + try{ + int result=client.executeMethod(get); + //check for 200 response + if(result<200 || result >299 ){ + throw new IOException("Can't read remote data, server returned "+HttpStatus.getStatusText(result)); + } + is=get.getResponseBodyAsStream(); + return copy(is, os); + }finally{ + try{ + if(is!=null)is.close(); + }catch(Exception ignored){} + get.releaseConnection(); + } + } + + /** + * read local data and write to remote location + * + * @param is - the InputStream to read from + * @parem append - whether to append to an existing file + * @throws Exception + */ + public void writeAllData(final InputStream is,boolean append)throws Exception{ + this.append=append; + writeAllData(is); + } + + + /** + * read local data and write to remote location + * + * @param is - the InputStream to read from + * @parem append - whether to append to an existing file + * @throws Exception + */ + public void writeAllData(final InputStream is)throws Exception{ + HttpClient client=getClient(); + EntityEnclosingMethod upload=createMethodForUpload(); + //monitor transfer progress, costs a bit performance though + InputStream decoratedStream=new InputStream(){ + @Override + public int read() throws IOException { + int b=is.read(); + if(b!=-1){ + totalBytesTransferred++; + if(observer!=null){ + observer.notifyProgress(Long.valueOf(1)); + if(observer.isCancelled())throw new ProgressListener.CancelledException("Cancelled."); + } + } + return b; + } + @Override + public int read(byte[] b, int off, int len) throws IOException { + int r=is.read(b, off, len); + if(r>0){ + totalBytesTransferred+=r; + if(observer!=null){ + observer.notifyProgress(Long.valueOf(r)); + if(observer.isCancelled())throw new ProgressListener.CancelledException("Cancelled."); + } + } + return r; + } + }; + upload.setRequestEntity(new InputStreamRequestEntity(decoratedStream)); + + totalBytesTransferred=Long.valueOf(0); + try{ + int result=client.executeMethod(upload); + //check for 200 response + if(result<200 || result >299 ){ + throw new IOException("Can't write data, server returned "+HttpStatus.getStatusText(result)); + } + logger.debug("Total transferred bytes: "+totalBytesTransferred + +", HTTP return status "+upload.getStatusLine()); + }finally{ + upload.releaseConnection(); + } + } + + + public String getAccessURL(){ + return accessURL; + } + + + @Override + public long readPartial(long offset, long length, OutputStream os) + throws IOException { + HttpClient client=getClient(); + GetMethod get=new GetMethod(accessURL); + //Note: byte range is inclusive! + get.addRequestHeader("Range", "bytes="+offset+"-"+(offset+length-1)); + return read(os, get, client); + } + + //copy all data from an input stream to an output stream + private long copy(InputStream in, OutputStream out)throws IOException{ + int bufferSize=16384; + byte[] buffer = new byte[bufferSize]; + int len=0; + int c=0; + long progress=0; + //the total bytes transferred in this invocation of copy() + long total=0; + while (true) + { + len=in.read(buffer,0,bufferSize); + if (len<0 ) + break; + if(len>0){ + c++; + out.write(buffer,0,len); + total+=len; + progress+=len; + if(c % 10 == 0){ + if(observer!=null){ + observer.notifyProgress(progress); + if(observer.isCancelled())throw new ProgressListener.CancelledException("Cancelled."); + progress=0; + } + } + } + } + if(observer!=null){ + observer.notifyProgress(progress); + } + out.flush(); + return total; + } + + protected HttpClient getClient(){ + HttpClient client=HttpUtils.createClient(accessURL, sec); + return client; + } + + /** + * the total bytes transferred. Note: this will only be updated once per call + * to readAllData() or readPartial(). If you need a 'live' value, use a {@link ProgressListener} + * and register it using {@link #setProgressListener(ProgressListener)} + * @return + */ + public long getTotalBytesTransferred(){ + return totalBytesTransferred; + } + + /** + * register a progress callback + */ + public void setProgressListener(ProgressListener<Long> o){ + observer=o; + } + + protected EntityEnclosingMethod createMethodForUpload(){ + return accessURL.contains("method=POST")? createPost(): createPut(); + } + + protected EntityEnclosingMethod createPut(){ + EntityEnclosingMethod upload=new PutMethod(accessURL); + upload.setContentChunked(true); + if(append)upload.addRequestHeader("X-UNICORE-AppendData", "true"); + return upload; + } + + protected EntityEnclosingMethod createPost(){ + EntityEnclosingMethod upload=new PostMethod(accessURL); + upload.addRequestHeader("Content-Type", "multipart/form-data; boundary=--part-boundary--"); + upload.setContentChunked(true); + if(append)upload.addRequestHeader("X-UNICORE-AppendData", "true"); + return upload; + } +} Property changes on: unicorex/trunk/uas-client/src/main/java/de/fzj/unicore/uas/client/HttpBasicClient.java ___________________________________________________________________ Added: svn:mime-type + text/plain Modified: unicorex/trunk/uas-core/src/test/java/de/fzj/unicore/uas/impl/http/TestHttp.java =================================================================== --- unicorex/trunk/uas-core/src/test/java/de/fzj/unicore/uas/impl/http/TestHttp.java 2012-10-30 11:25:15 UTC (rev 14831) +++ unicorex/trunk/uas-core/src/test/java/de/fzj/unicore/uas/impl/http/TestHttp.java 2012-10-30 11:38:52 UTC (rev 14832) @@ -11,6 +11,7 @@ import org.apache.commons.io.IOUtils; import org.apache.commons.io.output.ByteArrayOutputStream; +import de.fzj.unicore.uas.client.HttpBasicClient; import de.fzj.unicore.uas.client.JobClient; import de.fzj.unicore.uas.fts.http.FileServlet; import de.fzj.unicore.uas.testsuite.RunDate; @@ -20,7 +21,6 @@ import de.fzj.unicore.xnjs.Configuration; import de.fzj.unicore.xnjs.ems.Action; import de.fzj.unicore.xnjs.io.IStorageAdapter; -import eu.unicore.util.httpclient.HttpUtils; public class TestHttp extends RunDate { @@ -39,20 +39,17 @@ //try a "get" on a file in uspace String accessURL=makeBaseFileURL()+id+"/test.txt"; - HttpClient hc=HttpUtils.createClient(accessURL, job.getSecurityConfiguration()); - GetMethod get=new GetMethod(accessURL); ByteArrayOutputStream os = new ByteArrayOutputStream(); - read(os, get, hc); + HttpBasicClient hc=new HttpBasicClient(accessURL, job.getSecurityConfiguration()); + hc.readAllData(os); System.out.println("Downloaded content: '"+os+"'"); //try a "get" on a file in a uspace subdirectory accessURL=makeBaseFileURL()+id+"/folder/test.txt"; - get=new GetMethod(accessURL); - os = new ByteArrayOutputStream(); - read(os, get, hc); + hc=new HttpBasicClient(accessURL, job.getSecurityConfiguration()); + hc.readAllData(os); System.out.println("Downloaded content: '"+os+"'"); - if(doDestroy())job.destroy(); } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |