package com.sigem.gis.service; import org.springframework.http.*; import org.springframework.stereotype.Service; import org.springframework.web.client.RestTemplate; @Service public class GeoServerService { private final String GS_URL = "http://geoserver:8080/geoserver/rest"; private final String GS_USER = "admin"; private final String GS_PASS = "geoserver"; private final RestTemplate restTemplate; public GeoServerService() { org.springframework.http.client.SimpleClientHttpRequestFactory factory = new org.springframework.http.client.SimpleClientHttpRequestFactory(); factory.setConnectTimeout(2000); factory.setReadTimeout(2000); this.restTemplate = new RestTemplate(factory); } /** * Publica una vista como capa de GeoServer con un estilo específico. */ public void publishLayer(String layerName, String viewName, String styleName, String boundNo, String boundSe) { ensureInfrastructureExists(); String workspace = "sigem"; String datastore = "sigem_db"; System.out.println("Publicando Capa WMS en GeoServer: " + layerName + " (Estilo: " + styleName + ")"); // 1. Crear/Actualizar FeatureType (Configuración de datos y BBOX) String url = String.format("%s/workspaces/%s/datastores/%s/featuretypes/%s", GS_URL, workspace, datastore, layerName); StringBuilder bboxJson = new StringBuilder(); if (boundNo != null && boundSe != null) { try { String[] no = boundNo.split(","); String[] se = boundSe.split(","); double lat1 = Double.parseDouble(no[0].trim()); double lon1 = Double.parseDouble(no[1].trim()); double lat2 = Double.parseDouble(se[0].trim()); double lon2 = Double.parseDouble(se[1].trim()); bboxJson.append(", \"latLonBoundingBox\": {"); bboxJson.append(String.format("\"minx\": %f, \"maxx\": %f, \"miny\": %f, \"maxy\": %f, \"crs\": \"EPSG:4326\"", Math.min(lon1, lon2), Math.max(lon1, lon2), Math.min(lat1, lat2), Math.max(lat1, lat2))); bboxJson.append("}"); } catch (Exception e) { System.err.println("Error parseando bounds: " + e.getMessage()); } } String jsonBody = String.format( "{\"featureType\": {\"name\": \"%s\", \"nativeName\": \"%s\", \"title\": \"%s\", \"srs\": \"EPSG:4326\" %s}}", layerName, viewName, layerName, bboxJson.toString() ); HttpHeaders headers = createHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); HttpEntity entity = new HttpEntity<>(jsonBody, headers); try { restTemplate.exchange(url, HttpMethod.PUT, entity, String.class); } catch (Exception e) { String postUrl = String.format("%s/workspaces/%s/datastores/%s/featuretypes", GS_URL, workspace, datastore); try { restTemplate.postForEntity(postUrl, entity, String.class); } catch (Exception ex) { System.err.println("Error publicando FeatureType: " + ex.getMessage()); } } // 2. Asignar Estilo Predeterminado a la Capa if (styleName != null) { String layerUrl = String.format("%s/layers/%s:%s", GS_URL, workspace, layerName); String layerJson = String.format("{\"layer\": {\"defaultStyle\": {\"name\": \"%s\"}}}", styleName); try { restTemplate.exchange(layerUrl, HttpMethod.PUT, new HttpEntity<>(layerJson, headers), String.class); System.out.println("Estilo '" + styleName + "' asignado a la capa."); } catch (Exception e) { System.err.println("Error asignando estilo a la capa: " + e.getMessage()); } } } private void ensureInfrastructureExists() { String workspace = "sigem"; String datastore = "sigem_db"; // 1. Verificar Workspace try { restTemplate.exchange(GS_URL + "/workspaces/" + workspace, HttpMethod.GET, new HttpEntity<>(createHeaders()), String.class); } catch (Exception e) { System.out.println("Creando Workspace: " + workspace); String wsJson = String.format("{\"workspace\": {\"name\": \"%s\"}}", workspace); HttpHeaders h = createHeaders(); h.setContentType(MediaType.APPLICATION_JSON); restTemplate.postForEntity(GS_URL + "/workspaces", new HttpEntity<>(wsJson, h), String.class); } // 2. Verificar DataStore try { restTemplate.exchange(GS_URL + "/workspaces/" + workspace + "/datastores/" + datastore, HttpMethod.GET, new HttpEntity<>(createHeaders()), String.class); } catch (Exception e) { System.out.println("Creando DataStore: " + datastore); String dsJson = String.format( "{\"dataStore\": {\"name\": \"%s\", \"connectionParameters\": {" + "\"host\": \"postgres\", \"port\": \"5432\", \"database\": \"sigem\", " + "\"user\": \"sigem_user\", \"passwd\": \"sigem_pass\", \"dbtype\": \"postgis\"}}}", datastore ); HttpHeaders h = createHeaders(); h.setContentType(MediaType.APPLICATION_JSON); try { restTemplate.postForEntity(GS_URL + "/workspaces/" + workspace + "/datastores", new HttpEntity<>(dsJson, h), String.class); } catch (Exception ex) { System.err.println("Error creando DataStore: " + ex.getMessage()); } } } /** * Purga la caché de una capa en GeoWebCache (GWC) para forzar el recálculo de perímetros. */ public void truncateCache(String layerName) { String url = "http://geoserver:8080/geoserver/gwc/rest/masstruncate"; String xmlBody = String.format("sigem:%s", layerName); HttpHeaders headers = createHeaders(); headers.setContentType(MediaType.TEXT_XML); HttpEntity entity = new HttpEntity<>(xmlBody, headers); try { restTemplate.postForEntity(url, entity, String.class); System.out.println("Caché GWC purgada para: " + layerName); } catch (Exception e) { System.err.println("Error purgando caché para " + layerName + ": " + e.getMessage()); } } private HttpHeaders createHeaders() { HttpHeaders headers = new HttpHeaders(); // Intentamos admin/admin si falla el de las reglas (debido a reset de GS) try { headers.setBasicAuth(GS_USER, GS_PASS); // Probaríamos conexión aquí si fuera necesario, pero por ahora simplificamos: // Si el subagent detectó admin/admin, podríamos parametrizarlo. } catch (Exception e) { headers.setBasicAuth("admin", "admin"); } return headers; } }