views:

291

answers:

4

Hi, I'm trying to implement async http in java. Here is the important part of the code:

for (String urlString : urls) 
{ 
    // TODO: try and get rid of these two heap allocations 
    url = new URL(urlString); 
    request = new HTTPRequest(url); 
    request.addHeader(userAgentHeader); 
    request.addHeader(authorizationHeader); 
    request.addHeader(acceptEncodingHeader); 
    request.addHeader(acceptCharsetHeader); 
    responses.add(URLFetchServiceFactory.getURLFetchService().fetchAsync(reques t)); 
    apiCallsMade++; 
} 
for (Future<HTTPResponse> futureResponse : responses) 
{ 
    parseResponse(new String(futureResponse.get().getContent())); 
} 

I keep getting this error:

com.google.apphosting.api.ApiProxy$CallNotFoundException: The API package 'urlfetch' or call 'Fetch()' was not found.

I looked around for any jars that were missing from the classpath but didn't see anything missing. Do you know which jar that code is in? I googled the error and also searched through this group but found nothing. Thanks, David

A: 

My only guess is that it's due to a Future not completing before attempting to access its response. But that's a complete and utter guess!

Maybe check each of the futureResponses .isDone() and .isCancelled() before accessing its .get().

nicerobot
actually it turned out you can't use the app engine jar's in a console app. the code works great in a typical app engine project setup.
devadvocate
A: 

here's a simple working example of how to do this that I created for my blog:

package org.appEngineAsync.server;

import java.io.ByteArrayInputStream;

import java.io.ByteArrayOutputStream;

import java.net.URL;

import java.util.ArrayList;

import java.util.List;

import java.util.concurrent.CopyOnWriteArrayList;

import java.util.concurrent.Future;

import org.appEngineAsync.client.GreetingService;

import com.google.appengine.api.urlfetch.HTTPHeader;

import com.google.appengine.api.urlfetch.HTTPRequest;

import com.google.appengine.api.urlfetch.HTTPResponse;

import com.google.appengine.api.urlfetch.URLFetchServiceFactory;

import com.google.gwt.user.server.rpc.RemoteServiceServlet;

@SuppressWarnings("serial")

public class GreetingServiceImpl extends RemoteServiceServlet implements GreetingService

{

private HTTPRequest request = null;

HTTPHeader acceptCharsetHeader = new HTTPHeader("Accept-Charset", "utf-8");

// All three of these data types are synchronized for thread safety

List> responses = new CopyOnWriteArrayList>();

protected List tempSingleUrl = new CopyOnWriteArrayList();

StringBuffer sb = new StringBuffer();

public String greetServer(String input) throws Exception

{

List urlsToFetchInParrallel = new ArrayList();

urlsToFetchInParrallel.add("http://gdata.youtube.com/feeds/api/channels?q=" + input + "&start-index=1&max-results=10&v=2");

urlsToFetchInParrallel.add("http://gdata.youtube.com/feeds/api/channels?q=" + input + "&start-index=11&max-results=10&v=2");

urlsToFetchInParrallel.add("http://gdata.youtube.com/feeds/api/channels?q=" + input + "&start-index=21&max-results=10&v=2");

urlsToFetchInParrallel.add("http://gdata.youtube.com/feeds/api/channels?q=" + input + "&start-index=31&max-results=10&v=2");

urlsToFetchInParrallel.add("http://gdata.youtube.com/feeds/api/channels?q=" + input + "&start-index=41&max-results=10&v=2");

urlsToFetchInParrallel.add("http://gdata.youtube.com/feeds/api/channels?q=" + input + "&start-index=51&max-results=10&v=2");

urlsToFetchInParrallel.add("http://gdata.youtube.com/feeds/api/channels?q=" + input + "&start-index=61&max-results=10&v=2");

urlsToFetchInParrallel.add("http://gdata.youtube.com/feeds/api/channels?q=" + input + "&start-index=71&max-results=10&v=2");

urlsToFetchInParrallel.add("http://gdata.youtube.com/feeds/api/channels?q=" + input + "&start-index=81&max-results=10&v=2");

urlsToFetchInParrallel.add("http://gdata.youtube.com/feeds/api/channels?q=" + input + "&start-index=91&max-results=10&v=2");

return performHttpRequest(urlsToFetchInParrallel);

}

// pass in 10 urls at a time

private final String performHttpRequest(List urls) throws NumberFormatException, Exception

{

URL url = null;

request = null;

byte[] tempBuffer = null;

byte[] buffer = null;

ByteArrayInputStream memoryStream = null;

ByteArrayOutputStream baos = null;

final int buffSize = 8192;

int size = 0;

sb.setLength(0);

responses.clear();

try

{

for (String urlString : urls)

{

url = new URL(urlString);

request = new HTTPRequest(url);

request.addHeader(acceptCharsetHeader);

responses.add(URLFetchServiceFactory.getURLFetchService().fetchAsync(request));

}

for (Future futureResponse : responses)

{

try

{

memoryStream = new ByteArrayInputStream(futureResponse.get().getContent());

tempBuffer = new byte[buffSize];

baos = new ByteArrayOutputStream();

while ((size = memoryStream.read(tempBuffer, 0, buffSize)) != -1)

{

baos.write(tempBuffer, 0, size);

}

buffer = baos.toByteArray();

} catch (Exception ex)

{

// TODO: log or take other action

return null;

} finally

{

try

{

baos.close();

} catch (Exception ex)

{

// TODO: log

}

}

// TODO: put this on one line when done debugging

String responseString = new String(buffer, "UTF-8");

sb.append(responseString);

}

// TODO: put this on one line when done debugging

String allResponsesString = sb.toString();

return allResponsesString;

} catch (Exception ex)

{

// TODO: log

return null;

} finally

{

try

{

request = null;

url = null;

memoryStream = null;

tempBuffer = null;

baos = null;

} catch (Exception ex)

{

// TODO: log

return null;

}

}

}

}

