1
0
Fork 0
mirror of https://bitbucket.org/akapribot/owm-japis.git synced 2025-04-29 00:38:11 -07:00

v2.5.0.3 - Lots of new features and changes. It's exciting. :)

This commit is contained in:
Ashutosh Kumar Singh 2014-12-28 15:31:23 +05:30
parent a3156175a3
commit a573686f24
143 changed files with 9372 additions and 26935 deletions

View file

@ -0,0 +1,248 @@
/*
* Copyright (c) 2013-2014 Ashutosh Kumar Singh <me@aksingh.net>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package net.aksingh.owmjapis;
import org.json.JSONObject;
/**
* <p>
* Provides default behaviours and implementations for:
* 1. {@link net.aksingh.owmjapis.HourlyForecast}
* 2. {@link net.aksingh.owmjapis.DailyForecast}
* It defines common methods like <code>has</code>, <code>get</code> and some others.
* </p>
*
* @author Ashutosh Kumar Singh
* @version 2014/12/27
* @since 2.5.0.3
*/
public abstract class AbstractForecast extends AbstractResponse {
/*
JSON Keys
*/
final String JSON_FORECAST_LIST = "list";
/*
Instance variables
*/
private final double message;
private final City city;
private final int forecastCount;
/*
Constructors
*/
AbstractForecast() {
super();
this.message = Double.NaN;
this.forecastCount = 0;
this.city = null;
}
AbstractForecast(JSONObject jsonObj) {
super(jsonObj);
final String JSON_MESSAGE = "message";
final String JSON_CITY = "city";
final String JSON_FORECAST_COUNT = "cnt";
this.message = (jsonObj != null) ? jsonObj.optDouble(JSON_MESSAGE, Double.NaN) : Double.NaN;
this.city = (jsonObj != null) ? new City(jsonObj.optJSONObject(JSON_CITY)) : null;
this.forecastCount = (jsonObj != null) ? jsonObj.optInt(JSON_FORECAST_COUNT, 0) : 0;
}
/**
* @return <code>true</code> if message is available, otherwise <code>false</code>.
*/
public boolean hasMessage() {
return (this.message != Double.NaN);
}
/**
* @return <code>true</code> if count of forecasts is available, otherwise <code>false</code>.
*/
public boolean hasForecastCount() {
return (this.forecastCount != 0);
}
/**
* @return <code>true</code> if message is available, otherwise <code>false</code>.
*/
public boolean hasCityInstance() {
return (this.city != null);
}
/**
* @return Message if available, otherwise <code>Double.NaN</code>.
*/
public double getMessage() {
return this.message;
}
/**
* @return Count of forecasts if available, otherwise <code>0</code>.
*/
public int getForecastCount() {
return this.forecastCount;
}
/**
* @return City's instance if available, otherwise <code>null</code>.
*/
public City getCityInstance() {
return this.city;
}
/**
* <p>
* Provides default behaviours for City
* </p>
*
* @author Ashutosh Kumar Singh
*/
public static class City {
private final String JSON_CITY_ID = "id";
private final String JSON_CITY_NAME = "name";
private final String JSON_CITY_COUNTRY_CODE = "country";
private final String JSON_CITY_POPULATION = "population";
private final String JSON_CITY_COORD = "coord";
private final long cityID;
private final String cityName;
private final String countryCode;
private final long population;
private final Coord coord;
City() {
this.cityID = Long.MIN_VALUE;
this.cityName = null;
this.countryCode = null;
this.population = Long.MIN_VALUE;
this.coord = new Coord();
}
City(JSONObject jsonObj) {
this.cityID = (jsonObj != null) ? jsonObj.optLong(this.JSON_CITY_ID, Long.MIN_VALUE) : Long.MIN_VALUE;
this.cityName = (jsonObj != null) ? jsonObj.optString(this.JSON_CITY_NAME, null) : null;
this.countryCode = (jsonObj != null) ? jsonObj.optString(this.JSON_CITY_COUNTRY_CODE, null) : null;
this.population = (jsonObj != null) ? jsonObj.optLong(this.JSON_CITY_POPULATION, Long.MIN_VALUE) : Long.MIN_VALUE;
JSONObject jsonObjCoord = (jsonObj != null) ? jsonObj.optJSONObject(this.JSON_CITY_COORD) : null;
this.coord = (jsonObjCoord != null) ? new Coord(jsonObjCoord) : null;
}
public boolean hasCityCode() {
return (this.cityID != Long.MIN_VALUE);
}
public boolean hasCityName() {
return (this.cityName != null);
}
public boolean hasCountryCode() {
return (this.countryCode != null);
}
public boolean hasCityPopulation() {
return (this.population != Long.MIN_VALUE);
}
/**
* @return <code>true</code> if Coord instance is available, otherwise <code>false</code>.
*/
public boolean hasCoordInstance() {
return (coord != null);
}
public long getCityCode() {
return this.cityID;
}
public String getCityName() {
return this.cityName;
}
public String getCountryCode() {
return this.countryCode;
}
public long getCityPopulation() {
return this.population;
}
/**
* @return Coord instance if available, otherwise <code>null</code>.
*/
public Coord getCoordInstance() {
return this.coord;
}
public static class Coord extends AbstractWeather.Coord {
Coord() {
super();
}
Coord(JSONObject jsonObj) {
super(jsonObj);
}
}
}
/**
* <p>
* Parses forecast data (one element in the forecastList) and provides methods to get/access the same information.
* This class provides <code>has</code> and <code>get</code> methods to access the information.
* </p>
* <p>
* <code>has</code> methods can be used to check if the data exists, i.e., if the data was available
* (successfully downloaded) and was parsed correctly.
* <code>get</code> methods can be used to access the data, if the data exists, otherwise <code>get</code>
* methods will give value as per following basis:
* Boolean: <code>false</code>
* Integral: Minimum value (MIN_VALUE)
* Floating point: Not a number (NaN)
* Others: <code>null</code>
* </p>
*
* @author Ashutosh Kumar Singh
* @version 2014/12/27
* @since 2.5.0.3
*/
public abstract static class Forecast extends AbstractWeather {
Forecast() {
super();
}
Forecast(JSONObject jsonObj) {
super(jsonObj);
}
}
}

View file

@ -0,0 +1,92 @@
/*
* Copyright (c) 2013-2014 Ashutosh Kumar Singh <me@aksingh.net>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package net.aksingh.owmjapis;
import org.json.JSONObject;
/**
* <p>
* Provides default behaviours and implementations for the response from OWM.org
* </p>
*
* @author Ashutosh Kumar Singh
* @version 2014/12/28
* @since 2.5.0.3
*/
abstract class AbstractResponse {
/*
Instance variables
*/
private final int responseCode;
private final String rawResponse;
/*
Constructors
*/
AbstractResponse() {
this.rawResponse = null;
this.responseCode = Integer.MIN_VALUE;
}
AbstractResponse(JSONObject jsonObj) {
final String JSON_RESPONSE_CODE = "cod";
this.rawResponse = (jsonObj != null) ? jsonObj.toString() : null;
this.responseCode = (jsonObj != null) ? jsonObj.optInt(JSON_RESPONSE_CODE, Integer.MIN_VALUE) : Integer.MIN_VALUE;
}
/**
* @return <code>true</code> if response is valid (downloaded and parsed correctly), otherwise <code>false</code>.
*/
public boolean isValid() {
return (this.responseCode == 200);
}
/**
* @return <code>true</code> if response code is available, otherwise <code>false</code>.
*/
public boolean hasResponseCode() {
return (this.responseCode != Integer.MIN_VALUE);
}
/**
* @return <code>true</code> if raw response is available, otherwise <code>false</code>.
*/
public boolean hasRawResponse() {
return (this.rawResponse != null);
}
/**
* @return Response code if available, otherwise <code>Integer.MIN_VALUE</code>.
*/
public int getResponseCode() {
return this.responseCode;
}
/**
* @return Raw response if available, otherwise <code>null</code>.
*/
public String getRawResponse() {
return this.rawResponse;
}
}

View file

