Getting UnknownHostException instead of SocketTimeOutExcepetion - java

I am new to android and Java. And I am trying to learn android app development from UDACITY. I was trying to run this code and I am expecting a SocketTimeOutExcepetion but what I am getting is UnknownHostException.
try {
final String BASE_URL = "http://api.openweathermap.org/data/2.5/forecast/daily?";
final String ZIP = "zip";
final String MODE = "mode";
final String UNITS = "units";
final String COUNT = "cnt";
final String APP_ID = "appid";
Uri builtUri = Uri.parse(BASE_URL).buildUpon()
.appendQueryParameter(ZIP, params[0] + ",in")
.appendQueryParameter(MODE,format)
.appendQueryParameter(UNITS, units)
.appendQueryParameter(COUNT, Integer.toString(numDays))
.appendQueryParameter(APP_ID, BuildConfig.OPEN_WEATHER_MAP_API_KEY)
.build();
String str = java.net.URLDecoder.decode(builtUri.toString());
URL url = new URL(str);
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestMethod("GET");
urlConnection.setConnectTimeout(5000);
urlConnection.setReadTimeout(5000);
urlConnection.connect();
InputStream inputStream = urlConnection.getInputStream();
StringBuffer buffer = new StringBuffer();
if (inputStream == null) {
return null;
}
reader = new BufferedReader(new InputStreamReader(inputStream));
String line;
while ((line = reader.readLine()) != null)
buffer.append(line + "/n");
if (buffer.length() == 0)
return null;
forecastJsonStr = buffer.toString();
Log.v(LOG_TAG,"JSON forcast string:" +forecastJsonStr);
}catch(SocketTimeoutException e) {
startActivity(new Intent(getActivity(),CheckNet.class));
} catch (IOException e) {
Log.e("FetchWeatherTask", "Error:" + e.toString());
return null;
}
I tested it on my phone running Android version 4.0.4. And while testing I had my mobile data and wifi off

When your mobile data and wifi are turned off, the socket layer is unable to resolve internet addresses (e.g. "openweathermap.org") into an IP address. This is why you get an UnknownHostException.
Whereas, when you're on a network, and it's able to resolve IP addresses, and the server fails to reply, you will get a SocketTimeoutException.

If you want to simulate the exception do the following:
Disconnect your data and connect your Wi-Fi
Edit your setting of your Wi-Fi connection
Change to static IP and put 169.254.0.50 for IP, 255.255.0.0 for subnet and 169.254.0.1 for gateway
Change the BASE_URL = "192.241.169.168/data/2.5/forecast/daily?"
Run your app

Related

Handle HttpURLConnection redirect (NASA open API)

