Commit 6dd5dae5 authored by Christopher Bohn's avatar Christopher Bohn 🤔
Browse files

Initial commit

parents
# Mac file finder metadata
.DS_Store
# Windows file metadata
._*
# Thumbnail image caches
Thumbs.db
ethumbs.db
# MS Office temporary file
~*
# Emacs backup file
*~
# Common
[Bb]in/
[Bb]uild/
[Oo]bj/
[Oo]ut/
[Tt]mp/
[Xx]86/
[Ii][Aa]32/
[Xx]64/
[Xx]86_64/
[Xx]86-64/
[Aa]rm
[Aa]32
[Tt]32
[Aa]64
*.tmp
*.bak
*.bk
*.swp
# Java files
*.class
javadoc/
# Maven
target/
pom.xml.tag
pom.xml.releaseBackup
pom.xml.versionsBackup
pom.xml.next
release.properties
dependency-reduced-pom.xml
buildNumber.properties
.mvn/timing.properties
# JetBrains (IntelliJ IDEA, PyCharm, etc) files
.idea/
cmake-build-*/
*.iml
*.iws
*.ipr
# Eclipse files
.settings/
.project
.classpath
.buildpath
.loadpath
.factorypath
local.properties
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>edu.unl.cse.soft160.rest_connector</groupId>
<artifactId>rest_and_file_connector</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>rest_connector</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>8</source>
<target>8</target>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>com.googlecode.json-simple</groupId>
<artifactId>json-simple</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jetbrains</groupId>
<artifactId>annotations</artifactId>
<version>RELEASE</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>
package edu.unl.cse.soft160.json_connections;
import edu.unl.cse.soft160.json_connections.connector.OpenWeatherConnector;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Objects;
public class Main {
private static String getApiKey() {
JSONObject apiKeyJson = null;
String filename = "apikey.json";
try (InputStreamReader inputStreamReader = new InputStreamReader(Objects.requireNonNull(
Main.class.getClassLoader().getResourceAsStream(filename)))) {
apiKeyJson = (JSONObject)new JSONParser().parse(inputStreamReader);
} catch (NullPointerException nullPointerException) {
System.err.println("Could not find " + filename + ". Terminating.");
System.exit(1);
} catch (IOException ioException) {
System.err.println("Error loading " + filename + ". Terminating.");
System.exit(1);
} catch (ParseException parseException) {
System.err.println("Parse exception encountered while parsing " + filename + ". Terminating.");
System.exit(1);
}
return apiKeyJson.get("apikey").toString();
}
public static void main(String... args) {
String apiKey = getApiKey();
OpenWeatherConnector weather = new OpenWeatherConnector("weather", apiKey);
String data = null;
try {
data = weather.retrieveData("zip=68588");
} catch (IOException e) {
e.printStackTrace();
}
System.out.println(data);
System.out.println(weather.getWeatherCategory());
System.out.println("Temperature: " + weather.getTemperature() + "K");
System.out.println("Cloud cover: " + weather.getCloudCover() + "%");
System.out.println("Timestamp: " + weather.getTimestamp());
}
}
package edu.unl.cse.soft160.json_connections.connection;
import org.json.simple.JSONObject;
import org.json.simple.parser.ParseException;
import java.io.IOException;
public interface Connection {
JSONObject get(String filename) throws IOException, ParseException;
}
package edu.unl.cse.soft160.json_connections.connection;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Objects;
public class FileConnection implements Connection {
String directory;
public FileConnection() {
directory = "";
}
public FileConnection(String directory) {
this.directory = directory + "/";
}
public JSONObject get(String filename) throws IOException, ParseException {
JSONObject data;
try (InputStreamReader inputStreamReader = new InputStreamReader(Objects.requireNonNull(
FileConnection.class.getClassLoader().getResourceAsStream(directory + filename)))) {
data = (JSONObject)new JSONParser().parse(inputStreamReader);
} catch (NullPointerException originalException) {
throw new IOException("Could not find " + filename + ".", originalException);
}
return data;
}
public void save(String filename, JSONObject data) throws IOException {
FileWriter fileWriter = new FileWriter(filename);
data.writeJSONString(fileWriter);
fileWriter.close();
}
}
package edu.unl.cse.soft160.json_connections.connection;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLConnection;
public class RestConnection implements Connection {
protected final String protocol;
protected final String authority;
protected final String path;
protected final String apiKey;
public RestConnection(String protocol, String authority, String path, String apiKey) {
this.protocol = protocol;
this.authority = authority;
this.path = path;
this.apiKey = apiKey;
}
public JSONObject get(String query) throws IOException, ParseException {
JSONObject data;
try {
URLConnection connection =
new URI(protocol,
authority,
path,
query + "&appid=" + apiKey,
null).toURL().openConnection();
// connection.setRequestProperty("Accept", "application/json");
InputStreamReader inputStreamReader = new InputStreamReader(connection.getInputStream());
data = (JSONObject)new JSONParser().parse(inputStreamReader);
} catch (URISyntaxException | MalformedURLException originalException) {
throw new IOException("Could not retrieve usable data from " + authority + ".", originalException);
}
return data;
}
}
package edu.unl.cse.soft160.json_connections.connector;
import edu.unl.cse.soft160.json_connections.connection.Connection;
import edu.unl.cse.soft160.json_connections.connection.FileConnection;
import edu.unl.cse.soft160.json_connections.connection.RestConnection;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.ParseException;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
public class OpenWeatherConnector {
public enum WeatherCategory {
THUNDERSTORM, DRIZZLE, RAIN, SNOW, ATMOSPHERE, CLEAR, CLOUDS, UNKNOWN_CATEGORY,
}
protected enum DataSet {
WEATHER, ONECALL, FORECAST, AIR_POLLUTION, DIRECT, STATIONS, // TRIGGERS, // triggers is a POST call
}
protected static final String PROTOCOL = "http";
protected static final String REST_AUTHORITY = "api.openweathermap.org";
protected static String REST_PATH; // Should be able to declare this as final, but static analysis doesn't see that
protected final Connection dataSource;
protected final DataSet dataSet;
protected JSONObject data;
public OpenWeatherConnector(String fileDataSet) {
dataSource = new FileConnection(fileDataSet);
dataSet = DataSet.valueOf(fileDataSet.toUpperCase());
data = null;
switch (dataSet) {
case WEATHER:
case ONECALL:
case FORECAST:
case AIR_POLLUTION:
REST_PATH = "/data/2.5";
break;
case DIRECT:
REST_PATH = "geo/1.0";
break;
case STATIONS:
// case TRIGGERS:
REST_PATH = "data/3.0";
break;
default:
REST_PATH = "unknown";
}
}
public OpenWeatherConnector(String restDataSet, String apiKey) {
dataSource = new RestConnection(PROTOCOL, REST_AUTHORITY, REST_PATH + restDataSet, apiKey);
dataSet = DataSet.valueOf(restDataSet.toUpperCase());
data = null;
switch (dataSet) {
case WEATHER:
case ONECALL:
case FORECAST:
case AIR_POLLUTION:
REST_PATH = "/data/2.5";
break;
case DIRECT:
REST_PATH = "geo/1.0";
break;
case STATIONS:
// case TRIGGERS:
REST_PATH = "data/3.0";
break;
default:
REST_PATH = "unknown";
}
}
public String retrieveData(String requestedData) throws IOException {
try {
data = dataSource.get(requestedData);
} catch (FileNotFoundException fileNotFoundException) {
if (dataSource instanceof RestConnection) {
throw new IOException("Could not access \"" + dataSet.toString().toLowerCase()
+ "\" dataset at " + REST_AUTHORITY + ".",
fileNotFoundException);
} else {
throw fileNotFoundException; // For FileConnection, this exception is exactly what's on the label,
} // except that we'd more likely see a...
} catch (NullPointerException nullPointerException) {
if (dataSource instanceof FileConnection) {
FileNotFoundException newException = new FileNotFoundException("File " + requestedData + " not found.");
newException.initCause(nullPointerException);
throw newException;
} else {
throw nullPointerException; // Not going to try to predict why RestConnection generates NPE
}
} catch (ParseException parseException) {
String message;
if (dataSource instanceof FileConnection) {
message = "Error while parsing file " + requestedData + ".";
} else if (dataSource instanceof RestConnection) {
message = "Error while parsing the " + dataSet.toString().toLowerCase()
+ " response from " + REST_AUTHORITY + ".";
} else {
message = "Error while parsing requested data.";
}
throw new IOException(message, parseException);
}
return data.toJSONString();
}
private void checkForDataPresence() {
if (data == null) {
throw new IllegalStateException("No data has been retrieved from the "
+ dataSet.toString().toLowerCase() + "dataset.");
}
}
private double retrieveDoubleValue(String field, double defaultValue) {
checkForDataPresence();
double returnValue = defaultValue;
if (data.containsKey(field)) {
Double value = (Double)data.get(field);
returnValue = value == null ? defaultValue : value;
}
return returnValue;
}
private double retrieveDoubleValue(String topLevelField, String subField, double defaultValue) {
checkForDataPresence();
double returnValue = defaultValue;
if (data.containsKey(topLevelField)) {
JSONObject observations = (JSONObject)data.get(topLevelField);
if (data.containsKey(subField)) {
Double value = (Double)observations.get(subField);
returnValue = value == null ? defaultValue : value;
}
}
return returnValue;
}
private long retrieveLongValue(String field, long defaultValue) {
checkForDataPresence();
long returnValue = defaultValue;
if (data.containsKey(field)) {
Long value = (Long)data.get(field);
returnValue = value == null ? defaultValue : value;
}
return returnValue;
}
private long retrieveLongValue(String topLevelField, String subField, long defaultValue) {
checkForDataPresence();
long returnValue = defaultValue;
if (data.containsKey(topLevelField)) {
JSONObject observations = (JSONObject)data.get(topLevelField);
if (data.containsKey(subField)) {
Long value = (Long)observations.get(subField);
returnValue = value == null ? defaultValue : value;
}
}
return returnValue;
}
/* For now, we're only working with the current "weather" dataSet.
* We probably want to add "onecall" "forecast" "air_pollution"
* Not "map" since that doesn't look to be a download, and certainly not JSON
*/
public double getLatitude() {
return retrieveDoubleValue("coord", "lat", Double.NaN);
}
public double getLongitude() {
return retrieveDoubleValue("coord", "long", Double.NaN);
}
public Date getTimestamp() {
long unixTime = retrieveLongValue("dt", Long.MIN_VALUE);
return new Date(unixTime * 1000);
}
public List<WeatherCategory> getWeatherCategory() {
checkForDataPresence();
JSONArray weather = (JSONArray)data.get("weather");
List<WeatherCategory> categories = new ArrayList<>(weather.size());
for (Object condition : weather) {
String category = ((JSONObject)condition).get("main").toString();
try {
categories.add(WeatherCategory.valueOf(category.toUpperCase()));
} catch (IllegalArgumentException ignored) {
categories.add(WeatherCategory.UNKNOWN_CATEGORY);
}
}
return categories;
}
public List<String> getWeatherDescriptions() {
checkForDataPresence();
JSONArray weather = (JSONArray)data.get("weather");
List<String> categories = new ArrayList<>(weather.size());
for (Object condition : weather) {
categories.add(((JSONObject)condition).get("description").toString());
}
return categories;
}
public long getVisibility() {
return retrieveLongValue("visibility", Long.MIN_VALUE);
}
public double getTemperature() {
return retrieveDoubleValue("main", "temp", Double.NaN);
}
public long getHumidity() {
return retrieveLongValue("main", "humidity", Long.MIN_VALUE);
}
public double getFeelsLike() {
return retrieveDoubleValue("main", "feels_like", Double.NaN);
}
public long getPressure() {
return retrieveLongValue("main", "pressure", Long.MIN_VALUE);
}
public long getWindDirection() {
return retrieveLongValue("wind", "deg", Long.MIN_VALUE);
}
public double getWindSpeed() {
return retrieveDoubleValue("wind", "speed", 0.0);
}
public double getWindGust() {
checkForDataPresence();
if (data.containsKey("wind")) {
JSONObject wind = (JSONObject)data.get("wind");
return retrieveDoubleValue("gust", getWindSpeed());
} else {
return 0.0;
}
}
public long getCloudCover() {
return retrieveLongValue("clouds", "all", 0);
}
public double getOneHourRainfall() {
return retrieveDoubleValue("rain", "1h", 0.0);
}
public double getThreeHourRainfall() {
return retrieveDoubleValue("rain", "3h", 0.0);
}
public double getOneHourSnowfall() {
return retrieveDoubleValue("snow", "1h", 0.0);
}
public double getThreeHourSnowfall() {
return retrieveDoubleValue("snow", "3h", 0.0);
}
}
{
"visibility" : 10000,
"timezone" : -18000,
"main" : {
"temp" : 281.8,
"temp_min" : 279.77,
"humidity" : 73,
"pressure" : 1023,
"feels_like" : 281.45,
"temp_max" : 283.4
},
"clouds" : {
"all" : 34
},
"sys" : {
"country" : "US",
"sunrise" : 1634820289,
"sunset" : 1634859453,
"id" : 2039228,
"type" : 2
},
"dt" : 1634835577,
"coord" : {
"lon" : -96.6928,
"lat" : 40.8206
},
"weather" : [
{
"icon" : "03d",
"description" : "scattered clouds",
"main" : "Clouds",
"id" : 802
}
],
"name" : "Lincoln",
"cod" : 200,
"id" : 0,
"base" : "stations",
"wind" : {
"deg" : 41,
"speed" : 1.34,
"gust" : 3.13
}
}
\ No newline at end of file
Supports Markdown