@ -0,0 +1,527 @@
/*
* Copyright (c) 2013-2014 Ashutosh Kumar Singh <me@aksingh.net>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package net.aksingh.owmjapis;
import org.json.JSONArray;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
/**
* <p>
* Provides default behaviours and implementations for:
* 1. {@link net.aksingh.owmjapis.CurrentWeather}
* It defines common methods like <code>has</code>, <code>get</code> and some others.
* </p>
*
* @author Ashutosh Kumar Singh
* @version 2014/12/21
* @since 2.5.0.1
*/
public abstract class AbstractWeather extends AbstractResponse {
/*
JSON Keys
*/
final String JSON_CLOUDS = "clouds";
final String JSON_COORD = "coord";
final String JSON_MAIN = "main";
final String JSON_WIND = "wind";
/*
Instance variables
*/
private final Date dateTime;
private final int weatherCount;
private final List<Weather> weatherList;
/*
Constructors
*/
AbstractWeather() {
super();
this.weatherCount = 0;
this.weatherList = null;
this.dateTime = null;
}
AbstractWeather(JSONObject jsonObj) {
super(jsonObj);
final String JSON_WEATHER = "weather";
final String JSON_DATE_TIME = "dt";
long sec = (jsonObj != null) ? jsonObj.optLong(JSON_DATE_TIME, Long.MIN_VALUE) : Long.MIN_VALUE;
if (sec != Long.MIN_VALUE) { // converting seconds to Date object
/*
Bugfix: It always return "Sat Jan 17 04:10:42 CET 1970"
Issue: #3 at http://code.aksingh.net/owm-japis/issue/3/problem-with-datetime
Incorrect: this.dateTime = new Date(sec);
Correct: this.dateTime = new Date(sec * 1000);
Reason: Date requires milliseconds but previously, seconds were provided.
*/
this.dateTime = new Date(sec * 1000);
} else {
this.dateTime = null;
}
JSONArray weatherArray = (jsonObj != null) ? jsonObj.optJSONArray(JSON_WEATHER) : new JSONArray();
this.weatherList = (weatherArray != null) ? new ArrayList<Weather>(weatherArray.length()) : Collections.EMPTY_LIST;
if (this.weatherList != Collections.EMPTY_LIST) {
for (int i = 0; i < weatherArray.length(); i++) {
JSONObject weatherObj = weatherArray.optJSONObject(i);
if (weatherObj != null) {
this.weatherList.add(new Weather(weatherObj));
}
}
}
this.weatherCount = this.weatherList.size();
}
/**
* @return <code>true</code> if date/time is available, otherwise <code>false</code>.
*/
public boolean hasDateTime() {
return (this.dateTime != null);
}
/**
* @return <code>true</code> if Weather instance(s) is available, otherwise <code>false</code>.
*/
public boolean hasWeatherInstance() {
return (weatherCount != 0);
}
/**
* @return Date and time if available, otherwise <code>null</code>.
*/
public Date getDateTime() {
return this.dateTime;
}
/**
* @return Count of Weather instance(s) if available, otherwise 0.
*/
public int getWeatherCount() {
return this.weatherCount;
}
/**
* @param index Index of Weather instance in the list.
* @return Weather instance if available, otherwise <code>null</code>.
*/
public Weather getWeatherInstance(int index) {
return this.weatherList.get(index);
}
/**
* <p>
* Provides default behaviours for Cloud
* </p>
*
* @author Ashutosh Kumar Singh
* @version 2013/12/23
* @since 2.5.0.1
*/
abstract public static class Clouds {
private final String JSON_CLOUDS_ALL = "all";
private final float percentOfClouds;
Clouds() {
this.percentOfClouds = Float.NaN;
}
Clouds(JSONObject jsonObj) {
this.percentOfClouds = (float) jsonObj.optDouble(this.JSON_CLOUDS_ALL, Double.NaN);
}
/**
* Tells if percentage of clouds is available or not.
*
* @return <code>true</code> if data available, otherwise <code>false</code>
*/
public boolean hasPercentageOfClouds() {
return (this.percentOfClouds != Float.NaN);
}
/**
* @return Percentage of all clouds if available, otherwise <code>Float.NaN</code>.
*/
public float getPercentageOfClouds() {
return this.percentOfClouds;
}
}
/**
* <p>
* Provides default behaviours for Coord, i.e., coordinates.
* </p>
*
* @author Ashutosh Kumar Singh
* @version 2013/12/23
* @since 2.5.0.1
*/
abstract public static class Coord {
private final String JSON_COORD_LATITUDE = "lat";
private final String JSON_COORD_LONGITUDE = "lon";
private final float lat;
private final float lon;
Coord() {
this.lat = Float.NaN;
this.lon = Float.NaN;
}
Coord(JSONObject jsonObj) {
this.lat = (float) jsonObj.optDouble(this.JSON_COORD_LATITUDE, Double.NaN);
this.lon = (float) jsonObj.optDouble(this.JSON_COORD_LONGITUDE, Double.NaN);
}
/**
* Tells if the latitude of the city is available or not.
*
* @return <code>true</code> if data available, otherwise <code>false</code>
*/
public boolean hasLatitude() {
return (this.lat != Float.NaN);
}
/**
* Tells if the longitude of the city is available or not.
*
* @return <code>true</code> if data available, otherwise <code>false</code>
*/
public boolean hasLongitude() {
return (this.lon != Float.NaN);
}
/**
* @return Latitude of the city if available, otherwise <code>Float.NaN</code>.
*/
public float getLatitude() {
return this.lat;
}
/**
* @return Longitude of the city if available, otherwise <code>Float.NaN</code>.
*/
public float getLongitude() {
return this.lon;
}
}
/**
* <p>
* Provides default behaviours for Main, i.e., main weather elements like temperature, humidity, etc.
* </p>
*
* @author Ashutosh Kumar Singh
* @version 2013/12/23
* @since 2.5.0.1
*/
abstract public static class Main {
private final String JSON_MAIN_TEMP = "temp";
private final String JSON_MAIN_TEMP_MIN = "temp_min";
private final String JSON_MAIN_TEMP_MAX = "temp_max";
private final String JSON_MAIN_PRESSURE = "pressure";
private final String JSON_MAIN_HUMIDITY = "humidity";
private final float temp;
private final float minTemp;
private final float maxTemp;
private final float pressure;
private final float humidity;
Main() {
this.temp = Float.NaN;
this.minTemp = Float.NaN;
this.maxTemp = Float.NaN;
this.pressure = Float.NaN;
this.humidity = Float.NaN;
}
Main(JSONObject jsonObj) {
this.temp = (float) jsonObj.optDouble(this.JSON_MAIN_TEMP, Double.NaN);
this.minTemp = (float) jsonObj.optDouble(this.JSON_MAIN_TEMP_MIN, Double.NaN);
this.maxTemp = (float) jsonObj.optDouble(this.JSON_MAIN_TEMP_MAX, Double.NaN);
this.pressure = (float) jsonObj.optDouble(this.JSON_MAIN_PRESSURE, Double.NaN);
this.humidity = (float) jsonObj.optDouble(this.JSON_MAIN_HUMIDITY, Double.NaN);
}
/**
* Tells if the temperature of the city is available or not.
*
* @return <code>true</code> if data available, otherwise <code>false</code>
*/
public boolean hasTemperature() {
return (this.temp != Float.NaN);
}
/**
* Tells if the minimum temperature of the city is available or not.
*
* @return <code>true</code> if data available, otherwise <code>false</code>
*/
public boolean hasMinTemperature() {
return (this.minTemp != Float.NaN);
}
/**
* Tells if the maximum temperature of the city is available or not.
*
* @return <code>true</code> if data available, otherwise <code>false</code>
*/
public boolean hasMaxTemperature() {
return (this.maxTemp != Float.NaN);
}
/**
* Tells if pressure of the city is available or not.
*
* @return <code>true</code> if data available, otherwise <code>false</code>
*/
public boolean hasPressure() {
return (this.pressure != Float.NaN);
}
/**
* Tells if humidity of the city is available or not.
*
* @return <code>true</code> if data available, otherwise <code>false</code>
*/
public boolean hasHumidity() {
return (this.humidity != Float.NaN);
}
/**
* @return Temperature of the city if available, otherwise <code>Float.NaN</code>.
*/
public float getTemperature() {
return this.temp;
}
/**
* @return Minimum temperature of the city if available, otherwise <code>Float.NaN</code>.
*/
public float getMinTemperature() {
return this.minTemp;
}
/**
* @return Maximum temperature of the city if available, otherwise <code>Float.NaN</code>.
*/
public float getMaxTemperature() {
return this.maxTemp;
}
/**
* @return Pressure of the city if available, otherwise <code>Float.NaN</code>.
*/
public float getPressure() {
return this.pressure;
}
/**
* @return Humidity of the city if available, otherwise <code>Float.NaN</code>.
*/
public float getHumidity() {
return this.humidity;
}
}
/**
* <p>
* Parses weather data and provides methods to get/access the same information.
* This class provides <code>has</code> and <code>get</code> methods to access the information.
* </p>
* <p>
* <code>has</code> methods can be used to check if the data exists, i.e., if the data was available
* (successfully downloaded) and was parsed correctly.
* <code>get</code> methods can be used to access the data, if the data exists, otherwise <code>get</code>
* methods will give value as per following basis:
* Boolean: <code>false</code>
* Integral: Minimum value (MIN_VALUE)
* Floating point: Not a number (NaN)
* Others: <code>null</code>
* </p>
*
* @author Ashutosh Kumar Singh
* @version 2014/12/27
* @since 2.5.0.3
*/
public static class Weather {
private final String JSON_WEATHER_ID = "id";
private final String JSON_WEATHER_MAIN = "main";
private final String JSON_WEATHER_DESCRIPTION = "description";
private final String JSON_WEATHER_ICON = "icon";
private final int id;
private final String name;
private final String description;
private final String icon;
Weather() {
this.id = Integer.MIN_VALUE;
this.name = null;
this.description = null;
this.icon = null;
}
Weather(JSONObject jsonObj) {
this.id = jsonObj.optInt(this.JSON_WEATHER_ID, Integer.MIN_VALUE);
this.name = jsonObj.optString(this.JSON_WEATHER_MAIN, null);
this.description = jsonObj.optString(this.JSON_WEATHER_DESCRIPTION, null);
this.icon = jsonObj.optString(this.JSON_WEATHER_ICON, null);
}
/**
* Tells if weather's code is available or not.
*
* @return <code>true</code> if data available, otherwise <code>false</code>.
*/
public boolean hasWeatherCode() {
return (this.id != Integer.MIN_VALUE);
}
/**
* Tells if weather's name is available or not.
*
* @return <code>true</code> if data available, otherwise <code>false</code>.
*/
public boolean hasWeatherName() {
return (this.name != null && (!this.name.equals("")));
}
/**
* Tells if weather's description is available or not.
*
* @return <code>true</code> if data available, otherwise <code>false</code>.
*/
public boolean hasWeatherDescription() {
return (this.description != null && (!this.description.equals("")));
}
/**
* Tells if name of weather's icon is available or not.
*
* @return <code>true</code> if data available, otherwise <code>false</code>.
*/
public boolean hasWeatherIconName() {
return (this.icon != null && (!this.icon.equals("")));
}
/**
* @return Code for weather of the city if available, otherwise <code>Integer.MIN_VALUE</code>.
*/
public int getWeatherCode() {
return this.id;
}
/**
* @return Name for weather of the city if available, otherwise <code>null</code>.
*/
public String getWeatherName() {
return this.name;
}
/**
* @return Description for weather of the city if available, otherwise <code>null</code>.
*/
public String getWeatherDescription() {
return this.description;
}
/**
* @return Name of icon for weather of the city if available, otherwise <code>null</code>.
*/
public String getWeatherIconName() {
return this.icon;
}
}
/**
* <p>
* Provides default behaviours for Wind.
* </p>
*
* @author Ashutosh Kumar Singh
* @version 2013/12/23
* @since 2.5.0.1
*/
abstract public static class Wind {
private final String JSON_WIND_SPEED = "speed";
private final String JSON_WIND_DEGREE = "deg";
private final float speed;
private final float degree;
Wind() {
this.speed = Float.NaN;
this.degree = Float.NaN;
}
Wind(JSONObject jsonObj) {
this.speed = (float) jsonObj.optDouble(this.JSON_WIND_SPEED, Double.NaN);
this.degree = (float) jsonObj.optDouble(this.JSON_WIND_DEGREE, Double.NaN);
}
/**
* Tells if speed of wind in the city is available or not.
*
* @return <code>true</code> if data available, otherwise <code>false</code>.
*/
public boolean hasWindSpeed() {
return (this.speed != Float.NaN);
}
/**
* Tells if degree (degree gives direction) of wind in the city is available or not.
*
* @return <code>true</code> if data available, otherwise <code>false</code>.
*/
public boolean hasWindDegree() {
return (this.hasWindSpeed() && (this.degree != Float.NaN));
}
/**
* @return Speed of wind in the city if available, otherwise <code>Float.NaN</code>.
*/
public float getWindSpeed() {
return this.speed;
}
/**
* @return Degree of wind in the city if available, otherwise <code>Float.NaN</code>.
*/
public float getWindDegree() {
return this.degree;
}
}
}

