Blame | Last modification | View Log | RSS feed
package com.spice.profitmandi.service;import com.fasterxml.jackson.databind.JsonNode;import com.fasterxml.jackson.databind.ObjectMapper;import org.apache.logging.log4j.LogManager;import org.apache.logging.log4j.Logger;import org.springframework.cache.annotation.Cacheable;import org.springframework.stereotype.Service;import java.io.BufferedReader;import java.io.InputStreamReader;import java.net.HttpURLConnection;import java.net.URL;import java.net.URLEncoder;import java.nio.charset.StandardCharsets;@Servicepublic class GeocodingService {private static final Logger LOGGER = LogManager.getLogger(GeocodingService.class);private static final String GOOGLE_GEOCODE_URL = "https://maps.googleapis.com/maps/api/geocode/json";private static final String API_KEY = "AIzaSyAckO0y4Z6WhBOuMjNjioWLSYZDhGEvGBc";private final ObjectMapper objectMapper = new ObjectMapper();/*** Build a clean geocoding query from address parts.* Only includes: line1, city, state, pincode — no phone, no landmark prefix, no shop numbers.*/public static String buildGeoAddress(String line1, String city, String state, String pinCode) {StringBuilder sb = new StringBuilder();if (city != null && !city.isEmpty()) sb.append(city).append(", ");if (state != null && !state.isEmpty()) sb.append(state).append(", ");if (pinCode != null && !pinCode.isEmpty()) sb.append(pinCode).append(", ");sb.append("India");return sb.toString().trim();}/*** Geocode an address string to [latitude, longitude].* Cached in Redis forever to avoid repeated API calls.* Returns null if geocoding fails.*/@Cacheable(value = "partnerGeocode", key = "#address", cacheManager = "redisEternalCacheManager")public double[] geocodeAddress(String address) {if (address == null || address.trim().isEmpty()) {return null;}try {String cleanAddress = sanitizeForGeocoding(address);String encodedAddress = URLEncoder.encode(cleanAddress, StandardCharsets.UTF_8.toString());String urlStr = GOOGLE_GEOCODE_URL + "?address=" + encodedAddress+ "&key=" + API_KEY + "&components=country:IN";URL url = new URL(urlStr);HttpURLConnection conn = (HttpURLConnection) url.openConnection();conn.setRequestMethod("GET");conn.setConnectTimeout(5000);conn.setReadTimeout(5000);int responseCode = conn.getResponseCode();if (responseCode != 200) {LOGGER.warn("Geocoding HTTP error for '{}': {}", address, responseCode);return null;}BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));StringBuilder sb = new StringBuilder();String line;while ((line = reader.readLine()) != null) {sb.append(line);}reader.close();conn.disconnect();JsonNode root = objectMapper.readTree(sb.toString());String status = root.path("status").asText();if (!"OK".equals(status)) {LOGGER.warn("Geocoding failed for '{}': status={}", address, status);return null;}JsonNode location = root.path("results").get(0).path("geometry").path("location");double lat = location.path("lat").asDouble();double lng = location.path("lng").asDouble();LOGGER.info("Geocoded '{}' -> [{}, {}]", address, lat, lng);return new double[]{lat, lng};} catch (Exception e) {LOGGER.error("Geocoding error for '{}': {}", address, e.getMessage());return null;}}/*** Remove noise from address: phone numbers, PIN- prefix, Landmark:, Shop No. etc.* Keep only location-relevant parts for better geocoding accuracy.*/private String sanitizeForGeocoding(String address) {String clean = address;// Remove phone numbers (Ph: XXXXXXXXXX)clean = clean.replaceAll("(?i),?\\s*Ph:\\s*\\d+", "");// Remove PIN- prefix but keep the numberclean = clean.replaceAll("(?i)PIN-", "");// Remove Landmark: prefixclean = clean.replaceAll("(?i)Landmark:\\s*", "");// Remove Shop No. / Ward No. patterns (too specific for geocoding)clean = clean.replaceAll("(?i)Shop\\s*No\\.?\\s*[\\d/]+,?\\s*", "");clean = clean.replaceAll("(?i)Ward\\s*No\\.?\\s*[\\d/]+,?\\s*", "");// Clean up double commas and trailing commasclean = clean.replaceAll(",\\s*,", ",");clean = clean.replaceAll("^[,\\s]+|[,\\s]+$", "");return clean.trim();}}