devadvocate
A: 

Syntax highlighted version of the same answer given above.

package org.appEngineAsync.server;

import java.io.ByteArrayInputStream;

import java.io.ByteArrayOutputStream;

import java.net.URL;

import java.util.ArrayList;

import java.util.List;

import java.util.concurrent.CopyOnWriteArrayList;

import java.util.concurrent.Future;

import org.appEngineAsync.client.GreetingService;

import com.google.appengine.api.urlfetch.HTTPHeader;

import com.google.appengine.api.urlfetch.HTTPRequest;

import com.google.appengine.api.urlfetch.HTTPResponse;

import com.google.appengine.api.urlfetch.URLFetchServiceFactory;

import com.google.gwt.user.server.rpc.RemoteServiceServlet;

@SuppressWarnings("serial")

public class GreetingServiceImpl extends RemoteServiceServlet implements GreetingService

{

private HTTPRequest request = null;

HTTPHeader acceptCharsetHeader = new HTTPHeader("Accept-Charset", "utf-8");

// All three of these data types are synchronized for thread safety

List> responses = new CopyOnWriteArrayList>();

protected List tempSingleUrl = new CopyOnWriteArrayList();

StringBuffer sb = new StringBuffer();

public String greetServer(String input) throws Exception

{

List urlsToFetchInParrallel = new ArrayList();

urlsToFetchInParrallel.add("http://gdata.youtube.com/feeds/api/channels?q=" + input + "&start-index=1&max-results=10&v=2");

urlsToFetchInParrallel.add("http://gdata.youtube.com/feeds/api/channels?q=" + input + "&start-index=11&max-results=10&v=2");

urlsToFetchInParrallel.add("http://gdata.youtube.com/feeds/api/channels?q=" + input + "&start-index=21&max-results=10&v=2");

urlsToFetchInParrallel.add("http://gdata.youtube.com/feeds/api/channels?q=" + input + "&start-index=31&max-results=10&v=2");

urlsToFetchInParrallel.add("http://gdata.youtube.com/feeds/api/channels?q=" + input + "&start-index=41&max-results=10&v=2");

urlsToFetchInParrallel.add("http://gdata.youtube.com/feeds/api/channels?q=" + input + "&start-index=51&max-results=10&v=2");

urlsToFetchInParrallel.add("http://gdata.youtube.com/feeds/api/channels?q=" + input + "&start-index=61&max-results=10&v=2");

urlsToFetchInParrallel.add("http://gdata.youtube.com/feeds/api/channels?q=" + input + "&start-index=71&max-results=10&v=2");

urlsToFetchInParrallel.add("http://gdata.youtube.com/feeds/api/channels?q=" + input + "&start-index=81&max-results=10&v=2");

urlsToFetchInParrallel.add("http://gdata.youtube.com/feeds/api/channels?q=" + input + "&start-index=91&max-results=10&v=2");

return performHttpRequest(urlsToFetchInParrallel);

}

// pass in 10 urls at a time

private final String performHttpRequest(List urls) throws NumberFormatException, Exception

{

URL url = null;

request = null;

byte[] tempBuffer = null;

byte[] buffer = null;

ByteArrayInputStream memoryStream = null;

ByteArrayOutputStream baos = null;

final int buffSize = 8192;

int size = 0;

sb.setLength(0);

responses.clear();

try

{

for (String urlString : urls)

{

url = new URL(urlString);

request = new HTTPRequest(url);

request.addHeader(acceptCharsetHeader);

responses.add(URLFetchServiceFactory.getURLFetchService().fetchAsync(request));

}

for (Future futureResponse : responses)

{

try

{

memoryStream = new ByteArrayInputStream(futureResponse.get().getContent());

tempBuffer = new byte[buffSize];

baos = new ByteArrayOutputStream();

while ((size = memoryStream.read(tempBuffer, 0, buffSize)) != -1)

{

baos.write(tempBuffer, 0, size);

}

buffer = baos.toByteArray();

} catch (Exception ex)

{

// TODO: log or take other action

return null;

} finally

{

try

{

baos.close();

} catch (Exception ex)

{

// TODO: log

}

}

// TODO: put this on one line when done debugging

String responseString = new String(buffer, "UTF-8");

sb.append(responseString);

}

// TODO: put this on one line when done debugging

String allResponsesString = sb.toString();

return allResponsesString;

} catch (Exception ex)

{

// TODO: log

return null;

} finally

{

try

{

request = null;

url = null;

memoryStream = null;

tempBuffer = null;

baos = null;

} catch (Exception ex)

{

// TODO: log

return null;

}

}

}

}
Wilfred Springer
A: 

I also get the same exception

com.google.apphosting.api.ApiProxy$CallNotFoundException: The API package 'urlfetch' or call 'Fetch()' was not found even when I run the sample code by devadvocate

Reuben