This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git


The following commit(s) were added to refs/heads/main by this push:
     new 64f10b7c556d CAMEL-26131: camel-weather - the geolocation of a query 
is not kept on the configuration, so the CamelWeatherLocation header is queried 
(#28767)
64f10b7c556d is described below

commit 64f10b7c556d51c274d380bd65720264389b8377
Author: Vignesh Nayak Manel <[email protected]>
AuthorDate: Sun Nov 1 19:03:06 2026 +0530

    CAMEL-26131: camel-weather - the geolocation of a query is not kept on the 
configuration, so the CamelWeatherLocation header is queried (#28767)
    
    Co-Authored-By: Claude Opus 5.5 <[email protected]>
---
 .../camel/component/weather/WeatherProducer.java   |   2 +-
 .../camel/component/weather/WeatherQuery.java      |  34 +++---
 .../weather/WeatherProducerLocationHeaderTest.java | 123 +++++++++++++++++++++
 .../ROOT/pages/camel-4x-upgrade-guide-4_24.adoc    |   8 ++
 4 files changed, 149 insertions(+), 18 deletions(-)

diff --git 
a/components/camel-weather/src/main/java/org/apache/camel/component/weather/WeatherProducer.java
 
b/components/camel-weather/src/main/java/org/apache/camel/component/weather/WeatherProducer.java
index fb18d562aeef..8c6d7ce9293f 100644
--- 
a/components/camel-weather/src/main/java/org/apache/camel/component/weather/WeatherProducer.java
+++ 
b/components/camel-weather/src/main/java/org/apache/camel/component/weather/WeatherProducer.java
@@ -61,7 +61,7 @@ public class WeatherProducer extends DefaultProducer {
                         if (HttpStatus.SC_OK != response.getCode()) {
                             throw new IllegalStateException(
                                     "Got the invalid http status value '" + 
response.getCode()
-                                                            + "' as the result 
of the query '" + query + "'");
+                                                            + "' as the result 
of the query '" + uri + "'");
                         }
                         String weather = 
EntityUtils.toString(response.getEntity(), "UTF-8");
                         LOG.debug("Got back the Weather information {}", 
weather);
diff --git 
a/components/camel-weather/src/main/java/org/apache/camel/component/weather/WeatherQuery.java
 
b/components/camel-weather/src/main/java/org/apache/camel/component/weather/WeatherQuery.java
index 4550af8c6776..d467f79da55f 100644
--- 
a/components/camel-weather/src/main/java/org/apache/camel/component/weather/WeatherQuery.java
+++ 
b/components/camel-weather/src/main/java/org/apache/camel/component/weather/WeatherQuery.java
@@ -37,13 +37,17 @@ public class WeatherQuery {
 
     public String getQuery(String location) throws Exception {
         String answer = "http://api.openweathermap.org/data/2.5/";;
-        if (weatherConfiguration.getLat() != null && 
weatherConfiguration.getLon() != null
+        // the lat and lon of the current geolocation are for this query only: 
the configuration is shared by all the
+        // queries of the endpoint, and a later query can be for another 
location
+        String lat = weatherConfiguration.getLat();
+        String lon = weatherConfiguration.getLon();
+        if (lat != null && lon != null
                 && weatherConfiguration.getRightLon() == null && 
weatherConfiguration.getTopLat() == null) {
-            location = createLatLonQueryString();
-        } else if (weatherConfiguration.getLat() != null && 
weatherConfiguration.getLon() != null
+            location = createLatLonQueryString(lat, lon);
+        } else if (lat != null && lon != null
                 && weatherConfiguration.getRightLon() != null && 
weatherConfiguration.getTopLat() != null) {
-            location = "bbox=" + weatherConfiguration.getLon() + ","
-                       + weatherConfiguration.getLat() + ","
+            location = "bbox=" + lon + ","
+                       + lat + ","
                        + weatherConfiguration.getRightLon() + ","
                        + weatherConfiguration.getTopLat() + ","
                        + weatherConfiguration.getZoom() + "&cluster=yes";
@@ -53,9 +57,9 @@ public class WeatherQuery {
             location = "id=" + weatherConfiguration.getIds();
         } else if (isEmpty(location) || "current".equals(location)) {
             GeoLocation geoLocation = getCurrentGeoLocation();
-            weatherConfiguration.setLat(geoLocation.getLatitude());
-            weatherConfiguration.setLon(geoLocation.getLongitude());
-            location = createLatLonQueryString();
+            lat = geoLocation.getLatitude();
+            lon = geoLocation.getLongitude();
+            location = createLatLonQueryString(lat, lon);
         } else {
             // assuming the location is a town or country
             location = "q=" + location;
@@ -63,7 +67,7 @@ public class WeatherQuery {
 
         location = location + "&lang=" + weatherConfiguration.getLanguage();
 
-        String context = createContext();
+        String context = createContext(lat, lon);
         answer += context + location;
 
         if (!isEmpty(weatherConfiguration.getPeriod())) {
@@ -89,7 +93,7 @@ public class WeatherQuery {
         return answer;
     }
 
-    private String createContext() {
+    private String createContext(String lat, String lon) {
         String answer;
         if (isBoxedQuery()) {
             if (weatherConfiguration.getWeatherApi() == WeatherApi.Station) {
@@ -97,7 +101,7 @@ public class WeatherQuery {
             } else {
                 answer = "box/city?";
             }
-        } else if (isGeoLocation() && weatherConfiguration.getCnt() != null) {
+        } else if (lat != null && lon != null && weatherConfiguration.getCnt() 
!= null) {
             if (weatherConfiguration.getWeatherApi() == WeatherApi.Station) {
                 answer = "station/find?";
             } else {
@@ -131,12 +135,8 @@ public class WeatherQuery {
         return answer;
     }
 
-    private boolean isGeoLocation() {
-        return weatherConfiguration.getLat() != null && 
weatherConfiguration.getLon() != null;
-    }
-
-    private String createLatLonQueryString() {
-        return "lat=" + weatherConfiguration.getLat() + "&lon=" + 
weatherConfiguration.getLon();
+    private static String createLatLonQueryString(String lat, String lon) {
+        return "lat=" + lat + "&lon=" + lon;
     }
 
     private boolean isBoxedQuery() {
diff --git 
a/components/camel-weather/src/test/java/org/apache/camel/component/weather/WeatherProducerLocationHeaderTest.java
 
b/components/camel-weather/src/test/java/org/apache/camel/component/weather/WeatherProducerLocationHeaderTest.java
new file mode 100644
index 000000000000..bc1a1d2c6d1e
--- /dev/null
+++ 
b/components/camel-weather/src/test/java/org/apache/camel/component/weather/WeatherProducerLocationHeaderTest.java
@@ -0,0 +1,123 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.weather;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.camel.BindToRegistry;
+import org.apache.camel.CamelExecutionException;
+import org.apache.camel.component.weather.geolocation.GeoLocation;
+import org.apache.camel.component.weather.geolocation.GeoLocationProvider;
+import org.apache.camel.test.junit6.CamelTestSupport;
+import org.apache.hc.client5.http.classic.methods.HttpGet;
+import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
+import org.apache.hc.core5.http.HttpStatus;
+import org.apache.hc.core5.http.io.HttpClientResponseHandler;
+import org.apache.hc.core5.http.io.entity.StringEntity;
+import org.apache.hc.core5.http.message.BasicClassicHttpResponse;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertInstanceOf;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+/**
+ * The geolocation of a query for the current location is not kept on the 
shared configuration of the endpoint, so a
+ * later CamelWeatherLocation header is the location that is queried.
+ */
+class WeatherProducerLocationHeaderTest extends CamelTestSupport {
+
+    private static final String CURRENT = "lat=2&lon=1";
+
+    private final List<String> requested = new ArrayList<>();
+    private int status = HttpStatus.SC_OK;
+
+    @BindToRegistry("geo")
+    private final GeoLocationProvider geoLocationProvider = () -> new 
GeoLocation("1", "2");
+
+    @BindToRegistry("http")
+    private final CloseableHttpClient httpClient = createHttpClient();
+
+    @Test
+    void headerLocationIsQueriedOnAnEndpointWithoutLocation() {
+        String uri = 
"weather:foo?appid=x&geoLocationProvider=#geo&httpClient=#http";
+
+        template.requestBodyAndHeader(uri, null, 
WeatherConstants.WEATHER_LOCATION, "Paris");
+        template.requestBody(uri, (Object) null);
+
+        assertEquals(List.of("q=Paris", CURRENT), requestedLocations());
+        assertNoLatLonOnTheConfiguration(uri);
+    }
+
+    @Test
+    void currentLocationIsNotUsedByTheNextQuery() {
+        String uri = 
"weather:foo?appid=x&location=Madrid&geoLocationProvider=#geo&httpClient=#http";
+
+        template.requestBodyAndHeader(uri, null, 
WeatherConstants.WEATHER_LOCATION, "current");
+        template.requestBodyAndHeader(uri, null, 
WeatherConstants.WEATHER_LOCATION, "Paris");
+        template.requestBody(uri, (Object) null);
+
+        assertEquals(List.of(CURRENT, "q=Paris", "q=Madrid"), 
requestedLocations());
+        assertNoLatLonOnTheConfiguration(uri);
+    }
+
+    @Test
+    void errorNamesTheUriThatWasCalled() {
+        String uri = 
"weather:foo?appid=x&location=Madrid&geoLocationProvider=#geo&httpClient=#http";
+        status = HttpStatus.SC_INTERNAL_SERVER_ERROR;
+
+        CamelExecutionException e = assertThrows(CamelExecutionException.class,
+                () -> template.requestBodyAndHeader(uri, null, 
WeatherConstants.WEATHER_LOCATION, "Paris"));
+
+        IllegalStateException cause = 
assertInstanceOf(IllegalStateException.class, e.getCause());
+        assertTrue(cause.getMessage().contains("?q=Paris&"), 
cause.getMessage());
+    }
+
+    private List<String> requestedLocations() {
+        // the location part of each requested URI, such as q=Paris or 
lat=2&lon=1
+        return requested.stream().map(u -> u.substring(u.indexOf('?') + 1, 
u.indexOf("&lang="))).toList();
+    }
+
+    private void assertNoLatLonOnTheConfiguration(String uri) {
+        WeatherConfiguration configuration = context.getEndpoint(uri, 
WeatherEndpoint.class).getConfiguration();
+        assertNull(configuration.getLat());
+        assertNull(configuration.getLon());
+    }
+
+    private CloseableHttpClient createHttpClient() {
+        try {
+            CloseableHttpClient client = mock(CloseableHttpClient.class);
+            when(client.execute(any(HttpGet.class), 
any(HttpClientResponseHandler.class))).thenAnswer(invocation -> {
+                HttpGet request = invocation.getArgument(0);
+                requested.add(request.getRequestUri());
+                BasicClassicHttpResponse response = new 
BasicClassicHttpResponse(status);
+                response.setEntity(new StringEntity("{}"));
+                HttpClientResponseHandler<?> handler = 
invocation.getArgument(1);
+                return handler.handleResponse(response);
+            });
+            return client;
+        } catch (Exception e) {
+            throw new IllegalStateException(e);
+        }
+    }
+}
diff --git 
a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc 
b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc
index 674fffc04fb1..55384f7e25f2 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc
@@ -587,6 +587,14 @@ If you replaced these dependencies to use another HTTP 
client implementation, na
 `software.amazon.awssdk.http.service.impl` (synchronous clients) or 
`software.amazon.awssdk.http.async.service.impl`
 (asynchronous clients): Camel then leaves the choice of the HTTP client to the 
AWS SDK.
 
+=== camel-weather - the CamelWeatherLocation header is the location that is 
queried
+
+The latitude and longitude of the current geolocation (a location of 
`current`, or no location) are no longer written
+onto the configuration of the endpoint. Before, they were, so every later 
query on that endpoint, including one with a
+`CamelWeatherLocation` header such as `Paris`, requested the weather of the 
current geolocation. An endpoint without a
+`location` already did the geolocation when its producer was created, so its 
`CamelWeatherLocation` header was never
+used. The `lat` and `lon` options of an endpoint are still used instead of the 
location.
+
 === camel-gson, camel-jsonb - the unmarshal type header needs 
allowUnmarshallType
 
 The Gson and JSON-B data formats now use the `CamelGsonUnmarshalType` and 
`CamelJsonbUnmarshallType` headers to choose

Reply via email to