Leaflet Server in Java

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.

Leave a Reply

Your email address will not be published. Required fields are marked *


Macro Nepal Helper