Skip to content

Commit 23462b6

Browse files
dbadiaProminence
andauthored
Add onecall API 3 support to allow access to daily summary (#58)
* bump nexux-staging-maven-plugin version to resolve the following maven build error: [INFO] Scanning for projects... [WARNING] ClassRealm[extension>org.sonatype.plugins:nexus-staging-maven-plugin:1.6.9, parent: jdk.internal.loader.ClassLoaders$AppClassLoader@1d44bcfa] com.google.inject.CreationException: Unable to create injector, see the following errors: 1) No implementation for com.fasterxml.jackson.databind.ObjectMapper annotated with interface org.eclipse.sisu.inject.TypeArguments$Implicit was bound. Did you mean? com.fasterxml.jackson.databind.ObjectMapper annotated with @com.google.inject.name.Named(value="org.sonatype.sisu.siesta.jackson.ObjectMapperProvider") bound at ClassRealm[extension>org.sonatype.plugins:nexus-staging-maven-plugin:1.6.9, parent: jdk.internal.loader.ClassLoaders$AppClassLoader@1d44bcfa] (via modules: org.eclipse.sisu.wire.WireModule -> org.eclipse.sisu.plexus.PlexusBindingModule) com.fasterxml.jackson.databind.ObjectMapper bound at org.eclipse.sisu.wire.LocatorWiring at org.eclipse.sisu.wire.LocatorWiring 1 error at com.google.inject.internal.Errors.throwCreationExceptionIfErrorsExist (Errors.java:543) at com.google.inject.internal.InternalInjectorCreator.initializeStatically (InternalInjectorCreator.java:159) at com.google.inject.internal.InternalInjectorCreator.build (InternalInjectorCreator.java:106) at com.google.inject.Guice.createInjector (Guice.java:87) at com.google.inject.Guice.createInjector (Guice.java:69) at com.google.inject.Guice.createInjector (Guice.java:59) at org.codehaus.plexus.DefaultPlexusContainer.addPlexusInjector (DefaultPlexusContainer.java:481) at org.codehaus.plexus.DefaultPlexusContainer.discoverComponents (DefaultPlexusContainer.java:460) at org.apache.maven.plugin.internal.DefaultMavenPluginManager.discoverPluginComponents (DefaultMavenPluginManager.java:436) at org.apache.maven.plugin.internal.DefaultMavenPluginManager.setupExtensionsRealm (DefaultMavenPluginManager.java:879) at org.apache.maven.project.DefaultProjectBuildingHelper.createProjectRealm (DefaultProjectBuildingHelper.java:196) at org.apache.maven.project.DefaultModelBuildingListener.buildExtensionsAssembled (DefaultModelBuildingListener.java:100) at org.apache.maven.model.building.ModelBuildingEventCatapult$1.fire (ModelBuildingEventCatapult.java:44) at org.apache.maven.model.building.DefaultModelBuilder.fireEvent (DefaultModelBuilder.java:1359) at org.apache.maven.model.building.DefaultModelBuilder.build (DefaultModelBuilder.java:452) at org.apache.maven.model.building.DefaultModelBuilder.build (DefaultModelBuilder.java:432) at org.apache.maven.project.DefaultProjectBuilder.build (DefaultProjectBuilder.java:583) at org.apache.maven.project.DefaultProjectBuilder.build (DefaultProjectBuilder.java:372) at org.apache.maven.graph.DefaultGraphBuilder.collectProjects (DefaultGraphBuilder.java:414) at org.apache.maven.graph.DefaultGraphBuilder.getProjectsForMavenReactor (DefaultGraphBuilder.java:405) at org.apache.maven.graph.DefaultGraphBuilder.build (DefaultGraphBuilder.java:82) at org.apache.maven.DefaultMaven.buildGraph (DefaultMaven.java:507) at org.apache.maven.DefaultMaven.doExecute (DefaultMaven.java:219) * add onecall 3 API * Changed subscription plan for oneCall3 requester, deprecated oneCall. * Fixed query parameters encoding. --------- Co-authored-by: Prominence <alexey.zinchenko@protonmail.com>
1 parent 7f60964 commit 23462b6

File tree

8 files changed

+215
-8
lines changed

8 files changed

+215
-8
lines changed

pom.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
<groupId>com.github.prominence</groupId>
88
<artifactId>openweathermap-api</artifactId>
9-
<version>2.3.0</version>
9+
<version>2.4.0</version>
1010
<packaging>jar</packaging>
1111