View file

@ -0,0 +1,537 @@
/*
* Copyright (c) 2013-2014 Ashutosh Kumar Singh <me@aksingh.net>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package net.aksingh.owmjapis;
import org.json.JSONObject;
import java.util.Date;
/**
* <p>
* Parses current weather data and provides methods to get/access the same information.
* This class provides <code>has</code> and <code>get</code> methods to access the information.
* </p>
* <p>
* <code>has</code> methods can be used to check if the data exists, i.e., if the data was available
* (successfully downloaded) and was parsed correctly.
* <code>get</code> methods can be used to access the data, if the data exists, otherwise <code>get</code>
* methods will give value as per following basis:
* Boolean: <code>false</code>
* Integral: Minimum value (MIN_VALUE)
* Floating point: Not a number (NaN)
* Others: <code>null</code>
* </p>
*
* @author Ashutosh Kumar Singh
* @version 2014/12/26
* @see <a href="http://openweathermap.org/current">OWM's Current Weather API</a>
* @since 2.5.0.1
*/
public class CurrentWeather extends AbstractWeather {
/*
Instance variables
*/
private final String base;
private final long cityId;
private final String cityName;
private final Clouds clouds;
private final Coord coord;
private final Main main;
private final Rain rain;
private final Sys sys;
private final Wind wind;
/*
Constructor
*/
CurrentWeather(JSONObject jsonObj) {
super(jsonObj);
final String JSON_RAIN = "rain";
final String JSON_SYS = "sys";
final String JSON_BASE = "base";
final String JSON_CITY_ID = "id";
final String JSON_CITY_NAME = "name";
this.base = (jsonObj != null) ? jsonObj.optString(JSON_BASE, null) : null;
this.cityId = (jsonObj != null) ? jsonObj.optLong(JSON_CITY_ID, Long.MIN_VALUE) : Long.MIN_VALUE;
this.cityName = (jsonObj != null) ? jsonObj.optString(JSON_CITY_NAME, null) : null;
JSONObject cloudsObj = (jsonObj != null) ? jsonObj.optJSONObject(this.JSON_CLOUDS) : null;
this.clouds = (cloudsObj != null) ? new Clouds(cloudsObj) : null;
JSONObject coordObj = (jsonObj != null) ? jsonObj.optJSONObject(this.JSON_COORD) : null;
this.coord = (coordObj != null) ? new Coord(coordObj) : null;
JSONObject mainObj = (jsonObj != null) ? jsonObj.optJSONObject(this.JSON_MAIN) : null;
this.main = (mainObj != null) ? new Main(mainObj) : null;
JSONObject rainObj = (jsonObj != null) ? jsonObj.optJSONObject(JSON_RAIN) : null;
this.rain = (rainObj != null) ? new Rain(rainObj) : null;
JSONObject sysObj = (jsonObj != null) ? jsonObj.optJSONObject(JSON_SYS) : null;
this.sys = (sysObj != null) ? new Sys(sysObj) : null;
JSONObject windObj = (jsonObj != null) ? jsonObj.optJSONObject(this.JSON_WIND) : null;
this.wind = (windObj != null) ? new Wind(windObj) : null;
}
/**
* @return <code>true</code> if base station is available, otherwise <code>false</code>.
*/
public boolean hasBaseStation() {
return (this.base != null && (!this.base.equals("")));
}
/**
* @return <code>true</code> if city code is available, otherwise <code>false</code>.
*/
public boolean hasCityCode() {
return (this.cityId != Long.MIN_VALUE);
}
/**
* @return <code>true</code> if city name is available, otherwise <code>false</code>.
*/
public boolean hasCityName() {
return (this.cityName != null && (!this.cityName.equals("")));
}
/**
* @return <code>true</code> if Clouds instance is available, otherwise <code>false</code>.
*/
public boolean hasCloudsInstance() {
return (clouds != null);
}
/**
* @return <code>true</code> if Coord instance is available, otherwise <code>false</code>.
*/
public boolean hasCoordInstance() {
return (coord != null);
}
/**
* @return <code>true</code> if Main instance is available, otherwise <code>false</code>.
*/
public boolean hasMainInstance() {
return (main != null);
}
/**
* @return <code>true</code> if Rain instance is available, otherwise <code>false</code>.
*/
public boolean hasRainInstance() {
return (rain != null);
}
/**
* @return <code>true</code> if Sys instance is available, otherwise <code>false</code>.
*/
public boolean hasSysInstance() {
return (sys != null);
}
/**
* @return <code>true</code> if Wind instance is available, otherwise <code>false</code>.
*/
public boolean hasWindInstance() {
return (wind != null);
}
/**
* @return Base station if available, otherwise <code>null</code>.
*/
public String getBaseStation() {
return this.base;
}
/**
* @return City code if available, otherwise <code>Long.MIN_VALUE</code>.
*/
public long getCityCode() {
return this.cityId;
}
/**
* @return City name if available, otherwise <code>null</code>.
*/
public String getCityName() {
return this.cityName;
}
/**
* @return Clouds instance if available, otherwise <code>null</code>.
*/
public Clouds getCloudsInstance() {
return this.clouds;
}
/**
* @return Coord instance if available, otherwise <code>null</code>.
*/
public Coord getCoordInstance() {
return this.coord;
}
/**
* @return Main instance if available, otherwise <code>null</code>.
*/
public Main getMainInstance() {
return this.main;
}
/**
* @return Rain instance if available, otherwise <code>null</code>.
*/
public Rain getRainInstance() {
return this.rain;
}
/**
* @return Sys instance if available, otherwise <code>null</code>.
*/
public Sys getSysInstance() {
return this.sys;
}
/**
* @return Wind instance if available, otherwise <code>null</code>.
*/
public Wind getWindInstance() {
return this.wind;
}
/**
* <p>
* Parses clouds data and provides methods to get/access the same information.
* This class provides <code>has</code> and <code>get</code> methods to access the information.
* </p>
* <p>
* <code>has</code> methods can be used to check if the data exists, i.e., if the data was available
* (successfully downloaded) and was parsed correctly.
* <code>get</code> methods can be used to access the data, if the data exists, otherwise <code>get</code>
* methods will give value as per following basis:
* Boolean: <code>false</code>
* Integral: Minimum value (MIN_VALUE)
* Floating point: Not a number (NaN)
* Others: <code>null</code>
* </p>
*
* @author Ashutosh Kumar Singh
* @version 2014/12/26
* @since 2.5.0.1
*/
public static class Clouds extends AbstractWeather.Clouds {
Clouds() {
super();
}
Clouds(JSONObject jsonObj) {
super(jsonObj);
}
}
/**
* <p>
* Parses coordination data and provides methods to get/access the same information.
* This class provides <code>has</code> and <code>get</code> methods to access the information.
* </p>
* <p>
* <code>has</code> methods can be used to check if the data exists, i.e., if the data was available
* (successfully downloaded) and was parsed correctly.
* <code>get</code> methods can be used to access the data, if the data exists, otherwise <code>get</code>
* methods will give value as per following basis:
* Boolean: <code>false</code>
* Integral: Minimum value (MIN_VALUE)
* Floating point: Not a number (NaN)
* Others: <code>null</code>
* </p>
*
* @author Ashutosh Kumar Singh
* @version 2014/12/26
* @since 2.5.0.1
*/
public static class Coord extends AbstractWeather.Coord {
Coord() {
super();
}
Coord(JSONObject jsonObj) {
super(jsonObj);
}
}
/**
* <p>
* Parses main data and provides methods to get/access the same information.
* This class provides <code>has</code> and <code>get</code> methods to access the information.
* </p>
* <p>
* <code>has</code> methods can be used to check if the data exists, i.e., if the data was available
* (successfully downloaded) and was parsed correctly.
* <code>get</code> methods can be used to access the data, if the data exists, otherwise <code>get</code>
* methods will give value as per following basis:
* Boolean: <code>false</code>
* Integral: Minimum value (MIN_VALUE)
* Floating point: Not a number (NaN)
* Others: <code>null</code>
* </p>
*
* @author Ashutosh Kumar Singh
* @version 2014/12/26
* @since 2.5.0.1
*/
public static class Main extends AbstractWeather.Main {
Main() {
super();
}
Main(JSONObject jsonObj) {
super(jsonObj);
}
}
/**
* <p>
* Parses rain data and provides methods to get/access the same information.
* This class provides <code>has</code> and <code>get</code> methods to access the information.
* </p>
* <p>
* <code>has</code> methods can be used to check if the data exists, i.e., if the data was available
* (successfully downloaded) and was parsed correctly.
* <code>get</code> methods can be used to access the data, if the data exists, otherwise <code>get</code>
* methods will give value as per following basis:
* Boolean: <code>false</code>
* Integral: Minimum value (MIN_VALUE)
* Floating point: Not a number (NaN)
* Others: <code>null</code>
* </p>
*
* @author Ashutosh Kumar Singh
* @version 2014/12/26
* @since 2.5.0.1
*/
public static class Rain {
private final String JSON_RAIN_1HOUR = "1h";
private final float rain1h;
Rain() {
this.rain1h = Float.NaN;
}
Rain(JSONObject jsonObj) {
this.rain1h = (float) jsonObj.optDouble(this.JSON_RAIN_1HOUR, Double.NaN);
}
public boolean hasRain() {
return (this.rain1h != Float.NaN);
}
public float getRain() {
return this.rain1h;
}
}
/**
* <p>
* Parses sys data and provides methods to get/access the same information.
* This class provides <code>has</code> and <code>get</code> methods to access the information.
* </p>
* <p>
* <code>has</code> methods can be used to check if the data exists, i.e., if the data was available
* (successfully downloaded) and was parsed correctly.
* <code>get</code> methods can be used to access the data, if the data exists, otherwise <code>get</code>
* methods will give value as per following basis:
* Boolean: <code>false</code>
* Integral: Minimum value (MIN_VALUE)
* Floating point: Not a number (NaN)
* Others: <code>null</code>
* </p>
*
* @author Ashutosh Kumar Singh
* @version 2014/12/26
* @since 2.5.0.1
*/
public static class Sys {
private final String JSON_SYS_TYPE = "type";
private final String JSON_SYS_ID = "id";
private final String JSON_SYS_MESSAGE = "message";
private final String JSON_SYS_COUNTRY_CODE = "country";
private final String JSON_SYS_SUNRISE = "sunrise";
private final String JSON_SYS_SUNSET = "sunset";
private final int type;
private final int id;
private final double message;
private final String countryCode;
private final Date sunrise;
private final Date sunset;
Sys() {
this.type = Integer.MIN_VALUE;
this.id = Integer.MIN_VALUE;
this.message = Double.NaN;
this.countryCode = null;
this.sunrise = null;
this.sunset = null;
}
Sys(JSONObject jsonObj) {
this.type = jsonObj.optInt(this.JSON_SYS_TYPE, Integer.MIN_VALUE);
this.id = jsonObj.optInt(this.JSON_SYS_ID, Integer.MIN_VALUE);
this.message = jsonObj.optDouble(this.JSON_SYS_MESSAGE, Double.NaN);
this.countryCode = jsonObj.optString(this.JSON_SYS_COUNTRY_CODE, null);
long sr_secs = jsonObj.optLong(this.JSON_SYS_SUNRISE, Long.MIN_VALUE);
if (sr_secs != Long.MIN_VALUE) {
/*
Bugfix: Incorrect date and time
Issue: #3 given at http://code.aksingh.net/owm-japis/issue/3/problem-with-datetime
Incorrect: this.sunrise = new Date(sr_secs);
Correct: this.sunrise = new Date(sr_secs * 1000);
Reason: Date requires milliseconds but previously, seconds were provided.
*/
this.sunrise = new Date(sr_secs * 1000);
} else {
this.sunrise = null;
}
long ss_secs = jsonObj.optLong(this.JSON_SYS_SUNSET, Long.MIN_VALUE);
if (ss_secs != Long.MIN_VALUE) {
/*
Bugfix: Incorrect date and time
Issue: #3 given at http://code.aksingh.net/owm-japis/issue/3/problem-with-datetime
Incorrect: this.sunrise = new Date(ss_secs);
Correct: this.sunrise = new Date(ss_secs * 1000);
Reason: Date requires milliseconds but previously, seconds were provided.
*/
this.sunset = new Date(ss_secs * 1000);
} else {
this.sunset = null;
}
}
public boolean hasType() {
return (this.type != Integer.MIN_VALUE);
}
public boolean hasId() {
return (this.id != Integer.MIN_VALUE);
}
public boolean hasMessage() {
return (this.message != Double.NaN);
}
public boolean hasCountryCode() {
return (this.countryCode != null);
}
public boolean hasSunriseTime() {
return (this.sunrise != null);
}
public boolean hasSunsetTime() {
return (this.sunset != null);
}
public int getType() {
return this.type;
}
public int getId() {
return this.id;
}
public double getMessage() {
return this.message;
}
public String getCountryCode() {
return this.countryCode;
}
public Date getSunriseTime() {
return this.sunrise;
}
public Date getSunsetTime() {
return this.sunset;
}
}
/**
* <p>
* Parses wind data and provides methods to get/access the same information.
* This class provides <code>has</code> and <code>get</code> methods to access the information.
* </p>
* <p>
* <code>has</code> methods can be used to check if the data exists, i.e., if the data was available
* (successfully downloaded) and was parsed correctly.
* <code>get</code> methods can be used to access the data, if the data exists, otherwise <code>get</code>
* methods will give value as per following basis:
* Boolean: <code>false</code>
* Integral: Minimum value (MIN_VALUE)
* Floating point: Not a number (NaN)
* Others: <code>null</code>
* </p>
*
* @author Ashutosh Kumar Singh
* @version 2014/12/26
* @since 2.5.0.1
*/
public static class Wind extends AbstractWeather.Wind {
private final String JSON_WIND_GUST = "gust";
private final float gust;
Wind() {
super();
this.gust = Float.NaN;
}
Wind(JSONObject jsonObj) {
super(jsonObj);
this.gust = (float) jsonObj.optDouble(this.JSON_WIND_GUST, Double.NaN);
}
public boolean hasWindGust() {
return (this.gust != Float.NaN);
}
public float getWindGust() {
return this.gust;
}
}
}

