EDIT: used different decompiler now includes the Util$OS.class file
I am trying to modify the mine craft launcher to check for a minecraft folder in the current working directory and if none exists then use the established routines to Crete and download the needed files. This is my first foray into java programing so I am feeling a bit lost. Here is the source of the offending class file: (the block that i think needs modifying starts on line 15)
File Util.class
package net.minecraft;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.lang.reflect.Method;
import java.net.URI;
import java.net.URL;
import java.security.PublicKey;
import java.security.cert.Certificate;
import javax.net.ssl.HttpsURLConnection;
public class Util
{
private static File workDir = null;
public static File getWorkingDirectory() {
if (workDir == null) workDir = getWorkingDirectory("minecraft");
return workDir;
}
public static File getWorkingDirectory(String applicationName) {
String userHome = System.getProperty("user.home", ".");
File workingDirectory;
File workingDirectory;
File workingDirectory;
File workingDirectory;
switch ($SWITCH_TABLE$net$minecraft$Util$OS()[getPlatform().ordinal()]) {
case 1:
case 2:
workingDirectory = new File(userHome, '.' + applicationName + '/');
break;
case 3:
String applicationData = System.getenv("APPDATA");
File workingDirectory;
if (applicationData != null) workingDirectory = new File(applicationData, "." + applicationName + '/'); else
workingDirectory = new File(userHome, '.' + applicationName + '/');
break;
case 4:
workingDirectory = new File(userHome, "Library/Application Support/" + applicationName);
break;
default:
workingDirectory = new File(userHome, applicationName + '/');
}
if ((!workingDirectory.exists()) && (!workingDirectory.mkdirs())) throw new RuntimeException("The working directory could not be created: " + workingDirectory);
return workingDirectory;
}
private static OS getPlatform() {
String osName = System.getProperty("os.name").toLowerCase();
if (osName.contains("win")) return OS.windows;
if (osName.contains("mac")) return OS.macos;
if (osName.contains("solaris")) return OS.solaris;
if (osName.contains("sunos")) return OS.solaris;
if (osName.contains("linux")) return OS.linux;
if (osName.contains("unix")) return OS.linux;
return OS.unknown;
}
public static String excutePost(String targetURL, String urlParameters)
{
HttpsURLConnection connection = null;
try
{
URL url = new URL(targetURL);
connection = (HttpsURLConnection)url.openConnection();
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
connection.setRequestProperty("Content-Length", Integer.toString(urlParameters.getBytes().length));
connection.setRequestProperty("Content-Language", "en-US");
connection.setUseCaches(false);
connection.setDoInput(true);
connection.setDoOutput(true);
connection.connect();
Certificate[] certs = connection.getServerCertificates();
byte[] bytes = new byte[294];
DataInputStream dis = new DataInputStream(Util.class.getResourceAsStream("minecraft.key"));
dis.readFully(bytes);
dis.close();
Certificate c = certs[0];
PublicKey pk = c.getPublicKey();
byte[] data = pk.getEncoded();
for (int i = 0; i < data.length; i++) {
if (data[i] == bytes[i]) continue; throw new RuntimeException("Public key mismatch");
}
DataOutputStream wr = new DataOutputStream(connection.getOutputStream());
wr.writeBytes(urlParameters);
wr.flush();
wr.close();
InputStream is = connection.getInputStream();
BufferedReader rd = new BufferedReader(new InputStreamReader(is));
StringBuffer response = new StringBuffer();
String line;
while ((line = rd.readLine()) != null)
{
String line;
response.append(line);
response.append('\r');
}
rd.close();
String str1 = response.toString();
return str1;
}
catch (Exception e)
{
e.printStackTrace();
return null;
}
finally
{
if (connection != null)
connection.disconnect();
}
throw localObject;
}
public static boolean isEmpty(String str) {
return (str == null) || (str.length() == 0);
}
public static void openLink(URI uri) {
try {
Object o = Class.forName("java.awt.Desktop").getMethod("getDesktop", new Class[0]).invoke(null, new Object[0]);
o.getClass().getMethod("browse", new Class[] { URI.class }).invoke(o, new Object[] { uri });
} catch (Throwable e) {
System.out.println("Failed to open link " + uri.toString());
}
}
private static enum OS
{
linux, solaris, windows, macos, unknown;
}
}
I have done some research on getting the current working directory but i am not sure what needs modifing. If someone could at least explain what the various parts of the file mean that would be very helpful.
public static File getWorkingDirectory(String applicationName) {
File workingDirectory = new File("." + File.separator + applicationName);
if ((!workingDirectory.exists()) && (!workingDirectory.mkdirs()))
throw new RuntimeException("The working directory could not be created: " + workingDirectory);
return workingDirectory;
}
Sorry for the confusion, this should work just fine for you.
It will create a minecraft folder in the same directory as your launcher.
Note: On OS X this will still create the folder in the folder as the .app, not the .app/Contents/Resources/Java folder that the actual JAR is in, so you wont have any problem on any operating system.
Hope this helps!
I'm still not completely sure I understand your goals.
If you want to have it download "Minecraft" for you I'd try to do it in a batch file and shell script and just run the one that was appropriate for your system.
If you want to somehow "download" your worlds, texture packs and mods from somewhere then you could do the same.
If what you want is for every minecraft install you are playing on to use your data (like on a USB stick or something) you might have batch files that either copy over the data before running minecraft or perhaps use "ln" to replace the directories that minecraft thinks it's going to use with your own on your usb stick.
You can always modify the field that points to the directory where MC puts its saves and change it to whatever you want. Here's a snippet from my launcher (http://www.github.com/lekro/ModdishLauncher):
ClassLoader cl = new URLClassLoader(urls, ModdishLauncher.class.getClassLoader());
Class<?> mc = null;
try {
mc = cl.loadClass("net.minecraft.client.Minecraft");
} catch (ClassNotFoundException e2) {
System.err.println("Couldn't find Minecraft main class!");
e2.printStackTrace();
}
Field[] fields = mc.getDeclaredFields();
Field mcPathField = null;
for (int i = 0; i < fields.length; i++) {
Field f = fields[i];
if (f.getType() != File.class) {
continue;
}
if (f.getModifiers() != (Modifier.PRIVATE + Modifier.STATIC)) {
continue;
}
mcPathField = f;
break;
}
mcPathField.setAccessible(true);
try {
mcPathField.set(null, new File(myDir + "/minecrafts/"+minecraftType+"/"));
} catch (IllegalArgumentException e2) {
e2.printStackTrace();
} catch (IllegalAccessException e2) {
e2.printStackTrace();
}
This takes the hardcoded path field inside the Minecraft class and modifies it to whatever you want it to be. (e.g. on a USB stick, in a custom folder, etc.)
Related
I'm trying to put the progressmonitor inputstream in my code, but everything I've done I can't. I'm very new to java programming and have some difficulties implementing certain things in my code.
Apart from this inability to use inputstream, the code works correctly the way I need it. So I would like to see the download progress as it has the exceptions in case the download fails or server down.
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package javatar.language.download;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import javax.swing.JOptionPane;
/**
*
* #author Bruno
*/
public class UrlInput {
public static void main(String[] args) {
String userSys = System.getenv("USERNAME");
String sysDrive = System.getenv("SYSTEMDRIVE");
String downPath = sysDrive + "/Users/" + userSys + "/Downloads";
try {
URL url = new URL("http://akamai-gamecdn.blackdesertonline.com/live001/game/config/config.language.version");
try ( // read text returned by server
BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream()))) {
String line;
while ((line = in.readLine()) != null) {
String versao = line;
JOptionPane.showMessageDialog(null, "Actual version BDO-NA: " + versao);
String fileURL = "http://akamai-gamecdn.blackdesertonline.com/live001/game/language/BDOLanguage_" + versao + ".zip";
String saveDIR = downPath;
SysDownload.downloadFile(fileURL, saveDIR);
}
}
} catch (MalformedURLException e) {
JOptionPane.showMessageDialog(null, "Malformed URL: " + e.getMessage());
} catch (IOException e) {
JOptionPane.showMessageDialog(null, "Error I/O: " + e.getMessage());
}
}
}
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package javatar.language.download;
import java.io.*;
import java.net.*;
import javax.swing.*;
/**
*
* #author Bruno
*/
public class SysDownload {
private static final int BUFFER_SIZE = 4096;
public static void downloadFile(String fileURL, String saveDIR) throws IOException {
URL link = new URL(fileURL);
HttpURLConnection conn = (HttpURLConnection) link.openConnection();
int responseCode = conn.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK) {
String fileName = "";
String server = conn.getHeaderField("Server");
String connectionType = conn.getContentType();
int contentLenght = conn.getContentLength();
JOptionPane.showMessageDialog(null, "Server name: " + server);
if (server != null) {
int index = server.indexOf("filename");
if (index > 0) {
fileName = server.substring(index + 10, server.length() - 1);
} else {
fileName = fileURL.substring(fileURL.lastIndexOf("/") + 1, fileURL.length());
}
try (InputStream inputStream = conn.getInputStream()) {
String savePath = saveDIR + File.separator + fileName;
try (FileOutputStream outputStream = new FileOutputStream(savePath)) {
int bytesRead = - 1;
byte[] buffer = new byte[BUFFER_SIZE];
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
}
}
JOptionPane.showMessageDialog(null, "File " + fileName + " has been downloaded.\nSee users Download folder.");
} else {
JOptionPane.showMessageDialog(null, "None file downloaded.\nServer HTTP code: " + responseCode + JOptionPane.ERROR_MESSAGE);
}
conn.disconnect();
}
}
}
First, consult the documentation of ProgressMonitorInputStream.
The constructor requires three arguments. Like JOptionPane, the first argument is the dialog parent, which appers to be null in your application.
The second argument is the message. In your case, "Downloading " + link is probably sufficient.
The third argument is the InputStream to monitor. This should be the InputStream from which you are downloading.
The ProgressMonitor’s maximum should be the size of the download, which you can obtain from the getContentLength() method of URLConnection.
You don’t need to write your loop to save an InputStream to a file. You can use Files.copy for that.
So, putting it all together, it looks like this:
try (ProgressMonitorInputStream inputStream =
new ProgressMonitorInputStream(null,
"Downloading " + link,
conn.getInputStream())) {
inputStream.getProgressMonitor().setMaximum(conn.getContentLength());
Files.copy(inputStream, Paths.get(savePath));
}
I am attempting to use classes from a .jar file in a my .java file Tweetauthent. The .jar file is in another directory. I make a request to the Twitter rest api to obtain a bearertoken. Tweetauthent compiles when I run
-javac -cp /path/to/jar Tweetauthent.java
This is the code
import java.io.BufferedReader;
import java.lang.StringBuilder;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.URLEncoder;
public class Tweetauthent{
static String consumerkey = "astring";
static String consumersecret = "astring";
static String endurl = "https://api.twitter.com/oauth2/token";
public static void main(String []args){
Tweetauthent t = new Tweetauthent();
try{
System.out.println(t.requestBearerToken(endurl));
}catch(IOException e){
System.out.println(e);
}
}
public static String encodeKeys(String consumerKey,String consumerSecret){
try{
String encodedConsumerKey = URLEncoder.encode(consumerKey,"UTF-8");
String encodedConsumerSecret = URLEncoder.encode(consumerSecret,"UTF-8");
String fullKey = encodedConsumerKey + ":" + encodedConsumerSecret;
byte[] encodedBytes = Base64.getEncoder().encode(fullKey.getBytes());
return new String(encodedBytes);
}catch(UnsupportedEncodingException e){
return new String();
}
}
public static String requestBearerToken(String endPointURL) throws IOException {
HttpsURLConnection connection = null;
String encodedCredentials = encodeKeys("<consumerkey>","<consumersecret>");
try{
URL url = new URL(endPointURL);
connection = (HttpsURLConnection)url.openConnection();
connection.setDoOutput(true);
connection.setDoInput(true);
connection.setRequestProperty("Host","api.twitter.com");
connection.setRequestProperty("User-Agent","TweetPersonalityAnalyzer");
connection.setRequestProperty("Authorization","Basic " + encodedCredentials);
connection.setRequestProperty("Content-Type","application/x-www-form-urlencoded;charset=UTF-8");
connection.setRequestProperty("Content-Length","29");
writeRequest(connection, "grant_type=client_credentials");
JSONObject obj = (JSONObject)JSONValue.parse(readResponse(connection));
if(obj != null){
String tokenType = (String)obj.get("token_type");
String token = (String)obj.get("access_token");
return ((tokenType.equals("bearer")) && (token != null)) ? token : "";
}
return new String();
}catch(MalformedURLException e){
throw new IOException("Invalid endpoint URL specified.", e);
}
finally{
if( connection != null){
connection.disconnect();
}
}
}
public static boolean writeRequest(HttpsURLConnection connection, String textBody){
try{
BufferedWriter wr = new BufferedWriter(new OutputStreamWriter(connection.getOutputStream()));
wr.write(textBody);
wr.flush();
wr.close();
return true;
}
catch(IOException e){
return false;
}
}
public static String readResponse(HttpsURLConnection connection){
try {
StringBuilder str = new StringBuilder();
BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String line = "";
while((line = br.readLine()) != null){
str.append(line + System.getProperty("line.separator"));
}
return str.toString();
}catch(IOException e){
return new String();
}
}
The error I get when I run
java Tweetauthent
is
java.lang.NoClassDefFoundError: org/json/simple/JSONValue
at Tweetauthent.requestBearerToken(Tweetauthent.java:61)
at Tweetauthent.main(Tweetauthent.java:27)
Caused by: java.lang.ClassNotFoundException:
org.json.simple.JSONValue
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:335)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
... 2 more
From what I understand the NoClassDefFoundError is thrown when the JVM cant find neccesary class files that the .java file used to compile. What would be causing this? Is there a way to add the path of the jar too -java? Oh and with expected consumerkey and secret strings.
UPDATE: when I add the classpath to java
java /path/to/jar Tweethauthent
I get Error: could not find or load main class Tweetauthent
Any help would be greatly appreciated thank you!
You have a run time class path issue.
I don't see how you've set the runtime classpath. The fact that you compiled is necessary, but insufficient.
Either you don't have the runtime classpath set properly or the JAR is not part of your package.
You need to reference the runtime dependencies in -classpath or -cp option of the java command:
java -classpath /path/to/jar Tweetauthent
If you want to run with arguments add them as parameter after the Java file:
java -classpath /path/to/jar Tweetauthent <consumerkey> <consumersecret>
I have created a few files for temporary use and used them as inputs for some methods. And I called
deleteOnExit()
on all files I created. But one file still remains.
I assume it is because the file is still in use, but doesn't the compiler go to next line only after the current line is done?(Single thread)
While its not a problem practically because of java overwrite, there is only one file always. I would like to understand why it happens and also if I can use
Thread.sleep(sometime);
Edit:-
File x = new file("x.txt");
new class1().method1();
After creating all files(5), I just added this line
x.deleteOnExit(); y.deletOnExit() and so on...
All the files except that last one is deleted.
Make sure that whatever streams are writing to the file are closed. If the stream is not closed, file will be locked and delete will return false. That was an issue I had. Hopefully that helps.
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.StringWriter;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
public class Test {
public static void main(String[] args) {
File reportNew = null;
File writeToDir = null;
BufferedReader br = null;
BufferedWriter bw = null;
StringWriter sw = null;
List<File> fileList = new ArrayList<File>();
SimpleDateFormat ft = new SimpleDateFormat("yyyymmdd_hh_mm_ss_ms");
try {
//Read report.new file
reportNew = new File("c:\\temp\\report.new");
//Create temp directory for newly created files
writeToDir = new File("c:\\temp");
//tempDir.mkdir();
//Separate report.new into many files separated by a token
br = new BufferedReader(new FileReader(reportNew));
sw = new StringWriter();
new StringBuilder();
String line;
int fileCount = 0;
while (true) {
line=br.readLine();
if (line == null || line.contains("%PDF")) {
if (!sw.toString().isEmpty()) {
fileCount++;
File _file = new File(writeToDir.getPath()
+ File.separator
+ fileCount
+ "_"
+ ft.format(new Date())
+ ".htm");
_file.deleteOnExit();
fileList.add(_file);
bw = new BufferedWriter(new FileWriter(_file));
bw.write(sw.toString());
bw.flush();
bw.close();
sw.getBuffer().setLength(0);
System.out.println("File "
+ _file.getPath()
+ " exists "
+ _file.exists());
}
if (line == null)
break;
else
continue;
}
sw.write(line);
sw.write(System.getProperty("line.separator"));
}
} catch ( Exception e) {
e.printStackTrace();
} finally {
if (bw != null) {
try {
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
In order to close the file that you have opened in your program, try creating an explicit termination method.
Therefore, try writing the following:
public class ClassThatUsesFile {
private String filename;
private BufferReader reader;
public ClassThatUsesFile (String afile) {
this.filename = afile;
this.reader = new BufferReader(new FileReader(afile));
}
// try-finally block guarantees execution of termination method
protected void terminate() {
try {
// Do what must be done with your file before it needs to be closed.
} finally {
// Here is where your explicit termination method should be located.
// Close or delete your file and close or delete your buffer reader.
}
}
}
I am using Jsoup Java HTML parser to fetch images from a particular URL. But some of the images are throwing a status 502 error code and are not saved to my machine. Here is the code snapshot i have used:-
String url = "http://www.jabong.com";
String html = Jsoup.connect(url.toString()).get().html();
Document doc = Jsoup.parse(html, url);
images = doc.select("img");
for (Element element : images) {
String imgSrc = element.attr("abs:src");
log.info(imgSrc);
if (imgSrc != "") {
saveFromUrl(imgSrc, dirPath+"/" + nameCounter + ".jpg");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
log.error("error in sleeping");
}
nameCounter++;
}
}
And the saveFromURL function looks like this:-
public static void saveFromUrl(String Url, String destinationFile) {
try {
URL url = new URL(Url);
InputStream is = url.openStream();
OutputStream os = new FileOutputStream(destinationFile);
byte[] b = new byte[2048];
int length;
while ((length = is.read(b)) != -1) {
os.write(b, 0, length);
}
is.close();
os.close();
} catch (IOException e) {
log.error("Error in saving file from url:" + Url);
//e.printStackTrace();
}
}
I searched on internet about status code 502 but it says error is due to bad gateway. I don't understand this. One of the possible things i am thinking that this error may be because of I am sending get request to images in loop. May be webserver is not able handle to this much load so denying the request to the images when previous image is not sent.So I tried to put sleep after fetching every image but no luck :(
Some advices please
Here's a full code example that works for me...
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.Authenticator;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.MalformedURLException;
import java.net.Proxy;
import java.net.SocketAddress;
import java.net.URL;
public class DownloadImage {
public static void main(String[] args) {
// URLs for Images we wish to download
String[] urls = {
"http://cdn.sstatic.net/stackoverflow/img/apple-touch-icon.png",
"http://www.google.co.uk/images/srpr/logo3w.png",
"http://i.microsoft.com/global/en-us/homepage/PublishingImages/sprites/microsoft_gray.png"
};
for(int i = 0; i < urls.length; i++) {
downloadFromUrl(urls[i]);
}
}
/*
Extract the file name from the URL
*/
private static String getOutputFileName(URL url) {
String[] urlParts = url.getPath().split("/");
return "c:/temp/" + urlParts[urlParts.length-1];
}
/*
Assumes there is no Proxy server involved.
*/
private static void downloadFromUrl(String urlString) {
InputStream is = null;
FileOutputStream fos = null;
try {
URL url = new URL(urlString);
System.out.println("Reading..." + url);
HttpURLConnection conn = (HttpURLConnection)url.openConnection(proxy);
is = conn.getInputStream();
String filename = getOutputFileName(url);
fos = new FileOutputStream(filename);
byte[] readData = new byte[1024];
int i = is.read(readData);
while(i != -1) {
fos.write(readData, 0, i);
i = is.read(readData);
}
System.out.println("Created file: " + filename);
}
catch (MalformedURLException e) {
e.printStackTrace();
}
catch (IOException e) {
e.printStackTrace();
}
finally {
if(is != null) {
try {
is.close();
} catch (IOException e) {
System.out.println("Big problems if InputStream cannot be closed");
}
}
if(fos != null) {
try {
fos.close();
} catch (IOException e) {
System.out.println("Big problems if FileOutputSream cannot be closed");
}
}
}
System.out.println("Completed");
}
}
You should see the following ouput on your console...
Reading...http://cdn.sstatic.net/stackoverflow/img/apple-touch-icon.png
Created file: c:/temp/apple-touch-icon.png
Completed
Reading...http://www.google.co.uk/images/srpr/logo3w.png
Created file: c:/temp/logo3w.png
Completed
Reading...http://i.microsoft.com/global/en-us/homepage/PublishingImages/sprites/microsoft_gray.png
Created file: c:/temp/microsoft_gray.png
Completed
So that's a working example without a Proxy server involved.
Only if you require authentication with a proxy server here's an additional Class that you'll need based on this Oracle technote
import java.net.Authenticator;
import java.net.PasswordAuthentication;
public class ProxyAuthenticator extends Authenticator {
private String userName, password;
public ProxyAuthenticator(String userName, String password) {
this.userName = userName;
this.password = password;
}
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(userName, password.toCharArray());
}
}
And to use this new Class you would use the following code in place of the call to openConnection() shown above
...
try {
URL url = new URL(urlString);
System.out.println("Reading..." + url);
Authenticator.setDefault(new ProxyAuthenticator("username", "password");
SocketAddress addr = new InetSocketAddress("proxy.server.com", 80);
Proxy proxy = new Proxy(Proxy.Type.HTTP, addr);
HttpURLConnection conn = (HttpURLConnection)url.openConnection(proxy);
...
Your problem sounds like HTTP communication issues, so you are probably better off trying to use a library to handle the communication side of things. Take a look at Apache Commons HttpClient.
Some notes about your code example. You haven't used a URLConnection object so it's not clear what the behaviour will be in regards to the Web/Proxy servers and closing resources cleanly, etc. The HttpCommon library mentioned will help in this aspect.
There also seems to be some examples of doing what you want using J2ME libararies. Not something I have used personally but may also help you out.
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
With Google appengine, you cannot use those api's in the local java applications. This will work only when you develop and deploy web application using google appengine sdk. This is designed to work this way only.
When you use this api, it will make use of http client and in case of app engine environment, it will make use of google infrastructure. If you still want to unit test the application designed for google appengine you might consider using LocalURLServiceFactory.
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<Future<HTTPResponse>> responses = new CopyOnWriteArrayList<Future<HTTPResponse>>();
protected List<String> tempSingleUrl = new CopyOnWriteArrayList<String>();
StringBuffer sb = new StringBuffer();
public String greetServer(String input) throws Exception
{
List<String> urlsToFetchInParrallel = new ArrayList<String>();
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<String> 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<HTTPResponse> 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;
}
}
}
}
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().