Overview
Leaflet Server provides backend services for managing interactive maps, geographic data, and map rendering. This Java implementation includes spatial data storage, tile serving, geocoding, routing, and real-time map features.
1. Dependencies
<dependencies> <!-- Spring Boot --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <version>3.1.0</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> <version>3.1.0</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> <version>3.1.0</version> </dependency> <!-- Spatial Database Support --> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-spatial</artifactId> <version>6.2.7.Final</version> </dependency> <dependency> <groupId>org.postgresql</groupId> <artifactId>postgresql</artifactId> <version>42.6.0</version> </dependency> <dependency> <groupId>net.postgis</groupId> <artifactId>postgis-jdbc</artifactId> <version>2.5.1</version> </dependency> <!-- Geospatial Libraries --> <dependency> <groupId>org.locationtech.jts</groupId> <artifactId>jts-core</artifactId> <version>1.19.0</version> </dependency> <dependency> <groupId>org.geotools</groupId> <artifactId>gt-main</artifactId> <version>28.2</version> </dependency> <dependency> <groupId>org.geotools</groupId> <artifactId>gt-geojson</artifactId> <version>28.2</version> </dependency> <!-- Image Processing for Tiles --> <dependency> <groupId>com.twelvemonkeys.imageio</groupId> <artifactId>imageio-core</artifactId> <version>3.9.4</version> </dependency> <dependency> <groupId>com.twelvemonkeys.imageio</groupId> <artifactId>imageio-jpeg</artifactId> <version>3.9.4</version> </dependency> <dependency> <groupId>com.twelvemonkeys.imageio</groupId> <artifactId>imageio-png</artifactId> <version>3.9.4</version> </dependency> <!-- Caching --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-cache</artifactId> <version>3.1.0</version> </dependency> <dependency> <groupId>com.github.ben-manes.caffeine</groupId> <artifactId>caffeine</artifactId> <version>3.1.6</version> </dependency> <!-- JSON Processing --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>2.15.2</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.15.2</version> </dependency> <!-- Utilities --> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.12.0</version> </dependency> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.13.0</version> </dependency> <!-- Logging --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>2.0.7</version> </dependency> </dependencies>
2. Core Domain Models
Spatial Data Models
package com.example.leaflet.model; import org.locationtech.jts.geom.Geometry; import org.locationtech.jts.geom.Point; import org.locationtech.jts.geom.Polygon; import com.fasterxml.jackson.annotation.JsonIgnore; import javax.persistence.*; import java.time.LocalDateTime; import java.util.Map; @Entity @Table(name = "map_layers") public class MapLayer { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(nullable = false) private String name; private String description; @Enumerated(EnumType.STRING) @Column(nullable = false) private LayerType type; @Column(name = "is_visible") private Boolean isVisible = true; @Column(name = "is_base_layer") private Boolean isBaseLayer = false; @Column(name = "z_index") private Integer zIndex = 0; @Column(name = "opacity") private Double opacity = 1.0; @Column(name = "min_zoom") private Integer minZoom = 0; @Column(name = "max_zoom") private Integer maxZoom = 18; @Column(name = "tile_url_template") private String tileUrlTemplate; @Column(name = "data_source") private String dataSource; // URL, file path, or database query @Enumerated(EnumType.STRING) private DataFormat dataFormat; @ElementCollection @CollectionTable(name = "layer_style", joinColumns = @JoinColumn(name = "layer_id")) @MapKeyColumn(name = "style_key") @Column(name = "style_value") private Map<String, String> style; @ElementCollection @CollectionTable(name = "layer_metadata", joinColumns = @JoinColumn(name = "layer_id")) @MapKeyColumn(name = "meta_key") @Column(name = "meta_value") private Map<String, String> metadata; @Column(name = "created_at") private LocalDateTime createdAt; @Column(name = "updated_at") private LocalDateTime updatedAt; @PrePersist protected void onCreate() { createdAt = LocalDateTime.now(); updatedAt = LocalDateTime.now(); } @PreUpdate protected void onUpdate() { updatedAt = LocalDateTime.now(); } // Getters and Setters public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public LayerType getType() { return type; } public void setType(LayerType type) { this.type = type; } public Boolean getIsVisible() { return isVisible; } public void setIsVisible(Boolean isVisible) { this.isVisible = isVisible; } public Boolean getIsBaseLayer() { return isBaseLayer; } public void setIsBaseLayer(Boolean isBaseLayer) { this.isBaseLayer = isBaseLayer; } public Integer getZIndex() { return zIndex; } public void setZIndex(Integer zIndex) { this.zIndex = zIndex; } public Double getOpacity() { return opacity; } public void setOpacity(Double opacity) { this.opacity = opacity; } public Integer getMinZoom() { return minZoom; } public void setMinZoom(Integer minZoom) { this.minZoom = minZoom; } public Integer getMaxZoom() { return maxZoom; } public void setMaxZoom(Integer maxZoom) { this.maxZoom = maxZoom; } public String getTileUrlTemplate() { return tileUrlTemplate; } public void setTileUrlTemplate(String tileUrlTemplate) { this.tileUrlTemplate = tileUrlTemplate; } public String getDataSource() { return dataSource; } public void setDataSource(String dataSource) { this.dataSource = dataSource; } public DataFormat getDataFormat() { return dataFormat; } public void setDataFormat(DataFormat dataFormat) { this.dataFormat = dataFormat; } public Map<String, String> getStyle() { return style; } public void setStyle(Map<String, String> style) { this.style = style; } public Map<String, String> getMetadata() { return metadata; } public void setMetadata(Map<String, String> metadata) { this.metadata = metadata; } public LocalDateTime getCreatedAt() { return createdAt; } public void setCreatedAt(LocalDateTime createdAt) { this.createdAt = createdAt; } public LocalDateTime getUpdatedAt() { return updatedAt; } public void setUpdatedAt(LocalDateTime updatedAt) { this.updatedAt = updatedAt; } } @Entity @Table(name = "spatial_features") public class SpatialFeature { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(nullable = false) private String name; private String description; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "layer_id", nullable = false) private MapLayer layer; @Column(columnDefinition = "geometry(Geometry,4326)") @JsonIgnore private Geometry geometry; @Enumerated(EnumType.STRING) private FeatureType featureType; @ElementCollection @CollectionTable(name = "feature_properties", joinColumns = @JoinColumn(name = "feature_id")) @MapKeyColumn(name = "property_key") @Column(name = "property_value") private Map<String, String> properties; @ElementCollection @CollectionTable(name = "feature_style", joinColumns = @JoinColumn(name = "feature_id")) @MapKeyColumn(name = "style_key") @Column(name = "style_value") private Map<String, String> style; @Column(name = "created_at") private LocalDateTime createdAt; @Column(name = "updated_at") private LocalDateTime updatedAt; @PrePersist protected void onCreate() { createdAt = LocalDateTime.now(); updatedAt = LocalDateTime.now(); } @PreUpdate protected void onUpdate() { updatedAt = LocalDateTime.now(); } // Getters and Setters public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public MapLayer getLayer() { return layer; } public void setLayer(MapLayer layer) { this.layer = layer; } public Geometry getGeometry() { return geometry; } public void setGeometry(Geometry geometry) { this.geometry = geometry; } public FeatureType getFeatureType() { return featureType; } public void setFeatureType(FeatureType featureType) { this.featureType = featureType; } public Map<String, String> getProperties() { return properties; } public void setProperties(Map<String, String> properties) { this.properties = properties; } public Map<String, String> getStyle() { return style; } public void setStyle(Map<String, String> style) { this.style = style; } public LocalDateTime getCreatedAt() { return createdAt; } public void setCreatedAt(LocalDateTime createdAt) { this.createdAt = createdAt; } public LocalDateTime getUpdatedAt() { return updatedAt; } public void setUpdatedAt(LocalDateTime updatedAt) { this.updatedAt = updatedAt; } // Helper methods for common geometry types public Point getAsPoint() { return geometry instanceof Point ? (Point) geometry : null; } public Polygon getAsPolygon() { return geometry instanceof Polygon ? (Polygon) geometry : null; } public Double getLatitude() { Point point = getAsPoint(); return point != null ? point.getY() : null; } public Double getLongitude() { Point point = getAsPoint(); return point != null ? point.getX() : null; } } @Entity @Table(name = "map_markers") public class MapMarker { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(nullable = false) private String title; private String description; @Column(columnDefinition = "geometry(Point,4326)") @JsonIgnore private Point location; @Column(name = "icon_url") private String iconUrl; @Column(name = "icon_size_x") private Integer iconSizeX = 25; @Column(name = "icon_size_y") private Integer iconSizeY = 41; @Column(name = "icon_anchor_x") private Integer iconAnchorX = 12; @Column(name = "icon_anchor_y") private Integer iconAnchorY = 41; @Column(name = "popup_content") private String popupContent; @Column(name = "is_draggable") private Boolean isDraggable = false; @ElementCollection @CollectionTable(name = "marker_properties", joinColumns = @JoinColumn(name = "marker_id")) @MapKeyColumn(name = "property_key") @Column(name = "property_value") private Map<String, String> properties; @Column(name = "created_at") private LocalDateTime createdAt; @Column(name = "updated_at") private LocalDateTime updatedAt; @PrePersist protected void onCreate() { createdAt = LocalDateTime.now(); updatedAt = LocalDateTime.now(); } @PreUpdate protected void onUpdate() { updatedAt = LocalDateTime.now(); } // Getters and Setters public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public Point getLocation() { return location; } public void setLocation(Point location) { this.location = location; } public String getIconUrl() { return iconUrl; } public void setIconUrl(String iconUrl) { this.iconUrl = iconUrl; } public Integer getIconSizeX() { return iconSizeX; } public void setIconSizeX(Integer iconSizeX) { this.iconSizeX = iconSizeX; } public Integer getIconSizeY() { return iconSizeY; } public void setIconSizeY(Integer iconSizeY) { this.iconSizeY = iconSizeY; } public Integer getIconAnchorX() { return iconAnchorX; } public void setIconAnchorX(Integer iconAnchorX) { this.iconAnchorX = iconAnchorX; } public Integer getIconAnchorY() { return iconAnchorY; } public void setIconAnchorY(Integer iconAnchorY) { this.iconAnchorY = iconAnchorY; } public String getPopupContent() { return popupContent; } public void setPopupContent(String popupContent) { this.popupContent = popupContent; } public Boolean getIsDraggable() { return isDraggable; } public void setIsDraggable(Boolean isDraggable) { this.isDraggable = isDraggable; } public Map<String, String> getProperties() { return properties; } public void setProperties(Map<String, String> properties) { this.properties = properties; } public LocalDateTime getCreatedAt() { return createdAt; } public void setCreatedAt(LocalDateTime createdAt) { this.createdAt = createdAt; } public LocalDateTime getUpdatedAt() { return updatedAt; } public void setUpdatedAt(LocalDateTime updatedAt) { this.updatedAt = updatedAt; } // Convenience methods public Double getLatitude() { return location != null ? location.getY() : null; } public Double getLongitude() { return location != null ? location.getX() : null; } public void setLatLng(double lat, double lng) { // This would typically use a geometry factory // location = geometryFactory.createPoint(new Coordinate(lng, lat)); } } // Enums public enum LayerType { TILE("Tile Layer"), GEOJSON("GeoJSON"), WMS("WMS"), WMTS("WMTS"), VECTOR("Vector"), HEATMAP("Heatmap"), CLUSTER("Cluster"); private final String displayName; LayerType(String displayName) { this.displayName = displayName; } public String getDisplayName() { return displayName; } } public enum FeatureType { POINT("Point"), LINE("Line"), POLYGON("Polygon"), MULTIPOINT("MultiPoint"), MULTILINE("MultiLine"), MULTIPOLYGON("MultiPolygon"), GEOMETRYCOLLECTION("GeometryCollection"); private final String displayName; FeatureType(String displayName) { this.displayName = displayName; } public String getDisplayName() { return displayName; } } public enum DataFormat { GEOJSON("GeoJSON"), KML("KML"), GPX("GPX"), SHAPEFILE("Shapefile"), WKT("WKT"), CSV("CSV"); private final String displayName; DataFormat(String displayName) { this.displayName = displayName; } public String getDisplayName() { return displayName; } } Tile and Bounding Box Models
package com.example.leaflet.model; public class TileRequest { private int x; private int y; private int z; private String layer; private String format = "png"; private Integer scale; // For retina/high-DPI displays // Getters and Setters public int getX() { return x; } public void setX(int x) { this.x = x; } public int getY() { return y; } public void setY(int y) { this.y = y; } public int getZ() { return z; } public void setZ(int z) { this.z = z; } public String getLayer() { return layer; } public void setLayer(String layer) { this.layer = layer; } public String getFormat() { return format; } public void setFormat(String format) { this.format = format; } public Integer getScale() { return scale; } public void setScale(Integer scale) { this.scale = scale; } } public class BoundingBox { private double minLng; private double minLat; private double maxLng; private double maxLat; public BoundingBox() {} public BoundingBox(double minLng, double minLat, double maxLng, double maxLat) { this.minLng = minLng; this.minLat = minLat; this.maxLng = maxLng; this.maxLat = maxLat; } // Getters and Setters public double getMinLng() { return minLng; } public void setMinLng(double minLng) { this.minLng = minLng; } public double getMinLat() { return minLat; } public void setMinLat(double minLat) { this.minLat = minLat; } public double getMaxLng() { return maxLng; } public void setMaxLng(double maxLng) { this.maxLng = maxLng; } public double getMaxLat() { return maxLat; } public void setMaxLat(double maxLat) { this.maxLat = maxLat; } public boolean contains(double lng, double lat) { return lng >= minLng && lng <= maxLng && lat >= minLat && lat <= maxLat; } public double getWidth() { return maxLng - minLng; } public double getHeight() { return maxLat - minLat; } public Point getCenter() { double centerLng = (minLng + maxLng) / 2.0; double centerLat = (minLat + maxLat) / 2.0; return new Point(centerLng, centerLat); } } public class Point { private double lng; private double lat; public Point() {} public Point(double lng, double lat) { this.lng = lng; this.lat = lat; } // Getters and Setters public double getLng() { return lng; } public void setLng(double lng) { this.lng = lng; } public double getLat() { return lat; } public void setLat(double lat) { this.lat = lat; } public double distanceTo(Point other) { double earthRadius = 6371; // kilometers double dLat = Math.toRadians(other.lat - this.lat); double dLng = Math.toRadians(other.lng - this.lng); double a = Math.sin(dLat/2) * Math.sin(dLat/2) + Math.cos(Math.toRadians(this.lat)) * Math.cos(Math.toRadians(other.lat)) * Math.sin(dLng/2) * Math.sin(dLng/2); double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); return earthRadius * c; } } public class MapViewState { private Point center; private Integer zoom; private BoundingBox bounds; private java.util.List<String> activeLayers; // Getters and Setters public Point getCenter() { return center; } public void setCenter(Point center) { this.center = center; } public Integer getZoom() { return zoom; } public void setZoom(Integer zoom) { this.zoom = zoom; } public BoundingBox getBounds() { return bounds; } public void setBounds(BoundingBox bounds) { this.bounds = bounds; } public java.util.List<String> getActiveLayers() { return activeLayers; } public void setActiveLayers(java.util.List<String> activeLayers) { this.activeLayers = activeLayers; } } 3. Tile Serving System
package com.example.leaflet.service; import com.example.leaflet.model.TileRequest; import com.example.leaflet.model.MapLayer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cache.annotation.Cacheable; import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceLoader; import org.springframework.stereotype.Service; import javax.imageio.ImageIO; import java.awt.*; import java.awt.image.BufferedImage; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; @Service public class TileService { private static final Logger log = LoggerFactory.getLogger(TileService.class); @Autowired private ResourceLoader resourceLoader; @Autowired private MapLayerService mapLayerService; @Autowired private FeatureService featureService; private static final int TILE_SIZE = 256; /** * Get tile image for the given request */ @Cacheable(value = "tiles", key = "#request.x + '-' + #request.y + '-' + #request.z + '-' + #request.layer") public byte[] getTile(TileRequest request) throws IOException { log.debug("Generating tile: {}/{}/{} for layer: {}", request.getZ(), request.getX(), request.getY(), request.getLayer()); MapLayer layer = mapLayerService.getLayerByName(request.getLayer()); if (layer == null) { return generateErrorTile("Layer not found"); } switch (layer.getType()) { case TILE: return serveExternalTile(request, layer); case GEOJSON: case VECTOR: return generateVectorTile(request, layer); case HEATMAP: return generateHeatmapTile(request, layer); default: return generateErrorTile("Unsupported layer type"); } } /** * Serve tile from external source (proxy) */ private byte[] serveExternalTile(TileRequest request, MapLayer layer) throws IOException { String url = buildTileUrl(request, layer); try { Resource resource = resourceLoader.getResource(url); if (resource.exists()) { try (InputStream is = resource.getInputStream()) { return readFully(is); } } else { return generateNotFoundTile(); } } catch (Exception e) { log.warn("Failed to fetch external tile: {}", url, e); return generateErrorTile("Tile unavailable"); } } /** * Generate vector tile from spatial features */ private byte[] generateVectorTile(TileRequest request, MapLayer layer) throws IOException { BufferedImage image = new BufferedImage(TILE_SIZE, TILE_SIZE, BufferedImage.TYPE_INT_ARGB); Graphics2D g2d = image.createGraphics(); try { // Set up graphics g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); // Draw background (transparent) g2d.setColor(new Color(0, 0, 0, 0)); g2d.fillRect(0, 0, TILE_SIZE, TILE_SIZE); // Get features for this tile bounds BoundingBox bbox = tileToBoundingBox(request.getX(), request.getY(), request.getZ()); java.util.List<SpatialFeature> features = featureService.getFeaturesInBounds(layer, bbox); // Draw features for (SpatialFeature feature : features) { drawFeature(g2d, feature, bbox, request.getZ()); } // Convert to byte array return imageToByteArray(image, request.getFormat()); } finally { g2d.dispose(); } } /** * Generate heatmap tile */ private byte[] generateHeatmapTile(TileRequest request, MapLayer layer) throws IOException { BufferedImage image = new BufferedImage(TILE_SIZE, TILE_SIZE, BufferedImage.TYPE_INT_ARGB); Graphics2D g2d = image.createGraphics(); try { // Create gradient for heatmap GradientPaint gradient = new GradientPaint( 0, 0, new Color(0, 0, 255, 100), // Cool (low density) TILE_SIZE, TILE_SIZE, new Color(255, 0, 0, 200) // Hot (high density) ); g2d.setPaint(gradient); g2d.fillRect(0, 0, TILE_SIZE, TILE_SIZE); // Add data points (simplified) BoundingBox bbox = tileToBoundingBox(request.getX(), request.getY(), request.getZ()); java.util.List<SpatialFeature> features = featureService.getFeaturesInBounds(layer, bbox); for (SpatialFeature feature : features) { if (feature.getAsPoint() != null) { Point point = feature.getAsPoint(); Point tilePoint = worldToTile(point.getLng(), point.getLat(), request.getZ(), request.getX(), request.getY()); // Draw heat point int radius = 20; g2d.setColor(new Color(255, 255, 255, 100)); g2d.fillOval( (int)(tilePoint.getLng() * TILE_SIZE) - radius/2, (int)(tilePoint.getLat() * TILE_SIZE) - radius/2, radius, radius ); } } return imageToByteArray(image, request.getFormat()); } finally { g2d.dispose(); } } /** * Draw a spatial feature on the tile */ private void drawFeature(Graphics2D g2d, SpatialFeature feature, BoundingBox bbox, int zoom) { // Apply feature style applyFeatureStyle(g2d, feature.getStyle()); if (feature.getAsPoint() != null) { drawPoint(g2d, feature.getAsPoint(), bbox, zoom); } else if (feature.getAsPolygon() != null) { drawPolygon(g2d, feature.getAsPolygon(), bbox, zoom); } // Add support for other geometry types... } /** * Draw a point feature */ private void drawPoint(Graphics2D g2d, Point point, BoundingBox bbox, int zoom) { Point tilePoint = worldToTile(point.getX(), point.getY(), bbox); int markerSize = Math.max(5, 20 - zoom); // Adjust size based on zoom g2d.fillOval( (int)(tilePoint.getLng() * TILE_SIZE) - markerSize/2, (int)(tilePoint.getLat() * TILE_SIZE) - markerSize/2, markerSize, markerSize ); } /** * Draw a polygon feature */ private void drawPolygon(Graphics2D g2d, Polygon polygon, BoundingBox bbox, int zoom) { java.awt.Polygon awtPolygon = new java.awt.Polygon(); for (int i = 0; i < polygon.getNumPoints(); i++) { Point point = new Point( polygon.getCoordinates()[i].x, polygon.getCoordinates()[i].y ); Point tilePoint = worldToTile(point.getLng(), point.getLat(), bbox); awtPolygon.addPoint( (int)(tilePoint.getLng() * TILE_SIZE), (int)(tilePoint.getLat() * TILE_SIZE) ); } g2d.fillPolygon(awtPolygon); g2d.drawPolygon(awtPolygon); } /** * Apply feature styling */ private void applyFeatureStyle(Graphics2D g2d, Map<String, String> style) { if (style == null) return; // Fill color if (style.containsKey("fillColor")) { g2d.setColor(parseColor(style.get("fillColor"), new Color(0, 0, 255, 128))); } // Stroke color if (style.containsKey("color")) { g2d.setColor(parseColor(style.get("color"), Color.BLACK)); } // Stroke width if (style.containsKey("weight")) { g2d.setStroke(new BasicStroke(Float.parseFloat(style.get("weight")))); } } /** * Convert tile coordinates to bounding box */ public BoundingBox tileToBoundingBox(int x, int y, int zoom) { double n = Math.pow(2, zoom); double minLng = x / n * 360.0 - 180.0; double maxLng = (x + 1) / n * 360.0 - 180.0; double minLat = radToDeg(Math.atan(Math.sinh(Math.PI * (1 - 2 * (y + 1) / n)))); double maxLat = radToDeg(Math.atan(Math.sinh(Math.PI * (1 - 2 * y / n)))); return new BoundingBox(minLng, minLat, maxLng, maxLat); } /** * Convert world coordinates to tile-relative coordinates */ private Point worldToTile(double lng, double lat, BoundingBox bbox) { double x = (lng - bbox.getMinLng()) / bbox.getWidth(); double y = (bbox.getMaxLat() - lat) / bbox.getHeight(); // Invert Y axis return new Point(x, y); } private Point worldToTile(double lng, double lat, int zoom, int tileX, int tileY) { BoundingBox bbox = tileToBoundingBox(tileX, tileY, zoom); return worldToTile(lng, lat, bbox); } /** * Build external tile URL from template */ private String buildTileUrl(TileRequest request, MapLayer layer) { String url = layer.getTileUrlTemplate() .replace("{x}", String.valueOf(request.getX())) .replace("{y}", String.valueOf(request.getY())) .replace("{z}", String.valueOf(request.getZ())) .replace("{s}", "a"); // Subdomain - could be randomized if (request.getScale() != null && request.getScale() > 1) { url = url.replace("{r}", "@2x"); } else { url = url.replace("{r}", ""); } return url; } /** * Generate error tile */ private byte[] generateErrorTile(String message) throws IOException { BufferedImage image = new BufferedImage(TILE_SIZE, TILE_SIZE, BufferedImage.TYPE_INT_RGB); Graphics2D g2d = image.createGraphics(); try { g2d.setColor(Color.WHITE); g2d.fillRect(0, 0, TILE_SIZE, TILE_SIZE); g2d.setColor(Color.RED); g2d.drawString(message, 10, TILE_SIZE / 2); return imageToByteArray(image, "png"); } finally { g2d.dispose(); } } private byte[] generateNotFoundTile() throws IOException { return generateErrorTile("Not Found"); } /** * Convert image to byte array */ private byte[] imageToByteArray(BufferedImage image, String format) throws IOException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); ImageIO.write(image, format, baos); return baos.toByteArray(); } /** * Read input stream fully */ private byte[] readFully(InputStream is) throws IOException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int length; while ((length = is.read(buffer)) != -1) { baos.write(buffer, 0, length); } return baos.toByteArray(); } /** * Parse color from string */ private Color parseColor(String colorStr, Color defaultColor) { try { if (colorStr.startsWith("#")) { return Color.decode(colorStr); } else if (colorStr.startsWith("rgb")) { // Parse rgb(r, g, b) or rgba(r, g, b, a) String[] parts = colorStr.replace("rgb(", "").replace("rgba(", "").replace(")", "").split(","); int r = Integer.parseInt(parts[0].trim()); int g = Integer.parseInt(parts[1].trim()); int b = Integer.parseInt(parts[2].trim()); int a = parts.length > 3 ? (int)(Float.parseFloat(parts[3].trim()) * 255) : 255; return new Color(r, g, b, a); } } catch (Exception e) { log.warn("Failed to parse color: {}", colorStr, e); } return defaultColor; } private double radToDeg(double rad) { return rad * 180.0 / Math.PI; } } 4. Geospatial Services
```java
package com.example.leaflet.service;
import com.example.leaflet.model.*;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.ge
Java Observability, Logging Intelligence & AI-Driven Monitoring (APM, Tracing, Logs & Anomaly Detection)
https://macronepal.com/blog/beyond-metrics-observing-serverless-and-traditional-java-applications-with-thundra-apm/
Explains using Thundra APM to observe both serverless and traditional Java applications by combining tracing, metrics, and logs into a unified observability platform for faster debugging and performance insights.
https://macronepal.com/blog/dynatrace-oneagent-in-java-2/
Explains Dynatrace OneAgent for Java, which automatically instruments JVM applications to capture metrics, traces, and logs, enabling full-stack monitoring and root-cause analysis with minimal configuration.
https://macronepal.com/blog/lightstep-java-sdk-distributed-tracing-and-observability-implementation/
Explains Lightstep Java SDK for distributed tracing, helping developers track requests across microservices and identify latency issues using OpenTelemetry-based observability.
https://macronepal.com/blog/honeycomb-io-beeline-for-java-complete-guide-2/
Explains Honeycomb Beeline for Java, which provides high-cardinality observability and deep query capabilities to understand complex system behavior and debug distributed systems efficiently.
https://macronepal.com/blog/lumigo-for-serverless-in-java-complete-distributed-tracing-guide-2/
Explains Lumigo for Java serverless applications, offering automatic distributed tracing, log correlation, and error tracking to simplify debugging in cloud-native environments. (Lumigo Docs)
https://macronepal.com/blog/from-noise-to-signals-implementing-log-anomaly-detection-in-java-applications/
Explains how to detect anomalies in Java logs using behavioral patterns and machine learning techniques to separate meaningful incidents from noisy log data and improve incident response.
https://macronepal.com/blog/ai-powered-log-analysis-in-java-from-reactive-debugging-to-proactive-insights/
Explains AI-driven log analysis for Java applications, shifting from manual debugging to predictive insights that identify issues early and improve system reliability using intelligent log processing.
https://macronepal.com/blog/titliel-java-logging-best-practices/
Explains best practices for Java logging, focusing on structured logs, proper log levels, performance optimization, and ensuring logs are useful for debugging and observability systems.
https://macronepal.com/blog/seeking-a-loguru-for-java-the-quest-for-elegant-and-simple-logging/
Explains the search for simpler, more elegant logging frameworks in Java, comparing modern logging approaches that aim to reduce complexity while improving readability and developer experience.