View file

@ -0,0 +1,318 @@
/*
* Copyright (c) 2013-2014 Ashutosh Kumar Singh <me@aksingh.net>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package net.aksingh.owmjapis;
import org.json.JSONArray;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* <p>
* Parses daily forecast data and provides methods to get/access the same information.
* This class provides <code>has</code> and <code>get</code> methods to access the information.
* </p>
* <p>
* <code>has</code> methods can be used to check if the data exists, i.e., if the data was available
* (successfully downloaded) and was parsed correctly.
* <code>get</code> methods can be used to access the data, if the data exists, otherwise <code>get</code>
* methods will give value as per following basis:
* Boolean: <code>false</code>
* Integral: Minimum value (MIN_VALUE)
* Floating point: Not a number (NaN)
* Others: <code>null</code>
* </p>
*
* @author Ashutosh Kumar Singh
* @version 2014/12/27
* @see <a href="http://openweathermap.org/forecast">OWM's Weather Forecast API</a>
* @since 2.5.0.3
*/
public class DailyForecast extends AbstractForecast {
/*
Instance variables
*/
private final List<Forecast> forecastList;
/*
Constructors
*/
DailyForecast(JSONObject jsonObj) {
super(jsonObj);
JSONArray dataArray = (jsonObj != null) ? jsonObj.optJSONArray(this.JSON_FORECAST_LIST) : new JSONArray();
this.forecastList = (dataArray != null) ? new ArrayList<Forecast>(dataArray.length()) : Collections.EMPTY_LIST;
if (this.forecastList != Collections.EMPTY_LIST) {
for (int i = 0; i < dataArray.length(); i++) {
JSONObject forecastObj = dataArray.optJSONObject(i);
if (forecastObj != null) {
this.forecastList.add(new Forecast(forecastObj));
}
}
}
}
/**
* @param index Index of Forecast instance in the list.
* @return Forecast instance if available, otherwise <code>null</code>.
*/
public Forecast getForecastInstance(int index) {
return this.forecastList.get(index);
}
/**
* <p>
* Parses forecast data (one element in the forecastList) and provides methods to get/access the same information.
* This class provides <code>has</code> and <code>get</code> methods to access the information.
* </p>
* <p>
* <code>has</code> methods can be used to check if the data exists, i.e., if the data was available
* (successfully downloaded) and was parsed correctly.
* <code>get</code> methods can be used to access the data, if the data exists, otherwise <code>get</code>
* methods will give value as per following basis:
* Boolean: <code>false</code>
* Integral: Minimum value (MIN_VALUE)
* Floating point: Not a number (NaN)
* Others: <code>null</code>
* </p>
*/
public static class Forecast extends AbstractForecast.Forecast {
/*
JSON Keys
*/
public final String JSON_TEMP = "temp";
private final String JSON_FORECAST_PRESSURE = "pressure";
private final String JSON_FORECAST_HUMIDITY = "humidity";
private final String JSON_FORECAST_WIND_SPEED = "speed";
private final String JSON_FORECAST_WIND_DEGREE = "deg";
private final String JSON_FORECAST_CLOUDS = "clouds";
private final String JSON_FORECAST_RAIN = "rain";
private final String JSON_FORECAST_SNOW = "snow";
/*
Instance Variables
*/
private final float pressure;
private final float humidity;
private final float windSpeed;
private final float windDegree;
private final float cloudsPercent;
private final float rain;
private final float snow;
private final Temperature temp;
/*
Constructors
*/
Forecast() {
super();
this.pressure = Float.NaN;
this.humidity = Float.NaN;
this.windSpeed = Float.NaN;
this.windDegree = Float.NaN;
this.cloudsPercent = Float.NaN;
this.rain = Float.NaN;
this.snow = Float.NaN;
this.temp = new Temperature();
}
Forecast(JSONObject jsonObj) {
super(jsonObj);
JSONObject jsonObjTemp = (jsonObj != null) ? jsonObj.optJSONObject(this.JSON_TEMP) : null;
this.temp = (jsonObjTemp != null) ? new Temperature(jsonObjTemp) : new Temperature();
this.humidity = (jsonObj != null) ? (float) jsonObj.optDouble(this.JSON_FORECAST_HUMIDITY, Double.NaN) : Float.NaN;
this.pressure = (jsonObj != null) ? (float) jsonObj.optDouble(this.JSON_FORECAST_PRESSURE, Double.NaN) : Float.NaN;
this.windSpeed = (jsonObj != null) ? (float) jsonObj.optDouble(this.JSON_FORECAST_WIND_SPEED, Double.NaN) : Float.NaN;
this.windDegree = (jsonObj != null) ? (float) jsonObj.optDouble(this.JSON_FORECAST_WIND_DEGREE, Double.NaN) : Float.NaN;
this.cloudsPercent = (jsonObj != null) ? (float) jsonObj.optDouble(this.JSON_FORECAST_CLOUDS, Double.NaN) : Float.NaN;
this.rain = (jsonObj != null) ? (float) jsonObj.optDouble(this.JSON_FORECAST_RAIN, Double.NaN) : Float.NaN;
this.snow = (jsonObj != null) ? (float) jsonObj.optDouble(this.JSON_FORECAST_SNOW, Double.NaN) : Float.NaN;
}
public boolean hasHumidity() {
return (this.humidity != Float.NaN);
}
public boolean hasPressure() {
return (this.pressure != Float.NaN);
}
public boolean hasWindSpeed() {
return (this.windSpeed != Float.NaN);
}
public boolean hasWindDegree() {
return (this.windDegree != Float.NaN);
}
public boolean hasPercentageOfClouds() {
return (this.cloudsPercent != Float.NaN);
}
public boolean hasRain() {
return (this.rain != Float.NaN);
}
public boolean hasSnow() {
return (this.snow != Float.NaN);
}
public float getHumidity() {
return this.humidity;
}
public float getPressure() {
return this.pressure;
}
public float getWindSpeed() {
return this.windSpeed;
}
public float getWindDegree() {
return this.windDegree;
}
public float getPercentageOfClouds() {
return this.cloudsPercent;
}
public float getRain() {
return this.rain;
}
public float getSnow() {
return this.snow;
}
public Temperature getTemperatureInstance() {
return this.temp;
}
/**
* <p>
* Parses temperature data and provides methods to get/access the same information.
* This class provides <code>has</code> and <code>get</code> methods to access the information.
* </p>
* <p>
* <code>has</code> methods can be used to check if the data exists, i.e., if the data was available
* (successfully downloaded) and was parsed correctly.
* <code>get</code> methods can be used to access the data, if the data exists, otherwise <code>get</code>
* methods will give value as per following basis:
* Boolean: <code>false</code>
* Integral: Minimum value (MIN_VALUE)
* Floating point: Not a number (NaN)
* Others: <code>null</code>
* </p>
*/
public static class Temperature {
public final String JSON_TEMP_DAY = "day";
public final String JSON_TEMP_MIN = "min";
public final String JSON_TEMP_MAX = "max";
public final String JSON_TEMP_NIGHT = "night";
public final String JSON_TEMP_EVENING = "eve";
public final String JSON_TEMP_MORNING = "morn";
private final float dayTemp;
private final float minTemp;
private final float maxTemp;
private final float nightTemp;
private final float eveTemp;
private final float mornTemp;
Temperature() {
this.dayTemp = Float.NaN;
this.minTemp = Float.NaN;
this.maxTemp = Float.NaN;
this.nightTemp = Float.NaN;
this.eveTemp = Float.NaN;
this.mornTemp = Float.NaN;
}
Temperature(JSONObject jsonObj) {
this.dayTemp = (jsonObj != null) ? (float) jsonObj.optDouble(this.JSON_TEMP_DAY, Double.NaN) : Float.NaN;
this.minTemp = (jsonObj != null) ? (float) jsonObj.optDouble(this.JSON_TEMP_MIN, Double.NaN) : Float.NaN;
this.maxTemp = (jsonObj != null) ? (float) jsonObj.optDouble(this.JSON_TEMP_MAX, Double.NaN) : Float.NaN;
this.nightTemp = (jsonObj != null) ? (float) jsonObj.optDouble(this.JSON_TEMP_NIGHT, Double.NaN) : Float.NaN;
this.eveTemp = (jsonObj != null) ? (float) jsonObj.optDouble(this.JSON_TEMP_EVENING, Double.NaN) : Float.NaN;
this.mornTemp = (jsonObj != null) ? (float) jsonObj.optDouble(this.JSON_TEMP_MORNING, Double.NaN) : Float.NaN;
}
public boolean hasDayTemperature() {
return (this.dayTemp != Float.NaN);
}
public boolean hasMinimumTemperature() {
return (this.minTemp != Float.NaN);
}
public boolean hasMaximumTemperature() {
return (this.maxTemp != Float.NaN);
}
public boolean hasNightTemperature() {
return (this.nightTemp != Float.NaN);
}
public boolean hasEveningTemperature() {
return (this.eveTemp != Float.NaN);
}
public boolean hasMorningTemperature() {
return (this.mornTemp != Float.NaN);
}
public float getDayTemperature() {
return this.dayTemp;
}
public float getMinimumTemperature() {
return this.minTemp;
}
public float getMaximumTemperature() {
return this.maxTemp;
}
public float getNightTemperature() {
return this.nightTemp;
}
public float getEveningTemperature() {
return this.eveTemp;
}
public float getMorningTemperature() {
return this.mornTemp;
}
}
}
}

