package com.upweather.upweatherrequest;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;
import net.sf.json.JSONArray;
import net.sf.json.JSONException;
import net.sf.json.JSONObject;
import com.uplibrary.upexception.UPInvalidParameterException;
import com.uplibrary.upobject.UPPair;
import com.uplibrary.uprequest.UPHttpsRequest;
import com.upweather.upobject.*;
/**
* This class provides methods to obtain place forecasts, time series, models,
* outputs and so on.
* @author Giuseppe Persico - giuseppe.persico@studenti.uniparthenope.it
* @version 1.0
*/
public final class UPWeatherRequest extends UPHttpsRequest {
/**
* The constructor sets the request headers and the request type.
* @throws UPInvalidParameterException if invalid parameters are specified.
*/
public UPWeatherRequest() throws UPInvalidParameterException {
super("GET");
this.addProperty(new UPPair<>("Content-Type","application/json"));
}
/**
* This method returns all the models.
* @return an array containing UPModel objects.
* @throws IOException if connection hangs.
* @throws UPInvalidParameterException if parameters specified are invalid.
*/
public final ArrayList<UPModel> getModels() throws IOException, UPInvalidParameterException {
this.setUrl("https://api.uniparthenope.it/meteo/models/getmodels");
final JSONObject json = this.connect();
final JSONObject modelsRequested = json.getJSONObject("models");
final Iterator it = modelsRequested.keys();
ArrayList<UPModel> UPModels = new ArrayList<>();
while (it.hasNext()) {
Object currentKey = it.next();
UPModels.add(new UPModel(currentKey.toString(),modelsRequested.get(currentKey).toString()));
}
return UPModels;
}
/**
* This method returns a model using the modelRequested parameters as a filter.
* @param modelRequested the model requested.
* @return an UPModel object.
* @throws IOException if connection hangs.
* @throws UPInvalidParameterException if the parameters specified are invalid.
*/
public final UPModel getModels(final String modelRequested) throws IOException, UPInvalidParameterException {
if (modelRequested==null || modelRequested.isEmpty()) {
throw new UPInvalidParameterException("The model requested is not valid");
}
this.setUrl("https://api.uniparthenope.it/meteo/models/getmodels");
final String requestedModel = this.connect().getJSONObject("models").getString(modelRequested);
if (requestedModel!=null) {
return new UPModel(modelRequested,requestedModel);
}
return null;
}
/**
* This method returns all the outputs for a model.
* @param model the model.
* @return an array of UPOutput objects.
* @throws IOException if connection hangs.
* @throws UPInvalidParameterException if parameters specified are invalid.
*/
public final ArrayList<UPOutput> getOutputs(final String model) throws IOException, UPInvalidParameterException {
if (model == null || model.isEmpty()) {
throw new UPInvalidParameterException("The model can not be a null or an empty string");
}
this.setUrl("https://api.uniparthenope.it/meteo/"+model+"/getoutputs");
final JSONObject requestsOutputs = this.connect().getJSONObject("outputs");
final Iterator it = requestsOutputs.keys();
ArrayList<UPOutput> outputs = new ArrayList<>();
while (it.hasNext()) {
Object currentKey = it.next();
outputs.add(new UPOutput(currentKey.toString(),requestsOutputs.get(currentKey).toString()));
}
return outputs;
}
/**
* This method returns the outputs for a model and filtering the outputs with
* the outputRequested parameter.
* @param model the model.
* @param outputRequested the output requested.
* @return an object of type UPOutput.
* @throws IOException if connection hangs.
* @throws UPInvalidParameterException if invalid parameters are specified.
*/
public final UPOutput getOutputs(final String model, final String outputRequested) throws IOException, UPInvalidParameterException {
if (model == null || model.isEmpty()) {
throw new UPInvalidParameterException("The model can not be a null or an empty string");
} else if (outputRequested==null || outputRequested.isEmpty()) {
throw new UPInvalidParameterException("The output requested can not be null or an empty string");
}
this.setUrl("https://api.uniparthenope.it/meteo/"+model+"/getoutputs");
final Object requestedOutput = this.connect().getJSONObject("outputs").get(outputRequested);
if (requestedOutput != null) {
return new UPOutput(outputRequested,requestedOutput.toString());
}
return null;
}
/**
* This method returns a place using its name to search for it.
* @param placeName the place name
* @return an array of UPPlace objects
* @throws IOException if connection hangs.
* @throws UPInvalidParameterException if invalid parameters are specified.
*/
public final ArrayList<UPPlace> getPlaceByName(final String placeName) throws IOException, UPInvalidParameterException {
if (placeName==null || placeName.isEmpty()) {
throw new UPInvalidParameterException("Place name can not be null or an empty string");
}
this.setUrl("https://api.uniparthenope.it/meteo/byplacename/"+placeName);
final JSONArray placesJson = this.connect().getJSONArray("places");
ArrayList<UPPlace> places = new ArrayList<>(placesJson.size());
for (int i = 0; i < placesJson.size(); ++i) {
places.add(this.parsePlaces(placesJson.getJSONObject(i)));
}
return places;
}
/**
* This method returns a place using its identifier to search for it.
* @param identifier place identifier.
* @return an object of type UPPlace.
* @throws IOException if connection hangs.
* @throws UPInvalidParameterException if invalid parameters are specified.
*/
public final UPPlace getPlaceByIdentifier(final String identifier) throws IOException, UPInvalidParameterException {
if (identifier==null || identifier.isEmpty()) {
throw new UPInvalidParameterException("Identifier can not be a null or an empty string");
}
this.setUrl("https://api.uniparthenope.it/meteo/byid/"+identifier);
final JSONArray placesJson = this.connect().getJSONArray("places");
if (placesJson.size() > 0) {
return this.parsePlaces(placesJson.getJSONObject(0));
}
return null;
}
/**
* This method returns the nearest places using the coordinates passed as parameter.
* @param coordinates place coordinates.
* @return an array with UPPlace objects
* @throws IOException if connection hangs.
* @throws UPInvalidParameterException if invalid parameters are specified.
*/
public final ArrayList<UPPlace> getNearestPLaces(final UPCoordinate coordinates) throws IOException, UPInvalidParameterException {
this.setUrl("https://api.uniparthenope.it/meteo/bycoords/"+coordinates.getLatitude()+"/"+coordinates.getLongitude());
return this.parseNearestPlaces();
}
/**
* This method returns the nearest places filtering them with coordinates
* distance in kilometers and how many results to get.
* @param coordinates place coordinates.
* @param distanceKm distance in kilometers.
* @param resultsNumber how many results you want to get.
* @return an array of UPPlace objects.
* @throws IOException if connection hangs.
* @throws UPInvalidParameterException if invalid parameters are specified.
*/
public final ArrayList<UPPlace> getNearestPlaces(final UPCoordinate coordinates, final Double distanceKm, final int resultsNumber) throws IOException, UPInvalidParameterException {
this.setUrl("https://api.uniparthenope.it/meteo/bycoords/"+coordinates.getLatitude()+"/"+coordinates.getLongitude());
if (resultsNumber < 0) {
return this.parseNearestPlaces("radius="+distanceKm);
} else {
return this.parseNearestPlaces("limit="+resultsNumber+"&radius="+distanceKm);
}
}
/**
* This method returns a place forecasts filtering the place with an identifier
* @param identifier place identifier.
* @return an object of type UPForecast
* @throws IOException if connection hangs.
* @throws UPInvalidParameterException if invalid parameters are specified.
* @throws InvocationTargetException if internal error occurs.
* @throws IllegalAccessException if internal error occurs.
* @throws NoSuchMethodException if internal error occurs.
*/
public final UPForecast getPlaceForecasts(final String identifier) throws IOException, UPInvalidParameterException, InvocationTargetException, IllegalAccessException, NoSuchMethodException {
if (identifier==null || identifier.isEmpty()) {
throw new UPInvalidParameterException("Place identifier can not be null or an empty string");
}
this.setUrl("https://api.uniparthenope.it/meteo/" + identifier + "/modeloutput");
return this.parseJsonForecasts();
}
/**
* This method returns a place forecasts filtering the place with an identifier a model and an output.
* @param identifier place identifier.
* @param model a model
* @param output an output.
* @return UPForecast object.
* @throws IOException if connection hangs
* @throws UPInvalidParameterException if invalid parameters are specified.
* @throws NoSuchMethodException if internal errors occurs.
* @throws IllegalAccessException if internal errors occurs.
* @throws InvocationTargetException if internal errors occurs.
*/
public final UPForecast getPlaceForecasts(final String identifier, final String model, final String output) throws IOException, UPInvalidParameterException, NoSuchMethodException, IllegalAccessException, InvocationTargetException {
if (identifier==null || identifier.isEmpty()) {
throw new UPInvalidParameterException("Identifier can not be null or an empty string");
} else if (model==null || model.isEmpty()) {
throw new UPInvalidParameterException("Model can not be null or an empty string");
} else if (output==null || output.isEmpty()) {
throw new UPInvalidParameterException("Output can not be null or an empty string");
}
this.setUrl("https://api.uniparthenope.it/meteo/"+identifier+"/"+model+"/"+output+"/modeloutput");
return this.parseJsonForecasts();
}
/**
* This method retrieve place forecasts using a place identifier, a model, an output and a time.
* @param identifier the place identifier.
* @param model the model.
* @param output the output.
* @param time the time.
* @return an UPForecast object.
* @throws IOException if connection hangs.
* @throws UPInvalidParameterException if invalid parameters are specified.
* @throws NoSuchMethodException if internal errors occurs.
* @throws InvocationTargetException if internal errors occurs.
* @throws IllegalAccessException if internal errors occurs.
*/
public final UPForecast getPlaceForecasts(final String identifier, final String model, final String output, final UPDateTime time) throws IOException, UPInvalidParameterException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
if (identifier==null || identifier.isEmpty()) {
throw new UPInvalidParameterException("Identifier can not be null or an empty string");
} else if (model==null || model.isEmpty()) {
throw new UPInvalidParameterException("Model can not be null or an empty string");
} else if (output==null || output.isEmpty()) {
throw new UPInvalidParameterException("Output can not be null or an empty string");
} else if (time==null) {
throw new UPInvalidParameterException("The time must be specified in this API");
}
this.setUrl("https://api.uniparthenope.it/meteo/"+identifier+"/"+model+"/"+output+"/"+time.getYear()+"/"+time.getMonth()+"/"+time.getDay()+"/"+time.getHour()+"/modeloutput");
return this.parseJsonForecasts();
}
/**
* This method retrieve the time series storing them in a UPTimeSeries object.
* @return an UPTimeSeries object
* @throws IOException if connection hangs.
* @throws UPInvalidParameterException if invalid parameters are specified.
* @throws NoSuchMethodException if internal errors occurs.
* @throws IllegalAccessException if internal errors occurs.
* @throws IllegalArgumentException if internal errors occurs.
* @throws InvocationTargetException if internal errors occurs.
*/
public final UPTimeSeries getTimeSeries() throws IOException, UPInvalidParameterException, NoSuchMethodException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
this.setUrl("https://api.uniparthenope.it/meteo/timeseries");
JSONArray timeSeriesArray;
try {
timeSeriesArray = this.connect().getJSONObject("timeseries").getJSONObject("timeseries").getJSONObject("places").getJSONObject("place").getJSONObject("runs").getJSONArray("run").getJSONObject(0).getJSONArray("time");
} catch (JSONException exc) {
return null;
}
JSONObject currentObject;
UPTimeSeries series = new UPTimeSeries(timeSeriesArray.size());
Set keys = UPForecast.HASH_METHODS.keySet();
for (Object timeSeries : timeSeriesArray) {
currentObject = (JSONObject) timeSeries;
UPForecast forecast = this.parseJsonTimeSeries(currentObject, keys);
series.addForecast(forecast);
}
return series;
}
/**
* Utility method that parse a JSON object to find time series.
* @param jsonObject a JSON object
* @param keys methods to call.
* @return an UPForecast object.
* @throws NoSuchMethodException if internal errors occurs.
* @throws IllegalAccessException if internal errors occurs.
* @throws IllegalArgumentException if internal errors occurs.
* @throws InvocationTargetException if internal errors occurs.
*/
protected final UPForecast parseJsonTimeSeries(final JSONObject jsonObject, final Set keys) throws NoSuchMethodException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
UPForecast forecast = new UPForecast();
forecast.setForecastDate(jsonObject.get("@date").toString());
for (Object key : keys) {
try {
Object tmpObj = jsonObject.get(key.toString());
if (tmpObj!=null) {
Method toInvoke = UPForecast.class.getMethod(UPForecast.HASH_METHODS.get(key.toString()),String.class);
toInvoke.invoke(forecast,tmpObj.toString());
}
} catch (JSONException exc) { /* Computation must go on */ }
}
return forecast;
}
/**
* Utility method that parses a JSON to find forecasts.
* @return an UPForecast object.
* @throws NoSuchMethodException if internal errors occurs.
* @throws InvocationTargetException if internal errors occurs.
* @throws IllegalAccessException if internal errors occurs.
* @throws IOException if connection hangs.
* @throws UPInvalidParameterException if invalid parameters are specified.
*/
protected final UPForecast parseJsonForecasts() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, IOException, UPInvalidParameterException {
JSONObject json = this.connect(), weather;
try {
weather = json.getJSONObject("infoplace").getJSONObject("data").getJSONObject("places");
} catch (JSONException exc) {
return null;
}
UPForecast condition = new UPForecast();
condition.setForecastDate(weather.get("@dateTime").toString());
weather = weather.getJSONObject("place");
final Set methodsKeys = UPForecast.HASH_METHODS.keySet();
for (Object label : methodsKeys) {
try {
JSONObject tmpObj = weather.getJSONObject(label.toString());
Method toInvoke = UPForecast.class.getMethod(UPForecast.HASH_METHODS.get(label.toString()), UPPair.class);
toInvoke.invoke(condition,new UPPair<>(tmpObj.get("#text"),new UPUnit(tmpObj.get("@unit").toString())));
} catch (JSONException exc) { /* Computation must go on */}
}
return condition;
}
/**
* Utility method that parses nearest places.
* @return an array containing nearest places.
* @throws UPInvalidParameterException if invalid parameters are specified.
* @throws IOException if connection hangs.
*/
protected final ArrayList<UPPlace> parseNearestPlaces() throws UPInvalidParameterException, IOException {
final JSONObject json = this.connect();
final JSONArray placesJson = json.getJSONArray("places");
ArrayList<UPPlace> places = new ArrayList<>(placesJson.size());
for (int i=0; i<placesJson.size(); ++i) {
final JSONObject object = placesJson.getJSONObject(i);
UPPlace newPlace = new UPPlace();
newPlace.getCoordinates().setBoundsNeLat(object.get("bounds_ne_lat").toString());
newPlace.getCoordinates().setBoundsNeLong("bounds_ne_long");
newPlace.setName(object.get("placename").toString());
newPlace.getCoordinates().setLatitude(object.get("latitude").toString());
newPlace.getCoordinates().setLongitude(object.get("longitude").toString());
newPlace.getCoordinates().setBoundsSwLong(object.get("bounds_sw_long").toString());
newPlace.getCoordinates().setBoundsSwLat(object.get("bounds_sw_lat").toString());
newPlace.setExtendedName(object.get("extended").toString());
newPlace.setDistanceKm(object.get("distanceKM").toString());
newPlace.setFormattedAddress(object.get("formatted_address").toString());
newPlace.setIdentifier(object.get("identifier").toString());
places.add(newPlace);
}
return places;
}
/**
* Utility method to parse nearest places.
* @param parameter connection data.
* @return an array containing all the nearest places.
* @throws UPInvalidParameterException if invalid parameters are specified.
* @throws IOException if connection hangs.
*/
protected final ArrayList<UPPlace> parseNearestPlaces(final String parameter) throws UPInvalidParameterException, IOException {
final JSONObject json = this.connect(parameter);
final JSONArray placesJson = json.getJSONArray("places");
ArrayList<UPPlace> places = new ArrayList<>(placesJson.size());
for (int i=0; i<placesJson.size(); ++i) {
final JSONObject object = placesJson.getJSONObject(i);
UPPlace newPlace = new UPPlace();
newPlace.getCoordinates().setBoundsNeLat(object.get("bounds_ne_lat").toString());
newPlace.getCoordinates().setBoundsNeLong("bounds_ne_long");
newPlace.setName(object.get("placename").toString());
newPlace.getCoordinates().setLatitude(object.get("latitude").toString());
newPlace.getCoordinates().setLongitude(object.get("longitude").toString());
newPlace.getCoordinates().setBoundsSwLong(object.get("bounds_sw_long").toString());
newPlace.getCoordinates().setBoundsSwLat(object.get("bounds_sw_lat").toString());
newPlace.setExtendedName(object.get("extended").toString());
newPlace.setDistanceKm(object.get("distanceKM").toString());
newPlace.setFormattedAddress(object.get("formatted_address").toString());
newPlace.setIdentifier(object.get("identifier").toString());
places.add(newPlace);
}
return places;
}
/**
* Utility method used to parse a JSON object to find places.
* @param object a JSON object response
* @return a UPPlace object
* @throws UPInvalidParameterException if invalid parameters are specified.
*/
protected final UPPlace parsePlaces(final JSONObject object) throws UPInvalidParameterException {
UPPlace place = new UPPlace();
place.getCoordinates().setBoundsNeLat(object.get("bounds_ne_lat").toString());
place.getCoordinates().setBoundsNeLong("bounds_ne_long");
place.setName(object.get("placename").toString());
place.getCoordinates().setLatitude(object.get("latitude").toString());
place.getCoordinates().setLongitude(object.get("longitude").toString());
place.getCoordinates().setBoundsSwLong(object.get("bounds_sw_long").toString());
place.getCoordinates().setBoundsSwLat(object.get("bounds_sw_lat").toString());
place.setExtendedName(object.get("extended").toString());
place.setFormattedAddress(object.get("formatted_address").toString());
place.setIdentifier(object.get("identifier").toString());
return place;
}
}