1212
<name>Java OpenWeatherMap API</name>
@@ -80,7 +80,7 @@
8080
<plugin>
8181
<groupId>org.sonatype.plugins</groupId>
8282
<artifactId>nexus-staging-maven-plugin</artifactId>
83-
<version>1.6.9</version>
83+
<version>1.6.13</version>
8484
<extensions>true</extensions>
8585
<configuration>
8686
<serverId>ossrh</serverId>

src/main/java/com/github/prominence/openweathermap/api/OpenWeatherMapClient.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import com.github.prominence.openweathermap.api.request.weather.CurrentWeatherRequester;
3232

3333
import static com.github.prominence.openweathermap.api.enums.SubscriptionPlan.ALL;
34+
import static com.github.prominence.openweathermap.api.enums.SubscriptionPlan.SPECIAL;
3435

3536
/**
3637
* The main public API client to communicate with OpenWeatherMap services.
@@ -80,10 +81,29 @@ public FiveDayThreeHourStepForecastRequester forecast5Day3HourStep() {
8081
* @return requester for retrieving one call weather information.
8182
*/
8283
@SubscriptionAvailability(plans = ALL)
84+
@Deprecated
8385
public OneCallWeatherRequester oneCall() {
8486
return new OneCallWeatherRequester(new RequestSettings(apiKey, timeoutSettings));
8587
}
8688

89+
/**
90+
* One Call 3 API <a href="https://openweathermap.org/api/one-call-3">API</a>.
91+
* Includes a weather summary statement in addition to the information provided by {@link #oneCall()}
92+
*
93+
* Please note, that One Call API 3.0 is included in the "One Call by Call" subscription only.
94+
* This separate subscription includes 1,000 calls/day for free and allows you to pay only for the number of API calls made to this product.
95+
* Please note, that you do not need to subscribe to any other OpenWeather subscription plans to get access to the One Call API 3.0.
96+
* Please find more details on the pricing page and FAQ or ask Ulla, OpenWeather AI assistant.
97+
*
98+
* @return requester for retrieving one call weather information for the OneCall 3 API.
99+
*/
100+
@SubscriptionAvailability(plans = SPECIAL)
101+
public OneCallWeatherRequester oneCall3() {
102+
RequestSettings requestSettings = new RequestSettings(apiKey, timeoutSettings);
103+
requestSettings.setUseApi3();
104+
return new OneCallWeatherRequester(requestSettings);
105+
}
106+
87107
/**
88108
* Air Pollution <a href="https://openweathermap.org/api/air-pollution">API</a>.
89109
* Air Pollution API provides current, forecast and historical air pollution data for any coordinates on the globe.

src/main/java/com/github/prominence/openweathermap/api/enums/SubscriptionPlan.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,4 +56,9 @@ public enum SubscriptionPlan {
5656
* All existing subscription plans.
5757
*/
5858
ALL,
59+
60+
/**
61+
* Special subscription cases.
62+
*/
63+
SPECIAL,
5964
}

src/main/java/com/github/prominence/openweathermap/api/mapper/OneCallWeatherResponseMapper.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,7 @@ private List<Daily> parseDailyList(JsonNode dailyListNode) {
213213
daily.setMoonPhase(new MoonPhase(moonPhaseNode.asDouble()));
214214
}
215215

216+
daily.setSummary(parseSummary(dailyNode));
216217
daily.setWeatherState(parseWeatherState(dailyNode.get("weather").get(0)));
217218
daily.setTemperature(parseDailyTemperature(dailyNode));
218219
daily.setAtmosphericPressure(parsePressure(dailyNode));
@@ -439,4 +440,12 @@ private Clouds parseClouds(JsonNode rootNode) {
439440

440441
return null;
441442
}
443+
444+
private String parseSummary(JsonNode dailyNode) {
445+
final JsonNode summaryNode = dailyNode.get("summary");
446+
if(summaryNode != null) {
447+
return summaryNode.asText();
448+
}
449+
return null;
450+
}
442451
}