View file

@ -0,0 +1,376 @@
/*
* Copyright (c) 2013-2014 Ashutosh Kumar Singh <me@aksingh.net>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package net.aksingh.owmjapis;
import org.json.JSONArray;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* <p>
* Parses hourly forecast data and provides methods to get/access the same information.
* This class provides <code>has</code> and <code>get</code> methods to access the information.
* </p>
* <p>
* <code>has</code> methods can be used to check if the data exists, i.e., if the data was available
* (successfully downloaded) and was parsed correctly.
* <code>get</code> methods can be used to access the data, if the data exists, otherwise <code>get</code>
* methods will give value as per following basis:
* Boolean: <code>false</code>
* Integral: Minimum value (MIN_VALUE)
* Floating point: Not a number (NaN)
* Others: <code>null</code>
* </p>
*
* @author Ashutosh Kumar Singh
* @version 2014/12/27
* @see <a href="http://openweathermap.org/forecast">OWM's Weather Forecast API</a>
* @since 2.5.0.3
*/
public class HourlyForecast extends AbstractForecast {
/*
Instance variables
*/
private final List<Forecast> forecastList;
/*
Constructor
*/
HourlyForecast(JSONObject jsonObj) {
super(jsonObj);
JSONArray forecastArr = (jsonObj != null) ? jsonObj.optJSONArray(this.JSON_FORECAST_LIST) : new JSONArray();
this.forecastList = (forecastArr != null) ? new ArrayList<Forecast>(forecastArr.length()) : Collections.EMPTY_LIST;
if (this.forecastList != Collections.EMPTY_LIST) {
for (int i = 0; i < forecastArr.length(); i++) {
JSONObject forecastObj = forecastArr.optJSONObject(i);
if (forecastObj != null) {
this.forecastList.add(new Forecast(forecastObj));
}
}
}
}
/**
* @param index Index of Forecast instance in the list.
* @return Forecast instance if available, otherwise <code>null</code>.
*/
public Forecast getForecastInstance(int index) {
return this.forecastList.get(index);
}
/**
* <p>
* Parses forecast data (one element in the forecastList) and provides methods to get/access the same information.
* This class provides <code>has</code> and <code>get</code> methods to access the information.
* </p>
* <p>
* <code>has</code> methods can be used to check if the data exists, i.e., if the data was available
* (successfully downloaded) and was parsed correctly.
* <code>get</code> methods can be used to access the data, if the data exists, otherwise <code>get</code>
* methods will give value as per following basis:
* Boolean: <code>false</code>
* Integral: Minimum value (MIN_VALUE)
* Floating point: Not a number (NaN)
* Others: <code>null</code>
* </p>
*/
public static class Forecast extends AbstractForecast.Forecast {
/*
JSON Keys
*/
private final String JSON_SYS = "sys";
private final String JSON_DT_TEXT = "dt_txt";
/*
Instance Variables
*/
private final String dateTimeText;
private final Clouds clouds;
private final Main main;
private final Sys sys;
private final Wind wind;
/*
Constructor
*/
Forecast(JSONObject jsonObj) {
super(jsonObj);
this.dateTimeText = (jsonObj != null) ? jsonObj.optString(this.JSON_DT_TEXT, null) : null;
JSONObject jsonObjClouds = (jsonObj != null) ? jsonObj.optJSONObject(this.JSON_CLOUDS) : null;
this.clouds = (jsonObjClouds != null) ? new Clouds(jsonObjClouds) : null;
JSONObject jsonObjMain = (jsonObj != null) ? jsonObj.optJSONObject(this.JSON_MAIN) : null;
this.main = (jsonObjMain != null) ? new Main(jsonObjMain) : null;
JSONObject jsonObjSys = (jsonObj != null) ? jsonObj.optJSONObject(this.JSON_SYS) : null;
this.sys = (jsonObjSys != null) ? new Sys(jsonObjSys) : null;
JSONObject jsonObjWind = (jsonObj != null) ? jsonObj.optJSONObject(this.JSON_WIND) : null;
this.wind = (jsonObjWind != null) ? new Wind(jsonObjWind) : null;
}
public boolean hasDateTimeText() {
return (this.dateTimeText != null);
}
/**
* @return <code>true</code> if Clouds instance is available, otherwise <code>false</code>.
*/
public boolean hasCloudsInstance() {
return (clouds != null);
}
/**
* @return <code>true</code> if Main instance is available, otherwise <code>false</code>.
*/
public boolean hasMainInstance() {
return (main != null);
}
/**
* @return <code>true</code> if Sys instance is available, otherwise <code>false</code>.
*/
public boolean hasSysInstance() {
return (sys != null);
}
/**
* @return <code>true</code> if Wind instance is available, otherwise <code>false</code>.
*/
public boolean hasWindInstance() {
return (wind != null);
}
public String getDateTimeText() {
return this.dateTimeText;
}
/**
* @return Clouds instance if available, otherwise <code>null</code>.
*/
public Clouds getCloudsInstance() {
return this.clouds;
}
/**
* @return Main instance if available, otherwise <code>null</code>.
*/
public Main getMainInstance() {
return this.main;
}
/**
* @return Sys instance if available, otherwise <code>null</code>.
*/
public Sys getSysInstance() {
return this.sys;
}
/**
* @return Wind instance if available, otherwise <code>null</code>.
*/
public Wind getWindInstance() {
return this.wind;
}
/**
* <p>
* Parses clouds data and provides methods to get/access the same information.
* This class provides <code>has</code> and <code>get</code> methods to access the information.
* </p>
* <p>
* <code>has</code> methods can be used to check if the data exists, i.e., if the data was available
* (successfully downloaded) and was parsed correctly.
* <code>get</code> methods can be used to access the data, if the data exists, otherwise <code>get</code>
* methods will give value as per following basis:
* Boolean: <code>false</code>
* Integral: Minimum value (MIN_VALUE)
* Floating point: Not a number (NaN)
* Others: <code>null</code>
* </p>
*
* @author Ashutosh Kumar Singh
* @version 2014/12/26
* @since 2.5.0.1
*/
public static class Clouds extends AbstractForecast.Forecast.Clouds {
Clouds() {
super();
}
Clouds(JSONObject jsonObj) {
super(jsonObj);
}
}
/**
* <p>
* Parses main data and provides methods to get/access the same information.
* This class provides <code>has</code> and <code>get</code> methods to access the information.
* </p>
* <p>
* <code>has</code> methods can be used to check if the data exists, i.e., if the data was available
* (successfully downloaded) and was parsed correctly.
* <code>get</code> methods can be used to access the data, if the data exists, otherwise <code>get</code>
* methods will give value as per following basis:
* Boolean: <code>false</code>
* Integral: Minimum value (MIN_VALUE)
* Floating point: Not a number (NaN)
* Others: <code>null</code>
* </p>
*
* @author Ashutosh Kumar Singh
* @version 2014/12/26
* @since 2.5.0.1
*/
public static class Main extends AbstractForecast.Forecast.Main {
private final String JSON_MAIN_SEA_LEVEL = "sea_level";
private final String JSON_MAIN_GRND_LEVEL = "grnd_level";
private final String JSON_MAIN_TMP_KF = "temp_kf";
private final float seaLevel;
private final float groundLevel;
private final float tempKF;
Main() {
super();
this.seaLevel = Float.NaN;
this.groundLevel = Float.NaN;
this.tempKF = Float.NaN;
}
Main(JSONObject jsonObj) {
super(jsonObj);
this.seaLevel = (jsonObj != null) ? (float) jsonObj.optDouble(this.JSON_MAIN_SEA_LEVEL, Float.NaN) : Float.NaN;
this.groundLevel = (jsonObj != null) ? (float) jsonObj.optDouble(this.JSON_MAIN_GRND_LEVEL, Float.NaN) : Float.NaN;
this.tempKF = (jsonObj != null) ? (float) jsonObj.optDouble(this.JSON_MAIN_TMP_KF, Float.NaN) : Float.NaN;
}
public boolean hasSeaLevel() {
return (this.seaLevel != Float.NaN);
}
public boolean hasGroundLevel() {
return (this.groundLevel != Float.NaN);
}
public boolean hasTempKF() {
return (this.tempKF != Float.NaN);
}
public float getSeaLevel() {
return this.seaLevel;
}
public float getGroundLevel() {
return this.groundLevel;
}
public float getTempKF() {
return this.tempKF;
}
}
/**
* <p>
* Parses sys data and provides methods to get/access the same information.
* This class provides <code>has</code> and <code>get</code> methods to access the information.
* </p>
* <p>
* <code>has</code> methods can be used to check if the data exists, i.e., if the data was available
* (successfully downloaded) and was parsed correctly.
* <code>get</code> methods can be used to access the data, if the data exists, otherwise <code>get</code>
* methods will give value as per following basis:
* Boolean: <code>false</code>
* Integral: Minimum value (MIN_VALUE)
* Floating point: Not a number (NaN)
* Others: <code>null</code>
* </p>
*
* @author Ashutosh Kumar Singh
* @version 2014/12/26
* @since 2.5.0.1
*/
public static class Sys {
private final String JSON_SYS_POD = "pod";
private final String pod;
Sys() {
this.pod = null;
}
Sys(JSONObject jsonObj) {
this.pod = (jsonObj != null) ? jsonObj.optString(this.JSON_SYS_POD, null) : null;
}
public boolean hasPod() {
return (this.pod != null && (!this.pod.equals("")));
}
public String getPod() {
return this.pod;
}
}
/**
* <p>
* Parses wind data and provides methods to get/access the same information.
* This class provides <code>has</code> and <code>get</code> methods to access the information.
* </p>
* <p>
* <code>has</code> methods can be used to check if the data exists, i.e., if the data was available
* (successfully downloaded) and was parsed correctly.
* <code>get</code> methods can be used to access the data, if the data exists, otherwise <code>get</code>
* methods will give value as per following basis:
* Boolean: <code>false</code>
* Integral: Minimum value (MIN_VALUE)
* Floating point: Not a number (NaN)
* Others: <code>null</code>
* </p>
*
* @author Ashutosh Kumar Singh
* @version 2014/12/26
* @since 2.5.0.1
*/
public static class Wind extends AbstractWeather.Wind {
Wind() {
super();
}
Wind(JSONObject jsonObj) {
super(jsonObj);
}
}
}
}

