Compare commits
3 commits
f88d3f1023
...
102eb026a7
Author | SHA1 | Date | |
---|---|---|---|
102eb026a7 | |||
5e8f08b423 | |||
ef7a32aab6 |
8 changed files with 472 additions and 6 deletions
34
pom.xml
34
pom.xml
|
@ -6,13 +6,20 @@
|
|||
|
||||
<groupId>eu.m724</groupId>
|
||||
<artifactId>wtapi</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<version>0.1-SNAPSHOT</version>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>17</maven.compiler.source>
|
||||
<maven.compiler.target>17</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>724rocks</id>
|
||||
<url>https://git.724.rocks/api/packages/Minecon724/maven</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
|
@ -27,4 +34,29 @@
|
|||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-release-plugin</artifactId>
|
||||
<version>3.0.1</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<distributionManagement>
|
||||
<repository>
|
||||
<id>724rocks</id>
|
||||
<url>https://git.724.rocks/api/packages/Minecon724/maven</url>
|
||||
</repository>
|
||||
<snapshotRepository>
|
||||
<id>724rocks</id>
|
||||
<url>https://git.724.rocks/api/packages/Minecon724/maven</url>
|
||||
</snapshotRepository>
|
||||
</distributionManagement>
|
||||
|
||||
<scm>
|
||||
<developerConnection>scm:git:https://git.724.rocks/Minecon724/wtapi.git</developerConnection>
|
||||
</scm>
|
||||
|
||||
</project>
|
24
release.properties
Normal file
24
release.properties
Normal file
|
@ -0,0 +1,24 @@
|
|||
#release configuration
|
||||
#Thu May 30 13:55:56 CEST 2024
|
||||
completedPhase=end-release
|
||||
exec.pomFileName=pom.xml
|
||||
exec.snapshotReleasePluginAllowed=false
|
||||
pinExternals=false
|
||||
preparationGoals=clean verify
|
||||
project.dev.eu.m724\:wtapi=1.1-SNAPSHOT
|
||||
project.rel.eu.m724\:wtapi=1.0
|
||||
project.scm.eu.m724\:wtapi.developerConnection=scm\:git\:https\://git.724.rocks/Minecon724/wtapi.git
|
||||
project.scm.eu.m724\:wtapi.tag=HEAD
|
||||
projectVersionPolicyConfig=<projectVersionPolicyConfig>${projectVersionPolicyConfig}</projectVersionPolicyConfig>\n
|
||||
projectVersionPolicyId=default
|
||||
pushChanges=true
|
||||
releaseStrategyId=default
|
||||
remoteTagging=true
|
||||
scm.branchCommitComment=@{prefix} prepare branch @{releaseLabel}
|
||||
scm.commentPrefix=[maven-release-plugin]
|
||||
scm.developmentCommitComment=@{prefix} prepare for next development iteration
|
||||
scm.releaseCommitComment=@{prefix} prepare release @{releaseLabel}
|
||||
scm.rollbackCommitComment=@{prefix} rollback the release of @{releaseLabel}
|
||||
scm.tag=wtapi-1.0
|
||||
scm.tagNameFormat=@{project.artifactId}-@{project.version}
|
||||
scm.url=scm\:git\:https\://git.724.rocks/Minecon724/wtapi.git
|
5
src/main/java/eu/m724/wtapi/object/Severity.java
Normal file
5
src/main/java/eu/m724/wtapi/object/Severity.java
Normal file
|
@ -0,0 +1,5 @@
|
|||
package eu.m724.wtapi.object;
|
||||
|
||||
public enum Severity {
|
||||
LIGHT, MODERATE, HEAVY
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
package eu.m724.wtapi.object;
|
||||
|
||||
public enum WeatherState {
|
||||
CLEAR, RAIN, THUNDER
|
||||
}
|
|
@ -0,0 +1,230 @@
|
|||
package eu.m724.wtapi.provider.impl.openweathermap;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonPrimitive;
|
||||
|
||||
import eu.m724.wtapi.object.Coordinates;
|
||||
import eu.m724.wtapi.object.Severity;
|
||||
import eu.m724.wtapi.object.Weather;
|
||||
|
||||
public class OWMResponseConverter {
|
||||
static Weather convert(JsonObject json) {
|
||||
Weather weather = new Weather();
|
||||
|
||||
int conditionCode = json.getAsJsonArray("weather")
|
||||
.get(0).getAsJsonObject()
|
||||
.getAsJsonPrimitive("id").getAsInt();
|
||||
|
||||
switch (conditionCode) {
|
||||
// Group 2xx: Thunderstorm
|
||||
case 200: // thunderstorm with light rain
|
||||
weather.thunderstormSeverity = Severity.LIGHT;
|
||||
weather.rainSeverity = Severity.LIGHT;
|
||||
break;
|
||||
case 201: // thunderstorm with rain
|
||||
weather.thunderstormSeverity = Severity.MODERATE;
|
||||
weather.rainSeverity = Severity.MODERATE;
|
||||
break;
|
||||
case 202: // thunderstorm with heavy rain
|
||||
weather.thunderstormSeverity = Severity.HEAVY;
|
||||
weather.rainSeverity = Severity.HEAVY;
|
||||
break;
|
||||
case 210: // light thunderstorm
|
||||
weather.thunderstormSeverity = Severity.LIGHT;
|
||||
break;
|
||||
case 211: // thunderstorm
|
||||
weather.thunderstormSeverity = Severity.MODERATE;
|
||||
break;
|
||||
case 212: // heavy thunderstorm
|
||||
weather.thunderstormSeverity = Severity.HEAVY;
|
||||
break;
|
||||
case 221: // ragged thunderstorm
|
||||
weather.thunderstormSeverity = Severity.MODERATE;
|
||||
break;
|
||||
case 230: // thunderstorm with light drizzle
|
||||
weather.thunderstormSeverity = Severity.LIGHT;
|
||||
weather.drizzleSeverity = Severity.LIGHT;
|
||||
break;
|
||||
case 231: // thunderstorm with drizzle
|
||||
weather.thunderstormSeverity = Severity.MODERATE;
|
||||
weather.drizzleSeverity = Severity.MODERATE;
|
||||
break;
|
||||
case 232: // thunderstorm with heavy drizzle
|
||||
weather.thunderstormSeverity = Severity.HEAVY;
|
||||
weather.drizzleSeverity = Severity.HEAVY;
|
||||
break;
|
||||
|
||||
// Group 3xx: Drizzle
|
||||
case 300: // light intensity drizzle
|
||||
weather.drizzleSeverity = Severity.LIGHT;
|
||||
break;
|
||||
case 301: // drizzle
|
||||
weather.drizzleSeverity = Severity.MODERATE;
|
||||
break;
|
||||
case 302: // heavy intensity drizzle
|
||||
weather.drizzleSeverity = Severity.HEAVY;
|
||||
break;
|
||||
case 310: // light intensity drizzle rain
|
||||
weather.drizzleSeverity = Severity.LIGHT;
|
||||
break;
|
||||
case 311: // drizzle rain
|
||||
weather.drizzleSeverity = Severity.MODERATE;
|
||||
break;
|
||||
case 312: // heavy intensity drizzle rain
|
||||
weather.drizzleSeverity = Severity.HEAVY;
|
||||
break;
|
||||
case 313: // shower rain and drizzle
|
||||
weather.rainSeverity = Severity.MODERATE;
|
||||
weather.drizzleSeverity = Severity.MODERATE;
|
||||
weather.shower = true;
|
||||
break;
|
||||
case 314: // heavy shower rain and drizzle
|
||||
weather.rainSeverity = Severity.HEAVY;
|
||||
weather.drizzleSeverity = Severity.HEAVY;
|
||||
weather.shower = true;
|
||||
break;
|
||||
case 321: // shower drizzle
|
||||
weather.drizzleSeverity = Severity.MODERATE;
|
||||
weather.shower = true;
|
||||
break;
|
||||
|
||||
// Group 5xx: Rain
|
||||
case 500: // light rain
|
||||
weather.rainSeverity = Severity.LIGHT;
|
||||
break;
|
||||
case 501: // moderate rain
|
||||
weather.rainSeverity = Severity.MODERATE;
|
||||
break;
|
||||
case 502: // heavy intensity rain
|
||||
weather.rainSeverity = Severity.HEAVY;
|
||||
break;
|
||||
case 503: // very heavy rain
|
||||
weather.rainSeverity = Severity.HEAVY;
|
||||
break;
|
||||
case 504: // extreme rain
|
||||
weather.rainSeverity = Severity.HEAVY;
|
||||
break;
|
||||
case 511: // freezing rain
|
||||
weather.rainSeverity = Severity.MODERATE;
|
||||
break;
|
||||
case 520: // light intensity shower rain
|
||||
weather.rainSeverity = Severity.LIGHT;
|
||||
weather.shower = true;
|
||||
break;
|
||||
case 521: // shower rain
|
||||
weather.rainSeverity = Severity.MODERATE;
|
||||
weather.shower = true;
|
||||
break;
|
||||
case 522: // heavy intensity shower rain
|
||||
weather.rainSeverity = Severity.HEAVY;
|
||||
weather.shower = true;
|
||||
break;
|
||||
case 531: // ragged shower rain
|
||||
weather.rainSeverity = Severity.MODERATE;
|
||||
weather.shower = true;
|
||||
break;
|
||||
|
||||
// Group 6xx: Snow
|
||||
case 600: // light snow
|
||||
weather.snowSeverity = Severity.LIGHT;
|
||||
break;
|
||||
case 601: // snow
|
||||
weather.snowSeverity = Severity.MODERATE;
|
||||
break;
|
||||
case 602: // heavy snow
|
||||
weather.snowSeverity = Severity.HEAVY;
|
||||
break;
|
||||
case 611: // sleet
|
||||
weather.sleetSeverity = Severity.MODERATE;
|
||||
break;
|
||||
case 612: // light shower sleet
|
||||
weather.sleetSeverity = Severity.LIGHT;
|
||||
weather.shower = true;
|
||||
break;
|
||||
case 613: // shower sleet
|
||||
weather.sleetSeverity = Severity.MODERATE;
|
||||
weather.shower = true;
|
||||
break;
|
||||
case 615: // light rain and snow
|
||||
weather.rainSeverity = Severity.LIGHT;
|
||||
weather.snowSeverity = Severity.LIGHT;
|
||||
break;
|
||||
case 616: // rain and snow
|
||||
weather.rainSeverity = Severity.MODERATE;
|
||||
weather.snowSeverity = Severity.MODERATE;
|
||||
break;
|
||||
case 620: // light shower snow
|
||||
weather.snowSeverity = Severity.LIGHT;
|
||||
weather.shower = true;
|
||||
break;
|
||||
case 621: // shower snow
|
||||
weather.snowSeverity = Severity.MODERATE;
|
||||
weather.shower = true;
|
||||
break;
|
||||
case 622: // heavy shower snow
|
||||
weather.snowSeverity = Severity.HEAVY;
|
||||
weather.shower = true;
|
||||
break;
|
||||
}
|
||||
|
||||
weather.coordinates =
|
||||
new Coordinates(
|
||||
json.getAsJsonObject("coord").getAsJsonPrimitive("lon").getAsDouble(),
|
||||
json.getAsJsonObject("coord").getAsJsonPrimitive("lat").getAsDouble()
|
||||
);
|
||||
|
||||
weather.temperature = json
|
||||
.getAsJsonObject("main")
|
||||
.getAsJsonPrimitive("temp")
|
||||
.getAsFloat();
|
||||
|
||||
weather.temperatureApparent = json
|
||||
.getAsJsonObject("main")
|
||||
.getAsJsonPrimitive("feels_like")
|
||||
.getAsFloat();
|
||||
|
||||
weather.windSpeed = json
|
||||
.getAsJsonObject("wind")
|
||||
.getAsJsonPrimitive("speed")
|
||||
.getAsFloat();
|
||||
|
||||
JsonPrimitive pri = json
|
||||
.getAsJsonObject("wind")
|
||||
.getAsJsonPrimitive("gust");
|
||||
|
||||
if (pri != null)
|
||||
weather.windSpeed = pri.getAsFloat();
|
||||
|
||||
weather.humidity = json
|
||||
.getAsJsonObject("main")
|
||||
.getAsJsonPrimitive("humidity")
|
||||
.getAsInt() / 100f;
|
||||
|
||||
weather.cloudiness = json
|
||||
.getAsJsonObject("clouds")
|
||||
.getAsJsonPrimitive("all")
|
||||
.getAsInt() / 100f;
|
||||
|
||||
weather.sunrise = json
|
||||
.getAsJsonObject("sys")
|
||||
.getAsJsonPrimitive("sunrise")
|
||||
.getAsLong();
|
||||
|
||||
weather.sunset = json
|
||||
.getAsJsonObject("sys")
|
||||
.getAsJsonPrimitive("sunrise")
|
||||
.getAsLong();
|
||||
|
||||
weather.city = json
|
||||
.getAsJsonPrimitive("name")
|
||||
.getAsString();
|
||||
|
||||
weather.description = json
|
||||
.getAsJsonArray("weather")
|
||||
.get(0).getAsJsonObject()
|
||||
.getAsJsonPrimitive("description")
|
||||
.getAsString();
|
||||
|
||||
return weather;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,113 @@
|
|||
package eu.m724.wtapi.provider.impl.openweathermap;
|
||||
|
||||
import java.net.ProxySelector;
|
||||
import java.net.URI;
|
||||
import java.net.http.HttpClient;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.net.http.HttpResponse.BodyHandlers;
|
||||
import java.util.ArrayList;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
|
||||
import eu.m724.wtapi.object.Coordinates;
|
||||
import eu.m724.wtapi.object.Weather;
|
||||
import eu.m724.wtapi.provider.WeatherProvider;
|
||||
import eu.m724.wtapi.provider.exception.AuthorizationException;
|
||||
import eu.m724.wtapi.provider.exception.ProviderException;
|
||||
import eu.m724.wtapi.provider.exception.QuotaExceededException;
|
||||
import eu.m724.wtapi.provider.exception.ServerProviderException;
|
||||
|
||||
public class OpenWeatherMapProvider extends WeatherProvider {
|
||||
private String requestUrlFormat;
|
||||
private String apiKey;
|
||||
|
||||
public OpenWeatherMapProvider(String apiKey) {
|
||||
this.apiKey = apiKey;
|
||||
this.requestUrlFormat = "https://api.openweathermap.org/data/2.5/weather?lat=%f&lon=%f&appid=" + apiKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() throws ProviderException {
|
||||
CompletableFuture<Weather> weatherFuture =
|
||||
getWeather(new Coordinates(0, 0));
|
||||
|
||||
try {
|
||||
weatherFuture.get();
|
||||
} catch (InterruptedException e) {
|
||||
throw new ProviderException("unexpected interruptedexception");
|
||||
} catch (ExecutionException e) {
|
||||
throw (ProviderException) e.getSuppressed()[0]; // TODO
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Weather> getWeather(Coordinates coordinates) {
|
||||
String url = String.format(
|
||||
requestUrlFormat, coordinates.latitude, coordinates.longitude);
|
||||
|
||||
HttpRequest request = HttpRequest.newBuilder()
|
||||
.uri(URI.create(url))
|
||||
.build();
|
||||
|
||||
CompletableFuture<HttpResponse<String>> responseFuture =
|
||||
HttpClient.newBuilder()
|
||||
.proxy(ProxySelector.getDefault()).build()
|
||||
.sendAsync(request, BodyHandlers.ofString());
|
||||
|
||||
CompletableFuture<Weather> weatherFuture =
|
||||
responseFuture.thenApply((response) -> {
|
||||
int code = response.statusCode();
|
||||
|
||||
if (code == 401)
|
||||
throw new AuthorizationException("invalid api key");
|
||||
if (code == 429)
|
||||
throw new QuotaExceededException("ratelimited", 1000);
|
||||
if (code != 200)
|
||||
throw new ServerProviderException(String.format("status code %d", code));
|
||||
|
||||
JsonObject jsonResponse =
|
||||
JsonParser.parseString(response.body())
|
||||
.getAsJsonObject();
|
||||
|
||||
Weather weather = OWMResponseConverter.convert(jsonResponse);
|
||||
|
||||
return weather;
|
||||
});
|
||||
|
||||
return weatherFuture;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Weather[]> getWeatherBulk(Coordinates[] coordinateses) {
|
||||
ArrayList<CompletableFuture<Weather>> weatherFutures = new ArrayList<>();
|
||||
|
||||
for (Coordinates coordinates : coordinateses) {
|
||||
weatherFutures.add(getWeather(coordinates));
|
||||
}
|
||||
|
||||
CompletableFuture<Weather[]> weathersFuture =
|
||||
CompletableFuture.allOf(
|
||||
weatherFutures.toArray(new CompletableFuture[0]))
|
||||
.thenApply(v ->
|
||||
weatherFutures.stream()
|
||||
.map(CompletableFuture::join)
|
||||
.toArray(Weather[]::new));
|
||||
|
||||
return weathersFuture;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getQuotaHourly() {
|
||||
return 1370;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBulkLimit() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
}
|
20
src/test/java/eu/m724/wtapi/CoordinateTest.java
Normal file
20
src/test/java/eu/m724/wtapi/CoordinateTest.java
Normal file
|
@ -0,0 +1,20 @@
|
|||
package eu.m724.wtapi;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import eu.m724.wtapi.object.Coordinates;
|
||||
|
||||
public class CoordinateTest {
|
||||
@Test
|
||||
public void testCoordinates() {
|
||||
Coordinates coordinates = new Coordinates(-91.1, 180.01);
|
||||
|
||||
System.out.println(coordinates.longitude);
|
||||
|
||||
assert coordinates.latitude == 88.9;
|
||||
assert coordinates.longitude == -179.99;
|
||||
|
||||
coordinates = new Coordinates(-91.1, 180.1);
|
||||
assert coordinates.longitude != -179.9; // TODO
|
||||
}
|
||||
}
|
47
src/test/java/eu/m724/wtapi/TestOWM.java
Normal file
47
src/test/java/eu/m724/wtapi/TestOWM.java
Normal file
|
@ -0,0 +1,47 @@
|
|||
package eu.m724.wtapi;
|
||||
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import eu.m724.wtapi.object.Coordinates;
|
||||
import eu.m724.wtapi.object.Weather;
|
||||
import eu.m724.wtapi.provider.WeatherProvider;
|
||||
import eu.m724.wtapi.provider.impl.openweathermap.OpenWeatherMapProvider;
|
||||
|
||||
public class TestOWM {
|
||||
@Test
|
||||
public void openWeatherMapTest() throws InterruptedException, ExecutionException {
|
||||
String apiKey = "f3198d2a4ae3076e0aa47c821a253447";
|
||||
|
||||
WeatherProvider provider = new OpenWeatherMapProvider(apiKey);
|
||||
|
||||
provider.init();
|
||||
|
||||
CompletableFuture<Weather> weatherFuture =
|
||||
provider.getWeather(new Coordinates(53.2232, -4.2008));
|
||||
|
||||
Weather weather = weatherFuture.get();
|
||||
assertNotNull(weather);
|
||||
|
||||
System.out.printf("current weather in %s: %s\n", weather.city, weather.description);
|
||||
|
||||
CompletableFuture<Weather[]> weatherBulkFuture =
|
||||
provider.getWeatherBulk(
|
||||
new Coordinates[] {
|
||||
new Coordinates(54.6606714, -3.3827237),
|
||||
new Coordinates(47.5705952, -53.5556464),
|
||||
new Coordinates(34.2073721, -84.1402857),
|
||||
});
|
||||
|
||||
Weather[] weathers = weatherBulkFuture.get();
|
||||
assert weathers.length == 3;
|
||||
|
||||
for (Weather weather1 : weathers) {
|
||||
System.out.printf("current weather in %s: %s\n", weather1.city, weather1.description);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue