Hi,

Which version of HttpCore NIO are you using?

That looks like it may be a bug which would need raising in JIRA. The
Android docs [1] say that 1, 4, 8 and 16 are valid values for the bitmask
ops parameter (or use the constants defined on SelectionKey); the code [2]
is currently passing in 0. The JavaDoc says that may throw an
IllegalArgumentException in that case [3].

I'm not familiar enough with the code to know what the intent of the code is
at that point.

Cheers,

James

[1]
http://developer.android.com/reference/java/nio/channels/SelectionKey.html#OP_ACCEPT
[2]
http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/httpcore-nio/src/main/java/org/apache/http/impl/nio/reactor/DefaultConnectingIOReactor.java
[3]
http://java.sun.com/j2se/1.5.0/docs/api/java/nio/channels/SelectableChannel.html#register(java.nio.channels.Selector,
int)


On 29 April 2010 10:51, ching <[email protected]> wrote:

> I'm implementing a download application that works like android's
> DownloadProvider but based HttpCore NIO.
>
> A fatal problem I encountered is this:
> 04-29 09:26:05.419: ERROR/AndroidRuntime(332):
> java.nio.channels.IllegalSelectorException
> 04-29 09:26:05.419: ERROR/AndroidRuntime(332):     at
> java.nio.channels.spi.AbstractSelectableChannel.register(AbstractSelectableChannel.java:158)
> 04-29 09:26:05.419: ERROR/AndroidRuntime(332):     at
> java.nio.channels.SelectableChannel.register(SelectableChannel.java:158)
> 04-29 09:26:05.419: ERROR/AndroidRuntime(332):     at
> org.apache.http.impl.nio.reactor.DefaultConnectingIOReactor.processSessionRequests(DefaultConnectingIOReactor.java:244)
> 04-29 09:26:05.419: ERROR/AndroidRuntime(332):     at
> org.apache.http.impl.nio.reactor.DefaultConnectingIOReactor.processEvents(DefaultConnectingIOReactor.java:97)
> 04-29 09:26:05.419: ERROR/AndroidRuntime(332):     at
> org.apache.http.impl.nio.reactor.AbstractMultiworkerIOReactor.execute(AbstractMultiworkerIOReactor.java:317)
> 04-29 09:26:05.419: ERROR/AndroidRuntime(332):     at
> io.DownloadClient.run(DownloadClient.java:168)
> 04-29 09:26:05.419: ERROR/AndroidRuntime(332):     at
> java.lang.Thread.run(Thread.java:1096)
>
> however it can work on real j2se6, is that unsupported on android at all?
>
> And a minor problem: Will "ioReactor.execute(ioEventDispatch)" really throw
> out a InterruptedIOException?
> I found it will be never even when I interrupt the thread explicitly.
> shutdown can't be done gracefully without this.
>
>
> Thanks for help, my raw codes for testing:
> //********** io.DownloadClient.java **********
> package io;
>
> import java.io.File;
> import java.io.IOException;
> import java.io.InterruptedIOException;
> import java.net.InetSocketAddress;
> import java.net.URI;
> import java.util.Date;
> import java.util.concurrent.ExecutorService;
> import java.util.concurrent.Executors;
>
> import org.apache.http.HttpException;
> import org.apache.http.HttpHost;
> import org.apache.http.HttpRequest;
> import org.apache.http.HttpResponse;
> import org.apache.http.impl.DefaultConnectionReuseStrategy;
> import org.apache.http.impl.nio.DefaultClientIOEventDispatch;
> import org.apache.http.impl.nio.reactor.DefaultConnectingIOReactor;
> import org.apache.http.nio.ContentDecoder;
> import org.apache.http.nio.FileContentDecoder;
> import org.apache.http.nio.NHttpClientConnection;
> import org.apache.http.nio.NHttpClientHandler;
> import org.apache.http.nio.entity.ConsumingNHttpEntity;
> import org.apache.http.nio.protocol.AsyncNHttpClientHandler;
> import org.apache.http.nio.protocol.NHttpRequestExecutionHandler;
> import org.apache.http.nio.reactor.ConnectingIOReactor;
> import org.apache.http.nio.reactor.IOEventDispatch;
> import org.apache.http.nio.util.HeapByteBufferAllocator;
> import org.apache.http.params.BasicHttpParams;
> import org.apache.http.params.CoreConnectionPNames;
> import org.apache.http.params.CoreProtocolPNames;
> import org.apache.http.params.HttpParams;
> import org.apache.http.protocol.BasicHttpProcessor;
> import org.apache.http.protocol.HttpContext;
> import org.apache.http.protocol.RequestConnControl;
> import org.apache.http.protocol.RequestContent;
> import org.apache.http.protocol.RequestExpectContinue;
> import org.apache.http.protocol.RequestTargetHost;
> import org.apache.http.protocol.RequestUserAgent;
>
> public class DownloadClient implements Runnable {
>  public static final String TAG = "nioDownload";
>
>  Thread dispatcher;
>  ExecutorService workers;
>
>  ConnectingIOReactor reactor;
>  IOEventDispatch eventDispatch;
>
>  public DownloadClient() throws IOException {
>  BasicHttpProcessor httpproc = new BasicHttpProcessor();
>        httpproc.addInterceptor(new RequestContent());
>        httpproc.addInterceptor(new RequestTargetHost());
>        httpproc.addInterceptor(new RequestConnControl());
>        httpproc.addInterceptor(new RequestUserAgent());
>        httpproc.addInterceptor(new RequestExpectContinue());
>  HttpParams params = new BasicHttpParams();
>        params.setParameter(CoreProtocolPNames.USER_AGENT,
> "HttpComponents/1.1");
>     params.setIntParameter(CoreConnectionPNames.SO_TIMEOUT, 5000);
>     params.setIntParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 10000);
>     params.setIntParameter(CoreConnectionPNames.SOCKET_BUFFER_SIZE, 8 *
> 1024);
>     params.setBooleanParameter(CoreConnectionPNames.STALE_CONNECTION_CHECK,
> false);
>     params.setBooleanParameter(CoreConnectionPNames.TCP_NODELAY, true);
>  NHttpRequestExecutionHandler execHandler = new
> NHttpRequestExecutionHandler() {
>   HttpRequest request = null;
>   @Override
>   public void initalizeContext(HttpContext context, Object attachment) {
>    if(attachment != null && attachment instanceof DownloadCourse) {
>     DownloadCourse course = (DownloadCourse)attachment;
>     request = course.getRequest();
>     context.setAttribute(TAG, attachment);
>    }
>   }
>   @Override
>   public HttpRequest submitRequest(HttpContext context) {
>    HttpRequest result = this.request;
>    if(result != null) {
>     this.request = null;
>    }
>    return result;
>   }
>   @Override
>   public ConsumingNHttpEntity responseEntity(HttpResponse response,
> HttpContext context)
>     throws IOException {
>    //nothing, handle in NHttpClientHandler.inputReady
>    return null;
>   }
>   @Override
>   public void handleResponse(HttpResponse response, HttpContext context)
>     throws IOException {
>    //nothing, handle in NHttpClientHandler.inputReady
>   }
>   @Override
>   public void finalizeContext(HttpContext context) {
>    context.removeAttribute(TAG);
>   }
>  };
>  NHttpClientHandler handler = new AsyncNHttpClientHandler(
>           httpproc, execHandler, new DefaultConnectionReuseStrategy(),
>           new HeapByteBufferAllocator(), params) {
>   @Override
>   public void closed(NHttpClientConnection conn) {
>    super.closed(conn);
>    Object attachment = conn.getContext().getAttribute(TAG);
>    if(attachment != null && attachment instanceof DownloadCourse) {
>     DownloadCourse course = (DownloadCourse)attachment;
>     course.interrupt();
>    }
>   }
>   @Override
>   public void exception(NHttpClientConnection conn, HttpException ex) {
>    super.exception(conn, ex);
>    Object attachment = conn.getContext().getAttribute(TAG);
>    if(attachment != null && attachment instanceof DownloadCourse) {
>     DownloadCourse course = (DownloadCourse)attachment;
>     course.error(ex);
>    }
>   }
>   @Override
>   public void exception(NHttpClientConnection conn, IOException ex) {
>    super.exception(conn, ex);
>    Object attachment = conn.getContext().getAttribute(TAG);
>    if(attachment != null && attachment instanceof DownloadCourse) {
>     DownloadCourse course = (DownloadCourse)attachment;
>     course.error(ex);
>    }
>   }
>   @Override
>   public void inputReady(NHttpClientConnection conn, ContentDecoder
> content) {
>    //don't invoke super, handle by self
>    log("inputReady: %s", content);
>    Object attachment = conn.getContext().getAttribute(TAG);
>    if(attachment != null && attachment instanceof DownloadCourse) {
>     DownloadCourse course = (DownloadCourse)attachment;
>     course.update((FileContentDecoder)content);
>     if(content.isCompleted()) {
>      course.complete(conn.getHttpResponse());
>     }
>    }
>   }
>   @Override
>   public void responseReceived(NHttpClientConnection conn) {
>    super.responseReceived(conn);
>    Object attachment = conn.getContext().getAttribute(TAG);
>    if(attachment != null && attachment instanceof DownloadCourse) {
>     DownloadCourse course = (DownloadCourse)attachment;
>     course.prepare(conn.getHttpResponse());
>    }
>   }
>   @Override
>   public void timeout(NHttpClientConnection conn) {
>    super.timeout(conn);
>    Object attachment = conn.getContext().getAttribute(TAG);
>    if(attachment != null && attachment instanceof DownloadCourse) {
>     DownloadCourse course = (DownloadCourse)attachment;
>     course.interrupt();
>    }
>   }
>  };
>  eventDispatch = new DefaultClientIOEventDispatch(handler, params);
>  reactor = new DefaultConnectingIOReactor(1, params);
>  }
>
>  @Override
>  public void run() {
>  log("DownloadClient run at %s", new Date());
>  try {
>   reactor.execute(eventDispatch);
>  } catch(InterruptedIOException e) {
>   //never thrown? even when being interrupted?
>   log("DownloadClient interrupted");
>  } catch(IOException e) {
>   e.printStackTrace();
>  } finally {
>   try {
>    reactor.shutdown();
>   } catch(IOException e) {
>    e.printStackTrace();
>   }
>  }
>  }
>
>  public void execute(DownloadCourse course) {
>  HttpHost host = course.getHost();
>  reactor.connect(
>   new InetSocketAddress(host.getHostName(), host.getPort() > 0 ?
> host.getPort() : 80), null,
>   course, null);
>  }
>
>  public void startup() {
>  dispatcher = new Thread(this, "DownloadClient Thread");
>  dispatcher.setDaemon(true);
>  dispatcher.start();
>  workers = Executors.newFixedThreadPool(2);
>  }
>
>  public void shutdown() {
>  dispatcher.interrupt();
>  workers.shutdown();
>  }
>
>  public void download(URI uri, File saveFile) throws IOException {
>  DownloadCourse course = new DownloadCourse(this, uri, saveFile);
>  workers.submit(course);
>  }
>
>  public static void log(Object s) {
>  System.out.println(s);
>  }
>
>  public static void log(String format, Object... a) {
>  System.out.println(String.format(format, a));
>  }
>
>  public static void main(String[] args) throws Exception {
>  //startup client
>  DownloadClient client = new DownloadClient();
>  client.startup();
>
>  //submit request
>  File saveFile = new File("/sdcard/download.txt");
>  if(!saveFile.exists()) saveFile.createNewFile();
>  client.download(new URI("http://www.google.com/";), saveFile);
>
>  //for a while...
>  Thread.sleep(10000);
>
>  //clear for end
>  client.shutdown();
>  }
>
> }
>
>
> //********** io.DownloadCourse.java **********
> package io;
>
> import static io.DownloadClient.log;
>
> import java.io.File;
> import java.io.IOException;
> import java.io.RandomAccessFile;
> import java.net.URI;
> import java.nio.channels.FileChannel;
> import java.util.Date;
>
> import org.apache.commons.io.FileUtils;
> import org.apache.http.Header;
> import org.apache.http.HttpHost;
> import org.apache.http.HttpRequest;
> import org.apache.http.HttpResponse;
> import org.apache.http.message.BasicHttpRequest;
> import org.apache.http.nio.FileContentDecoder;
>
> public class DownloadCourse implements Runnable {
>
>  public static final int maxRetryTimes = 5;
>  public static final byte QUEUING_STATUS = 0;
>  public static final byte DOWNLOADING = 1;
>  public static final byte PAUSED = 15;
>  public static final byte FINISHED = 127;
>  public static final byte VIOLATED = -1;
>  public static final byte TERMINATED = -128;
>
>  DownloadClient client;
>  URI uri;
>  File file;
>  RandomAccessFile randomAccessFile;
>  FileChannel fileChannel;
>  long contentLength;
>  long position;
>  int status;
>  int retryTimes;
>
>  public DownloadCourse(DownloadClient client, URI uri, File file) {
>  this.client = client;
>  this.uri = uri;
>  this.file = file;
>  status = QUEUING_STATUS;
>  }
>
>  @Override
>  public void run() {
>  log("DownloadCourse run at %s", new Date());
>  status = QUEUING_STATUS;
>  client.execute(this);
>  }
>
>  public HttpHost getHost() {
>  return uri.getPort() > 0 ?
>   new HttpHost(uri.getHost(), uri.getPort()) :
>   new HttpHost(uri.getHost());
>  }
>
>  public HttpRequest getRequest() {
>  HttpRequest request = uri.getQuery() != null ?
>   new BasicHttpRequest("GET", uri.getPath() + "?" + uri.getQuery()) :
>   new BasicHttpRequest("GET", uri.getPath());
>  request.setHeader("Host", getHost().toHostString());
>  return request;
>  }
>
>  public void prepare(HttpResponse response) {
>  Header contentLengthHeader = response.getFirstHeader("Content-Length");
>  if(contentLengthHeader != null) {
>   contentLength = Integer.parseInt(contentLengthHeader.getValue().trim());
>  }
>  try {
>   randomAccessFile = new RandomAccessFile(file, "rw");
>   if(contentLength > 0) {
>    randomAccessFile.setLength(contentLength);
>   }
>   fileChannel = randomAccessFile.getChannel();
>  } catch(IOException e) {
>   throw new RuntimeException(e);
>  }
>  status = DOWNLOADING;
>  }
>
>  public void update(FileContentDecoder content) {
>  long length = 0;
>  try {
>   length = content.transfer(fileChannel, position, contentLength);
>  } catch(IOException e) {
>   throw new RuntimeException(e);
>  }
>  position += length;
>  log("download progress: %d/%d", position, contentLength);
>  }
>
>  public void complete(HttpResponse response) {
>  try {
>   randomAccessFile.close();
>   log(response.getStatusLine().toString());
>   log(new String(FileUtils.readFileToByteArray(file)));
>  } catch(IOException e) {
>   throw new RuntimeException(e);
>  }
>  status = FINISHED;
>  }
>
>  public void error(Exception ex) {
>  try {
>   randomAccessFile.close();
>  } catch(IOException e) {
>   throw new RuntimeException(e);
>  }
>  if(++retryTimes < maxRetryTimes) {
>   status = VIOLATED;
>  } else {
>   status = TERMINATED;
>  }
>  }
>
>  public void interrupt() {
>  try {
>   randomAccessFile.close();
>  } catch(IOException e) {
>   throw new RuntimeException(e);
>  }
>  status = PAUSED;
>  }
>
>  public String toString() {
>  return String.format("%s\n\turi: %s\n\tfile: %s\n\tstatus:
> %d\n\tcontentLength: %d\n\tposition:%d", super.toString(), uri, file,
> status, contentLength, position);
>  }
>
> }
>
>

Reply via email to