View file

@ -0,0 +1,677 @@
/*
* Copyright (c) 2013-2014 Ashutosh Kumar Singh <me@aksingh.net>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package net.aksingh.owmjapis;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.zip.GZIPInputStream;
/**
* <p>
* Lets you access data from OpenWeatherMap.org using its Web APIs.
* Henceforth, it's shortened as OWM.org to ease commenting.
* </p>
* <p>
* <b>Sample code:</b><br>
* <code>OpenWeatherMap.org owm = new OpenWeatherMap("your-api-key");</code><br>
* <code>OpenWeatherMap.org owm = new OpenWeatherMap(your-units, "your-api-key");</code><br>
* <code>OpenWeatherMap.org owm = new OpenWeatherMap(your-units, your-language, "your-api-key");</code>
* </p>
*
* @author Ashutosh Kumar Singh <me@aksingh.net>
* @version 12/19/2014
* @see <a href="http://openweathermap.org/">OpenWeatherMap.org</a>
* @see <a href="http://openweathermap.org/api">OpenWeatherMap.org API</a>
* @since 2.5.0.1
*/
public class OpenWeatherMap {
/*
URLs and parameters for OWM.org
*/
private static final String URL_API = "http://api.openweathermap.org/data/2.5/";
private static final String URL_CURRENT = "weather?";
private static final String URL_HOURLY_FORECAST = "forecast?";
private static final String URL_DAILY_FORECAST = "forecast/daily?";
private static final String PARAM_COUNT = "cnt=";
private static final String PARAM_CITY_NAME = "q=";
private static final String PARAM_CITY_ID = "id=";
private static final String PARAM_LATITUDE = "lat=";
private static final String PARAM_LONGITUDE = "lon=";
private static final String PARAM_MODE = "mode=";
private static final String PARAM_UNITS = "units=";
private static final String PARAM_APPID = "appId=";
private static final String PARAM_LANG = "unit=";
/*
Instance Variables
*/
private final OWMAddress owmAddress;
private final OWMResponse owmResponse;
/**
* Constructor
*
* @param apiKey API key from OWM.org
* @see <a href="http://openweathermap.org/appid">OWM.org API Key</a>
*/
public OpenWeatherMap(String apiKey) {
this(Units.IMPERIAL, Language.ENGLISH, apiKey);
}
/**
* Constructor
*
* @param units Any constant from Units
* @param apiKey API key from OWM.org
* @see net.aksingh.owmjapis.OpenWeatherMap.Units
* @see <a href="http://openweathermap.org/appid">OWM.org API Key</a>
*/
public OpenWeatherMap(Units units, String apiKey) {
this(units, Language.ENGLISH, apiKey);
}
/**
* Constructor
*
* @param units Any constant from Units
* @param lang Any constant from Language
* @param apiKey API key from OWM.org
* @see net.aksingh.owmjapis.OpenWeatherMap.Units
* @see net.aksingh.owmjapis.OpenWeatherMap.Language
* @see <a href="http://openweathermap.org/current#multi">OWM.org's Multilingual support</a>
* @see <a href="http://openweathermap.org/appid">OWM.org's API Key</a>
*/
public OpenWeatherMap(Units units, Language lang, String apiKey) {
this.owmAddress = new OWMAddress(units, lang, apiKey);
this.owmResponse = new OWMResponse(owmAddress);
}
/*
Getters
*/
public OWMAddress getOwmAddressInstance() {
return owmAddress;
}
public String getApiKey() {
return owmAddress.getAppId();
}
public Units getUnits() {
return owmAddress.getUnits();
}
public String getMode() {
return owmAddress.getMode();
}
public Language getLang() {
return owmAddress.getLang();
}
/*
Setters
*/
/**
* Set units for getting data from OWM.org
*
* @param units Any constant from Units
* @see net.aksingh.owmjapis.OpenWeatherMap.Units
*/
public void setUnits(Units units) {
owmAddress.setUnits(units);
}
/**
* Set API key for getting data from OWM.org
*
* @param appId API key from OWM.org
* @see <a href="http://openweathermap.org/appid">OWM.org's API Key</a>
*/
public void setApiKey(String appId) {
owmAddress.setAppId(appId);
}
/**
* Set language for getting data from OWM.org
*
* @param lang Any constant from Language
* @see net.aksingh.owmjapis.OpenWeatherMap.Language
* @see <a href="http://openweathermap.org/current#multi">OWM.org's Multilingual support</a>
*/
public void setLang(Language lang) {
owmAddress.setLang(lang);
}
public CurrentWeather currentWeatherByCityName(String cityName)
throws IOException, JSONException {
String response = owmResponse.currentWeatherByCityName(cityName);
return this.currentWeatherFromRawResponse(response);
}
public CurrentWeather currentWeatherByCityName(String cityName, String countryCode)
throws IOException, JSONException {
String response = owmResponse.currentWeatherByCityName(cityName, countryCode);
return this.currentWeatherFromRawResponse(response);
}
public CurrentWeather currentWeatherByCityCode(long cityCode)
throws JSONException {
String response = owmResponse.currentWeatherByCityCode(cityCode);
return this.currentWeatherFromRawResponse(response);
}
public CurrentWeather currentWeatherByCoordinates(float latitude, float longitude)
throws JSONException {
String response = owmResponse.currentWeatherByCoordinates(latitude, longitude);
return this.currentWeatherFromRawResponse(response);
}
public CurrentWeather currentWeatherFromRawResponse(String response)
throws JSONException {
JSONObject jsonObj = (response != null) ? new JSONObject(response) : null;
return new CurrentWeather(jsonObj);
}
public HourlyForecast hourlyForecastByCityName(String cityName)
throws IOException, JSONException {
String response = owmResponse.hourlyForecastByCityName(cityName);
return this.hourlyForecastFromRawResponse(response);
}
public HourlyForecast hourlyForecastByCityName(String cityName, String countryCode)
throws IOException, JSONException {
String response = owmResponse.hourlyForecastByCityName(cityName, countryCode);
return this.hourlyForecastFromRawResponse(response);
}
public HourlyForecast hourlyForecastByCityCode(long cityCode)
throws JSONException {
String response = owmResponse.hourlyForecastByCityCode(cityCode);
return this.hourlyForecastFromRawResponse(response);
}
public HourlyForecast hourlyForecastByCoordinates(float latitude, float longitude)
throws JSONException {
String response = owmResponse.hourlyForecastByCoordinates(latitude, longitude);
return this.hourlyForecastFromRawResponse(response);
}
public HourlyForecast hourlyForecastFromRawResponse(String response)
throws JSONException {
JSONObject jsonObj = (response != null) ? new JSONObject(response) : null;
return new HourlyForecast(jsonObj);
}
public DailyForecast dailyForecastByCityName(String cityName, byte count)
throws IOException, JSONException {
String response = owmResponse.dailyForecastByCityName(cityName, count);
return this.dailyForecastFromRawResponse(response);
}
public DailyForecast dailyForecastByCityName(String cityName, String countryCode, byte count)
throws IOException, JSONException {
String response = owmResponse.dailyForecastByCityName(cityName, countryCode, count);
return this.dailyForecastFromRawResponse(response);
}
public DailyForecast dailyForecastByCityCode(long cityCode, byte count)
throws JSONException {
String response = owmResponse.dailyForecastByCityCode(cityCode, count);
return this.dailyForecastFromRawResponse(response);
}
public DailyForecast dailyForecastByCoordinates(float latitude, float longitude, byte count)
throws JSONException {
String response = owmResponse.dailyForecastByCoordinates(latitude, longitude, count);
return this.dailyForecastFromRawResponse(response);
}
public DailyForecast dailyForecastFromRawResponse(String response)
throws JSONException {
JSONObject jsonObj = (response != null) ? new JSONObject(response) : null;
return new DailyForecast(jsonObj);
}
/**
* Units that can be set for getting data from OWM.org
*
* @since 2.5.0.3
*/
public static enum Units {
METRIC("metric"),
IMPERIAL("imperial");
private final String unit;
Units(String unit) {
this.unit = unit;
}
}
/**
* Languages that can be set for getting data from OWM.org
*
* @since 2.5.0.3
*/
public static enum Language {
ENGLISH("en"),
RUSSIAN("ru"),
ITALIAN("it"),
SPANISH("es"),
UKRAINIAN("uk"),
GERMAN("de"),
PORTUGUESE("pt"),
ROMANIAN("ro"),
POLISH("pl"),
FINNISH("fi"),
DUTCH("nl"),
FRENCH("FR"),
BULGARIAN("bg"),
SWEDISH("sv"),
CHINESE_TRADITIONAL("zh_tw"),
CHINESE_SIMPLIFIED("zh"),
TURKISH("tr"),
CROATIAN("hr"),
CATALAN("ca");
private final String lang;
Language(String lang) {
this.lang = lang;
}
}
/**
* Generates addresses for accessing the information from OWM.org
*
* @since 2.5.0.3
*/
public static class OWMAddress {
private final String MODE = "json";
private final String ENCODING = "UTF-8";
private String mode;
private Units units;
private String appId;
private Language lang;
/*
Constructors
*/
private OWMAddress(String appId) {
this(Units.IMPERIAL, Language.ENGLISH, appId);
}
private OWMAddress(Units units, String appId) {
this(units, Language.ENGLISH, appId);
}
private OWMAddress(Units units, Language lang, String appId) {
this.mode = MODE;
this.units = units;
this.lang = lang;
this.appId = appId;
}
/*
Getters
*/
private String getAppId() {
return this.appId;
}
private Units getUnits() {
return this.units;
}
private String getMode() {
return this.mode;
}
private Language getLang() {
return this.lang;
}
/*
Setters
*/
private void setUnits(Units units) {
this.units = units;
}
private void setAppId(String appId) {
this.appId = appId;
}
private void setLang(Language lang) {
this.lang = lang;
}
/*
Addresses for current weather
*/
public String currentWeatherByCityName(String cityName) throws UnsupportedEncodingException {
return new StringBuilder()
.append(URL_API).append(URL_CURRENT)
.append(PARAM_CITY_NAME).append(URLEncoder.encode(cityName, ENCODING)).append("&")
.append(PARAM_MODE).append(this.mode).append("&")
.append(PARAM_UNITS).append(this.units).append("&")
.append(PARAM_LANG).append(this.lang).append("&")
.append(PARAM_APPID).append(this.appId)
.toString();
}
public String currentWeatherByCityName(String cityName, String countryCode) throws UnsupportedEncodingException {
return currentWeatherByCityName(new StringBuilder()
.append(cityName).append(",").append(countryCode)
.toString());
}
public String currentWeatherByCityCode(long cityCode) {
return new StringBuilder()
.append(URL_API).append(URL_CURRENT)
.append(PARAM_CITY_ID).append(Long.toString(cityCode)).append("&")
.append(PARAM_MODE).append(this.mode).append("&")
.append(PARAM_UNITS).append(this.units).append("&")
.append(PARAM_LANG).append(this.lang).append("&")
.append(PARAM_APPID).append(this.appId)
.toString();
}
public String currentWeatherByCoordinates(float latitude, float longitude) {
return new StringBuilder()
.append(URL_API).append(URL_CURRENT)
.append(PARAM_LATITUDE).append(Float.toString(latitude)).append("&")
.append(PARAM_LONGITUDE).append(Float.toString(longitude)).append("&")
.append(PARAM_MODE).append(this.mode).append("&")
.append(PARAM_UNITS).append(this.units).append("&")
.append(PARAM_APPID).append(this.appId)
.toString();
}
/*
Addresses for hourly forecasts
*/
public String hourlyForecastByCityName(String cityName) throws UnsupportedEncodingException {
return new StringBuilder()
.append(URL_API).append(URL_HOURLY_FORECAST)
.append(PARAM_CITY_NAME).append(URLEncoder.encode(cityName, ENCODING)).append("&")
.append(PARAM_MODE).append(this.mode).append("&")
.append(PARAM_UNITS).append(this.units).append("&")
.append(PARAM_LANG).append(this.lang).append("&")
.append(PARAM_APPID).append(this.appId)
.toString();
}
public String hourlyForecastByCityName(String cityName, String countryCode) throws UnsupportedEncodingException {
return hourlyForecastByCityName(new StringBuilder()
.append(cityName).append(",").append(countryCode)
.toString());
}
public String hourlyForecastByCityCode(long cityCode) {
return new StringBuilder()
.append(URL_API).append(URL_HOURLY_FORECAST)
.append(PARAM_CITY_ID).append(Long.toString(cityCode)).append("&")
.append(PARAM_MODE).append(this.mode).append("&")
.append(PARAM_UNITS).append(this.units).append("&")
.append(PARAM_LANG).append(this.lang).append("&")
.append(PARAM_APPID).append(this.appId)
.toString();
}
public String hourlyForecastByCoordinates(float latitude, float longitude) {
return new StringBuilder()
.append(URL_API).append(URL_HOURLY_FORECAST)
.append(PARAM_LATITUDE).append(Float.toString(latitude)).append("&")
.append(PARAM_LONGITUDE).append(Float.toString(longitude)).append("&")
.append(PARAM_MODE).append(this.mode).append("&")
.append(PARAM_UNITS).append(this.units).append("&")
.append(PARAM_LANG).append(this.lang).append("&")
.append(PARAM_APPID).append(this.appId)
.toString();
}
/*
Addresses for daily forecasts
*/
public String dailyForecastByCityName(String cityName, byte count) throws UnsupportedEncodingException {
return new StringBuilder()
.append(URL_API).append(URL_DAILY_FORECAST)
.append(PARAM_CITY_NAME).append(URLEncoder.encode(cityName, ENCODING)).append("&")
.append(PARAM_COUNT).append(Byte.toString(count)).append("&")
.append(PARAM_MODE).append(this.mode).append("&")
.append(PARAM_UNITS).append(this.units).append("&")
.append(PARAM_LANG).append(this.lang).append("&")
.append(PARAM_APPID).append(this.appId)
.toString();
}
public String dailyForecastByCityName(String cityName, String countryCode, byte count) throws UnsupportedEncodingException {
return dailyForecastByCityName(new StringBuilder()
.append(cityName).append(",").append(countryCode)
.toString(), count);
}
public String dailyForecastByCityCode(long cityCode, byte count) {
return new StringBuilder()
.append(URL_API).append(URL_DAILY_FORECAST)
.append(PARAM_CITY_ID).append(Long.toString(cityCode)).append("&")
.append(PARAM_COUNT).append(Byte.toString(count)).append("&")
.append(PARAM_MODE).append(this.mode).append("&")
.append(PARAM_UNITS).append(this.units).append("&")
.append(PARAM_LANG).append(this.lang).append("&")
.append(PARAM_APPID).append(this.appId)
.toString();
}
public String dailyForecastByCoordinates(float latitude, float longitude, byte count) {
return new StringBuilder()
.append(URL_API).append(URL_DAILY_FORECAST)
.append(PARAM_LATITUDE).append(Float.toString(latitude)).append("&")
.append(PARAM_LONGITUDE).append(Float.toString(longitude)).append("&")
.append(PARAM_COUNT).append(Byte.toString(count)).append("&")
.append(PARAM_MODE).append(this.mode).append("&")
.append(PARAM_UNITS).append(this.units).append("&")
.append(PARAM_LANG).append(this.lang).append("&")
.append(PARAM_APPID).append(this.appId)
.toString();
}
}
/**
* Requests OWM.org for data and provides back the incoming response.
*
* @since 2.5.0.3
*/
private static class OWMResponse {
private final OWMAddress owmAddress;
private OWMResponse(OWMAddress owmAddress) {
this.owmAddress = owmAddress;
}
/*
Responses for current weather
*/
public String currentWeatherByCityName(String cityName) throws UnsupportedEncodingException {
String address = owmAddress.currentWeatherByCityName(cityName);
return httpGET(address);
}
public String currentWeatherByCityName(String cityName, String countryCode) throws UnsupportedEncodingException {
String address = owmAddress.currentWeatherByCityName(cityName, countryCode);
return httpGET(address);
}
public String currentWeatherByCityCode(long cityCode) {
String address = owmAddress.currentWeatherByCityCode(cityCode);
return httpGET(address);
}
public String currentWeatherByCoordinates(float latitude, float longitude) {
String address = owmAddress.currentWeatherByCoordinates(latitude, longitude);
return httpGET(address);
}
/*
Responses for daily forecasts
*/
public String hourlyForecastByCityName(String cityName) throws UnsupportedEncodingException {
String address = owmAddress.hourlyForecastByCityName(cityName);
return httpGET(address);
}
public String hourlyForecastByCityName(String cityName, String countryCode) throws UnsupportedEncodingException {
String address = owmAddress.hourlyForecastByCityName(cityName, countryCode);
return httpGET(address);
}
public String hourlyForecastByCityCode(long cityCode) {
String address = owmAddress.hourlyForecastByCityCode(cityCode);
return httpGET(address);
}
public String hourlyForecastByCoordinates(float latitude, float longitude) {
String address = owmAddress.hourlyForecastByCoordinates(latitude, longitude);
return httpGET(address);
}
/*
Responses for daily forecasts
*/
public String dailyForecastByCityName(String cityName, byte count) throws UnsupportedEncodingException {
String address = owmAddress.dailyForecastByCityName(cityName, count);
return httpGET(address);
}
public String dailyForecastByCityName(String cityName, String countryCode, byte count) throws UnsupportedEncodingException {
String address = owmAddress.dailyForecastByCityName(cityName, countryCode, count);
return httpGET(address);
}
public String dailyForecastByCityCode(long cityCode, byte count) {
String address = owmAddress.dailyForecastByCityCode(cityCode, count);
return httpGET(address);
}
public String dailyForecastByCoordinates(float latitude, float longitude, byte count) {
String address = owmAddress.dailyForecastByCoordinates(latitude, longitude, count);
return httpGET(address);
}
/**
* Implements HTTP's GET method
*
* @param requestAddress Address to be loaded
* @return Response if successful, else <code>null</code>
* @see <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html">HTTP - (9.3) GET</a>
*/
private String httpGET(String requestAddress) {
URL request;
HttpURLConnection connection = null;
BufferedReader reader = null;
String s;
String response = null;
try {
request = new URL(requestAddress);
connection = (HttpURLConnection) request.openConnection();
connection.setRequestMethod("GET");
connection.setUseCaches(false);
connection.setDoInput(true);
connection.setDoOutput(false);
connection.setRequestProperty("Accept-Encoding", "gzip");
connection.connect();
if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) {
try {
if (connection.getRequestProperty("Accept-Encoding") != null) {
reader = new BufferedReader(new InputStreamReader(new GZIPInputStream(connection.getInputStream())));
while ((s = reader.readLine()) != null) {
response = s;
}
} else {
reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
while ((s = reader.readLine()) != null) {
response = s;
}
}
} catch (IOException e) {
System.err.println("Error: " + e.getMessage());
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
System.err.println("Error: " + e.getMessage());
}
}
}
} else { // if HttpURLConnection is not okay
try {
reader = new BufferedReader(new InputStreamReader(connection.getErrorStream()));
while ((s = reader.readLine()) != null)
response = s;
} catch (IOException e) {
System.err.println("Error: " + e.getMessage());
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
System.err.println("Error: " + e.getMessage());
}
}
}
// if response is bad
System.err.println("Bad Response: " + response + "\n");
return null;
}
} catch (IOException e) {
System.err.println("Error: " + e.getMessage());
response = null;
} finally {
if (connection != null) {
connection.disconnect();
}
}
return response;
}
}
}