src/main/java/com/github/prominence/openweathermap/api/model/onecall/current/Daily.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ public class Daily {
4343
private LocalDateTime moonsetTime;
4444
private MoonPhase moonPhase;
4545

46+
private String summary;
4647
private WeatherState weatherState;
4748
private DailyTemperature temperature;
4849
private AtmosphericPressure atmosphericPressure;
@@ -162,6 +163,24 @@ public void setMoonPhase(MoonPhase moonPhase) {
162163
this.moonPhase = moonPhase;
163164
}
164165

166+
/**
167+
* Gets summary.
168+
*
169+
* @return the summary
170+
*/
171+
public String getSummary() {
172+
return summary;
173+
}
174+
175+
/**
176+
* Sets summary.
177+
*
178+
* @param summary the summary
179+
*/
180+
public void setSummary(String summary) {
181+
this.summary = summary;
182+
}
183+
165184
/**
166185
* Gets weather state.
167186
*
@@ -435,4 +454,5 @@ public String toString() {
435454
}
436455
return stringBuilder.toString();
437456
}
457+
438458
}

src/main/java/com/github/prominence/openweathermap/api/request/RequestSettings.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ public class RequestSettings {
4545

4646
private Language language = Language.ENGLISH;
4747
private UnitSystem unitSystem = UnitSystem.STANDARD;
48+
private boolean useApi3 = false;
4849

4950
public RequestSettings(String apiKey, TimeoutSettings timeoutSettings) {
5051
this.putRequestParameter(API_KEY_PARAM_NAME, apiKey);
@@ -94,6 +95,14 @@ public void appendToURL(String appendix) {
9495
urlAppenderBuilder.append(appendix);
9596
}
9697

98+
public void setUseApi3() {
99+
this.useApi3 = true;
100+
}
101+
102+
public boolean getUseApi3() {
103+
return this.useApi3;
104+
}
105+
97106
public StringBuilder getUrlAppender() {
98107
return urlAppenderBuilder;
99108
}

src/main/java/com/github/prominence/openweathermap/api/utils/RequestUtils.java

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,11 @@
2929
import org.slf4j.Logger;
3030
import org.slf4j.LoggerFactory;
3131

32-
import java.io.BufferedReader;
33-
import java.io.IOException;
34-
import java.io.InputStream;
35-
import java.io.InputStreamReader;
32+
import java.io.*;
3633
import java.net.HttpURLConnection;
3734
import java.net.MalformedURLException;
3835
import java.net.URL;
36+
import java.net.URLEncoder;
3937
import java.nio.charset.StandardCharsets;
4038
import java.util.stream.Collectors;
4139

@@ -44,7 +42,8 @@
4442
*/
4543
public final class RequestUtils {
4644

47-
private static final String OWM_URL_BASE = "http://api.openweathermap.org/data/2.5/";
45+
private static final String OWM_URL_BASE = "https://api.openweathermap.org/data/2.5/";
46+
private static final String OWM_URL_BASE_3_0 = "https://api.openweathermap.org/data/3.0/";
4847

4948
private static final Logger logger = LoggerFactory.getLogger(RequestUtils.class);
5049

@@ -53,10 +52,19 @@ private RequestUtils() {
5352

5453
public static String getResponse(RequestSettings requestSettings) {
5554
StringBuilder requestUrlBuilder = new StringBuilder(OWM_URL_BASE);
55+
if(requestSettings.getUseApi3()) {
56+
requestUrlBuilder = new StringBuilder(OWM_URL_BASE_3_0);
57+
}
5658
requestUrlBuilder.append(requestSettings.getUrlAppender());
5759
requestUrlBuilder.append('?');
5860
String parameters = requestSettings.getRequestParameters().entrySet().stream()
59-
.map(entry -> entry.getKey() + "=" + entry.getValue())
61+
.map(entry -> {
62+
try {
63+
return entry.getKey() + "=" + URLEncoder.encode(entry.getValue(), "UTF-8");
64+
} catch (UnsupportedEncodingException e) {
65+
throw new RuntimeException(e);
66+
}
67+
})
6068
.collect(Collectors.joining("&"));
6169
requestUrlBuilder.append(parameters);
6270

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
/*
2+
* Copyright (c) 2021 Alexey Zinchenko
3+
*
4+
* Permission is hereby granted, free of charge, to any person obtaining a copy
5+
* of this software and associated documentation files (the "Software"), to deal
6+
* in the Software without restriction, including without limitation the rights
7+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+
* copies of the Software, and to permit persons to whom the Software is
9+
* furnished to do so, subject to the following conditions:
10+
*
11+
* The above copyright notice and this permission notice shall be included in all
12+
* copies or substantial portions of the Software.
13+
*
14+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20+
* SOFTWARE.
21+
*/
22+
23+
package com.github.prominence.openweathermap.api.request.onecall.current;
24+
25+
import com.github.prominence.openweathermap.api.ApiTest;
26+
import com.github.prominence.openweathermap.api.OpenWeatherMapClient;
27+
import com.github.prominence.openweathermap.api.enums.Language;
28+
import com.github.prominence.openweathermap.api.enums.OneCallResultOptions;
29+
import com.github.prominence.openweathermap.api.enums.UnitSystem;
30+
import com.github.prominence.openweathermap.api.exception.InvalidAuthTokenException;
31+
import com.github.prominence.openweathermap.api.exception.NoDataFoundException;
32+
import com.github.prominence.openweathermap.api.model.Coordinate;
33+
import com.github.prominence.openweathermap.api.model.onecall.current.CurrentWeatherData;
34+
import org.junit.jupiter.api.Test;
35+
36+
import java.util.concurrent.CompletableFuture;
37+
import java.util.concurrent.ExecutionException;
38+
39+
import static org.junit.jupiter.api.Assertions.*;
40+
41+
public class CurrentWeatherOneCallApi3IntegrationTest extends ApiTest {
42+
@Test
43+
public void whenRetrieveCurrentOneCallResponseAsJava_thenOk() {
44+
final CurrentWeatherData currentWeatherData = getClient()
45+
.oneCall3()
46+
.current()
47+
.byCoordinate(Coordinate.of(53.54, 27.34))
48+
.language(Language.ENGLISH)
49+
.unitSystem(UnitSystem.METRIC)
50+
.retrieve()
51+
.asJava();
52+
53+
assertNotNull(currentWeatherData);
54+
assertNotNull(currentWeatherData.getDailyList().get(0).getSummary());
55+
}
56+
57+
@Test
58+
public void whenRetrieveCurrentOneCallResponseAsJSON_thenOk() {
59+
final String responseJson = getClient()
60+
.oneCall3()
61+
.current()
62+
.byCoordinate(Coordinate.of(53.54, 27.34))
63+
.language(Language.ENGLISH)
64+
.unitSystem(UnitSystem.METRIC)
65+
.retrieve()
66+
.asJSON();
67+
68+
assertNotNull(responseJson);
69+
assertNotEquals("", responseJson);
70+
}
71+
72+
@Test
73+
public void whenRetrieveCurrentOneCallResponseWithExclusionAsJava_thenOk() {
74+
final CurrentWeatherData currentWeatherData = getClient()
75+
.oneCall3()
76+
.current()
77+
.byCoordinate(Coordinate.of(53.54, 27.34))
78+
.language(Language.ENGLISH)
79+
.unitSystem(UnitSystem.METRIC)
80+
.exclude(OneCallResultOptions.CURRENT, OneCallResultOptions.MINUTELY)
81+
.retrieve()
82+
.asJava();
83+
84+
assertNotNull(currentWeatherData);
85+
assertNull(currentWeatherData.getCurrent());
86+
assertNull(currentWeatherData.getMinutelyList());
87+
assertNotNull(currentWeatherData.getDailyList().get(0).getSummary());
88+
}
89+
90+
@Test
91+
public void whenRetrieveCurrentOneCallAsyncResponseAsJava_thenOk() throws ExecutionException, InterruptedException {
92+
final CompletableFuture<CurrentWeatherData> currentWeatherDataFuture = getClient()
93+
.oneCall3()
94+
.current()
95+
.byCoordinate(Coordinate.of(53.54, 27.34))
96+
.language(Language.ENGLISH)
97+
.unitSystem(UnitSystem.METRIC)
98+
.retrieveAsync()
99+
.asJava();
100+
101+
assertNotNull(currentWeatherDataFuture);
102+
assertNotNull(currentWeatherDataFuture.get());
103+
assertNotNull(currentWeatherDataFuture.get().getDailyList().get(0).getSummary());
104+
}
105+
106+
@Test
107+
public void whenRetrieveCurrentOneCallAsyncResponseAsJSON_thenOk() throws ExecutionException, InterruptedException {
108+
final CompletableFuture<String> responseJsonFuture = getClient()
109+
.oneCall3()
110+
.current()
111+
.byCoordinate(Coordinate.of(53.54, 27.34))
112+
.language(Language.ENGLISH)
113+
.unitSystem(UnitSystem.METRIC)
114+
.retrieveAsync()
115+
.asJSON();
116+
117+
assertNotNull(responseJsonFuture);
118+
final String responseJson = responseJsonFuture.get();
119+
assertNotNull(responseJson);
120+
}
121+
122+
@Test
123+
public void whenRequestOnecallWithInvalidApiKey_thenThrowAnException() {
124+
OpenWeatherMapClient client = new OpenWeatherMapClient("invalidKey");
125+
assertThrows(InvalidAuthTokenException.class, () ->
126+
client
127+
.oneCall3()
128+
.current()
129+
.byCoordinate(Coordinate.of(53.54, 27.34))
130+
.language(Language.ENGLISH)
131+
.unitSystem(UnitSystem.METRIC)
132+
.retrieve()
133+
.asJSON()
134+
);
135+
}
136+
}

0 commit comments

Comments
 (0)