I'm writing a Java application that communicates with the NASA open apis. I've a class named NASAClient which exposes the required interface to achieve this task, but I'm facing with the following problem when dealing with the Earth Imagery API.
public EarthImageryResponseObject earthImagery(double lon, double lat, String year, String mon, String day, boolean cloud_score) {
String cs;
if(cloud_score) cs = "True";
else cs = "False";
String url = "https://api.nasa.gov/planetary/earth/imagery?lon="
+ lon
+ "&lat="
+ lat
+ "&date="
+ year+"-"+mon+"-"+day
+ "&cloud_score="
+ cs
+ "&api_key=" + api_key;
try {
String json = (read(getConnection(url)));
return gson.fromJson(json, EarthImageryResponseObject.class);
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
private String read(HttpURLConnection conn) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader((conn.getInputStream())));
return readFromBufferedReader(br);
}
private String readFromBufferedReader(BufferedReader br) throws IOException {
StringBuilder sb = new StringBuilder();
String line = br.readLine();
while (line != null) {
sb.append(line);
line = br.readLine();
}
return sb.toString();
}
private HttpURLConnection getConnection(String url) throws IOException {
HttpURLConnection connection;
connection = createConnection(url);
this.availability = connection.getHeaderField("X-RateLimit-Remaining");
connection.setConnectTimeout(2000);
this.last_resp = connection.getResponseCode();
return connection;
}
private HttpURLConnection createConnection(String url) throws IOException {
URL UniformResourceLocation = new URL(url);
return (HttpURLConnection) UniformResourceLocation.openConnection();
}
When I call earthImagery with some standard parameters, I get the following url:
https://api.nasa.gov/planetary/earth/imagery?lon=100.75&lat=1.5&date=2017-01-01&cloud_score=False&api_key=[MY_KEY]
If I navigate to this url using curl or the browser, I get the expected Json serialized object, but when invoked within my application, I get a redirection link (with 301 response code) to an heroku app:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"><title>Redirecting...</title><h1>Redirecting...</h1><p>You should be redirected automatically to target URL: http://earth-imagery-api.herokuapp.com/earth/imagery/?lon=100.75&lat=1.5&date=2017-01-01&cloud_score=False. If not click the link.
If I try to open a connection to such link, as explained here ,or open it in a browser it returns an error message (parameters are wrong). Really don't know what I am doing wrong. This strategy is the same for the other API I'm using in the application, and they work. Here it follows the stacktrace
Exception in thread "Thread-1" com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 1 column 1 path $
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:226)
at com.google.gson.Gson.fromJson(Gson.java:927)
at com.google.gson.Gson.fromJson(Gson.java:892)
at com.google.gson.Gson.fromJson(Gson.java:841)
at com.google.gson.Gson.fromJson(Gson.java:813)
at com.alexfoglia.nasaapi.NASAClient.earthImagery(NASAClient.java:151)
at com.alexfoglia.nasaapi.gui.EarthPanel.lambda$2(EarthPanel.java:127)
at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 1 column 1 path $
at com.google.gson.stream.JsonReader.beginObject(JsonReader.java:385)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:215)
... 7 more
And that's because i'm expecting a Json object, but I get a String (html redirect page).
If you want your code to automatically follow redirects then set this flag
connection.setFollowRedirects (true);
https://developer.android.com/reference/java/net/HttpURLConnection.html#setFollowRedirects(boolean)
I solved using both HttpURLConnection and SSLSocket. The first connection obtain the redirect link, that is reached not by another httpurlconnection, instead, a SSLSocket is used to get to this link.
public EarthImageryResponseObject earthImagery(double lon, double lat, String year, String mon, String day, boolean cloud_score) {
String cs;
if(cloud_score) cs = "True";
else cs = "False";
String url = "https://api.nasa.gov/planetary/earth/imagery?lon="
+ lon
+ "&lat="
+ lat
+ "&date="
+ year+"-"+mon+"-"+day
+ "&cloud_score="
+ cs
+ "&api_key=" + api_key;
try {
HttpURLConnection conn = getConnection(url);
String new_url = conn.getHeaderField("Location");
SSLSocketFactory factory =
(SSLSocketFactory)SSLSocketFactory.getDefault();
SSLSocket socket =
(SSLSocket)factory.createSocket("api.nasa.gov", 443);
socket.startHandshake();
socket.getOutputStream().write(("GET "+new_url+"\n").getBytes());
BufferedReader in = new BufferedReader(
new InputStreamReader(
socket.getInputStream()));
StringBuilder sb = new StringBuilder();
String inputLine;
while ((inputLine = in.readLine()) != null)
sb.append(inputLine);
in.close();
socket.close();
String json = sb.toString();
System.out.println(json);
return gson.fromJson(json, EarthImageryResponseObject.class);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}

java.io.FileNotFoundException: When using real server

I am beginner in Java and Android Studio. I have written a code by Android Studio and Wamp as server and Genymotion as simulator. all codes work fine and I can interact with mysql by use of my .php files
Then I decide to transfer codes to real server.
but I get this error:
java.io.FileNotFoundException: http://burj.1shahrvand.com/Burj/BikerLogin.php
The File is available check it here but I get Exception that file not found
The code is like this:
String uri = rp.getUri();
if(rp.getMethod().equals("GET")){
uri += "?" + rp.getEncodedParams();
}
HttpURLConnection connection;
try {
URL url = new URL(uri);
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod(rp.getMethod());
if (rp.getMethod().equals("POST")){
connection.setDoOutput(true);
connection.setDoInput(true);
OutputStreamWriter writer = new OutputStreamWriter(connection.getOutputStream());
writer.write(rp.getEncodedParams());
writer.flush();
}
BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String line;
StringBuilder sb = new StringBuilder();
while ((line = reader.readLine()) != null) {
sb.append(line);
}
return sb.toString();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
Log.i("HESAM Original", e.getMessage());
e.printStackTrace();
}
return null;
I appreciate your Help!
You will get a FileNotFoundException if you call getInputStream after the server has responded withe a 404 or 410 status code.
If you want to avoid the exception, check that the response status code is a 2xx code. If it isn't then use getErrorStream instead of getInputStream.
In my case, There is an option in my Cpanel. It is MOD Security, Just turn it off, after 15 minutes my app worked properly.
Simply you need to add the port name(:8080) with the localhost ip address in URL String, like i did:
String login_url = "http://192.168.0.136:8080/login.php";

reCaptcha response is blank

I have implemented reCaptcha in the application I am working on. Somehow I am getting a blank reCaptcha response.
It works fine with localhost, but I am having a problem in upper environments like DEV, TEST. User response is being verified on server side (servlet).
Anyone having idea or faced similar problem ? Let me know if you need more info.
String userresponse = (String) request.getAttribute("g-recaptcha-response");
URL url = null;
HttpURLConnection conn = null;
String line, outputString = "";
try {
url = new URL(https://www.google.com/recaptcha/api/siteverify?secret=privateKey&response=userresponse);
conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
BufferedReader reader = new BufferedReader(
new InputStreamReader(conn.getInputStream()));
while ((line = reader.readLine()) != null) {
outputString += line;
}
Log.debug("Google response is :- "+outputString);
} catch (IOException e) {
e.printStackTrace();
}

Using HTTP Get request to overcome the Geocoder limits in Android

Is it possible to use HTTP API and perform HTTP Get request for Google maps in order to overcome the limits of using Geocoder API when requesting latitude and longitude of places?
Something like-
URL url = new URL("https://www.google.com/maps/place/Paris/");
connection.setDoOutput(true);
connection.setDoInput(true);
connection.setRequestMethod("GET");
System.out.println("Value" + connection.getResponseCode());
System.out.println(connection.getResponseMessage());
System.out.println("content"+connection.getContent());
or
URL url = new URL("https://www.google.com/maps/place/Paris/");
BufferedReader br = new BufferedReader(new InputStreamReader(url.openStream()));
String strTemp = "";
while (null != (strTemp = br.readLine())) {
System.out.println(strTemp);
}
Expecting the response to contain the lat and long of the place as in Google maps site, that way my client appears as a regular web client of google maps.
The Places API request has quota limit too, you can see the detail in this page: https://developers.google.com/places/webservice/usage
Also, you need an API key to do your Places API request, a sample way to do a Places API URL request in Android should be like this:
URL placeUrl = new URL("https://maps.googleapis.com/maps/api/place/textsearch/json?query=restaurants+in+Sydney&key=AddYourOwnKeyHere");
HttpURLConnection connection = (HttpURLConnection)placeUrl.openConnection();
connection.setRequestMethod("GET");
connection.connect();
responseCode = connection.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK) {
BufferedReader reader = null;
InputStream inputStream = connection.getInputStream();
StringBuffer buffer = new StringBuffer();
if (inputStream == null) {
// Nothing to do.
return null;
}
reader = new BufferedReader(new InputStreamReader(inputStream));
String line;
while ((line = reader.readLine()) != null) {
buffer.append(line + "\n");
}
if (buffer.length() == 0) {
return null;
}
Log.d(TAG, buffer.toString());
}
else {
Log.i(TAG, "Unsuccessful HTTP Response Code: " + responseCode);
}
You should do this URL request in background thread, for example, in the doInBackground() method of AsyncTask.
You can also visit this tutorial for more detail about how to use Places API in Android.

Effective measurement of dns lookup and site content download duration

I am implementing a Java method that measures a number of metrics while loading a webpage. The metrics include : resolve time, the connect time and download time.
The challenge seems to be the name resolution, since the code should never trigger two NS look-ups by any means (even when DNS caching is disabled).
My first thought was to trigger the name resolution before connecting to the server, and then prevent java from running a second one upon connect.
Using InetAddress.getByName() for the name lookup and then HttpURLConnection and it's setRequestProperty method to set the a host header seemed to do the trick.
So here is my question: Do those two snippets below have the same effect? Do they always give the exact same result for all possible hosts? If not, what other options do I have?
VERSION 1: Implicit name resolution
/**
* Site content download Test
*
* #throws IOException
*/
public static void testMethod() throws IOException {
String protocol = "http";
String host = "stackoverflow.com";
String file = "/";
// create a URL object
URL url = new URL(protocol, host, file);
// create the connection object
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
// connect
conn.connect();
// create a stream reader
BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String inputLine;
// read contents and print on std out
while ((inputLine = in.readLine()) != null) {
System.out.println(inputLine);
}
// close the stream
in.close();
}
VERSION 2: Explicit name resolution
/**
* Enhanced Site content download Test
*
* #throws IOException
*/
public static void testMethod2() throws IOException {
String protocol = "http";
String host = "stackoverflow.com";
String file = "/";
// Do a name lookup.
// If a literal IP address is supplied, only the validity of the address format is checked.
InetAddress address = InetAddress.getByName(host);
// create a URL object
URL url = new URL(protocol, address.getHostAddress(), file);
// create the connection object
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
// allow overriding Host and other restricted headers
System.setProperty("sun.net.http.allowRestrictedHeaders", "true");
// set the host header
conn.setRequestProperty("Host", host);
// connect
conn.connect();
// create a stream reader
BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String inputLine;
// read contents and print on std out
while ((inputLine = in.readLine()) != null) {
System.out.println(inputLine);
}
// close the stream
in.close();
}
TIA for the help.
-Dimi
I've browsed through Java's source code to see what happens when you pass a domain name to HttpURLConnection and it eventually ends up in NetworkClient.doConnect:
if (connectTimeout >= 0) {
s.connect(new InetSocketAddress(server, port), connectTimeout);
} else {
if (defaultConnectTimeout > 0) {
s.connect(new InetSocketAddress(server, port), defaultConnectTimeout);
} else {
s.connect(new InetSocketAddress(server, port));
}
}
As you see, the domain resolution is always handled by InetSocketAddress:
public InetSocketAddress(String hostname, int port) {
if (port < 0 || port > 0xFFFF) {
throw new IllegalArgumentException("port out of range:" + port);
}
if (hostname == null) {
throw new IllegalArgumentException("hostname can't be null");
}
try {
addr = InetAddress.getByName(hostname);
} catch(UnknownHostException e) {
this.hostname = hostname;
addr = null;
}
this.port = port;
}
As you can see, InetAddress.getByName is called everytime. I think that you method is safe.

Categories