View file

@ -0,0 +1,91 @@
/*
* Copyright (c) 2013-2014 Ashutosh Kumar Singh <me@aksingh.net>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package net.aksingh.owmjapis;
/**
* <p>
* Provides methods for conversions, etc.
* </p>
*
* @author Ashutosh Kumar Singh
* @version 2014-12-27
* @since 2.5.0.1
*/
public class Tools {
/**
* <p>
* Converts degree to direction.
* </p>
*
* @param degree Degree of wind as received from OWM.org
* @return Direction
* @throws IllegalArgumentException Degree should be between 0 and 360.
*/
public String convertDegree2Direction(float degree)
throws IllegalArgumentException {
String direction;
// degree should be between 0 and 360
if ((degree < 0.0f) || (degree > 360.0f)) {
throw new IllegalArgumentException("Degree cannot be less than 0 or more than 360.");
}
if (degree <= 11.25f) {
direction = "N";
} else if (degree <= 33.75f) {
direction = "NNE";
} else if (degree <= 56.25f) {
direction = "NE";
} else if (degree <= 78.75f) {
direction = "ENE";
} else if (degree <= 101.25f) {
direction = "E";
} else if (degree <= 123.75f) {
direction = "ESE";
} else if (degree <= 146.25f) {
direction = "SE";
} else if (degree <= 168.75f) {
direction = "SSE";
} else if (degree <= 191.25f) {
direction = "S";
} else if (degree <= 213.75f) {
direction = "SSW";
} else if (degree <= 236.25f) {
direction = "SW";
} else if (degree <= 258.75f) {
direction = "WSW";
} else if (degree <= 281.25f) {
direction = "W";
} else if (degree <= 303.75f) {
direction = "WNW";
} else if (degree <= 326.25f) {
direction = "NW";
} else if (degree <= 348.75f) {
direction = "NNW";
} else {
direction = "N";
}
return direction;
}
}