package org.geoserver.geosearch; import org.opengis.referencing.FactoryException; import org.opengis.referencing.NoSuchAuthorityCodeException; import org.opengis.referencing.crs.CoordinateReferenceSystem; import org.restlet.Restlet; import org.restlet.data.Request; import org.restlet.data.Response; import org.restlet.data.Method; import org.restlet.data.MediaType; import org.restlet.data.Status; import org.geoserver.catalog.Catalog; import org.geoserver.catalog.FeatureTypeInfo; import org.geoserver.catalog.NamespaceInfo; import org.geoserver.geosearch.GeoServerProxyAwareRestlet; import org.geoserver.rest.format.DataFormat; import org.geoserver.rest.format.FreemarkerFormat; import org.geoserver.rest.util.RESTUtils; import org.geoserver.rest.RestletException; import org.geotools.geometry.jts.ReferencedEnvelope; import org.geotools.referencing.CRS; import org.jdom.Document; import org.jdom.Element; import org.jdom.Namespace; import com.vividsolutions.jts.geom.Envelope; import java.io.IOException; import java.util.Map; import java.util.HashMap; import java.util.List; import java.util.ArrayList; import java.util.Iterator; import java.util.logging.Level; import java.util.logging.Logger; import freemarker.template.SimpleHash; import freemarker.template.TemplateModelException; public class LayerAboutPage extends GeoServerProxyAwareRestlet { private static final Logger LOGGER = org.geotools.util.logging.Logging.getLogger("org.geoserver.geosearch"); private final DataFormat format = new FreemarkerFormat("layerpage.ftl", getClass(), MediaType.TEXT_HTML); private Catalog catalog; public void setCatalog(Catalog cat){ catalog = cat; } public Catalog getCatalog(){ return catalog; } public void handle(Request request, Response response){ if (request.getMethod().equals(Method.GET)) doGet(request, response); else response.setStatus(Status.CLIENT_ERROR_METHOD_NOT_ALLOWED); } public void doGet(Request request, Response response){ String namespace = (String)request.getAttributes().get("namespace"); String layer = (String)request.getAttributes().get("layer"); response.setEntity(format.toRepresentation(getContext(namespace, layer, request))); } SimpleHash getContext(String namespace, String layer, Request request){ FeatureTypeInfo info = lookupType(namespace, layer); if (!(Boolean)info.getMetadata().get("indexingEnabled")) { throw new RestletException( "Layer indexing disabled", Status.CLIENT_ERROR_FORBIDDEN ); } SimpleHash map = new SimpleHash(); //basic map.put("title", info.getTitle()); map.put("abstract", info.getAbstract()); //Metadata map.put("keywords", info.getKeywords()); map.put("declaredCRS", info.getCRS()); map.put("metadataLinks", info.getMetadataLinks()); try { Object o = info.getNativeCRS(); if (o != null) { map.put("nativeCRS", info.getNativeCRS()); } else { map.put("nativeCRS", "No native CRS configured for layer"); } } catch (Exception e) { LOGGER.log(Level.WARNING, "Error trying to get nativeCRS from " + info.getName() + "FeatureTypeInfo", e ); } String baseUrl = RESTUtils.getBaseURL(request); map.put("base", baseUrl); //general parameters for data requests map.put("name", info.getPrefixedName()); map.put("srs", info.getSRS()); ReferencedEnvelope bbox = getBBOX(info); String bboxString = bbox.getMinX() + "," + bbox.getMinY() + "," + bbox.getMaxX() + "," + bbox.getMaxY(); map.put("bbox", bboxString); map.put("tilesOrigin", bbox.getMinX()+","+bbox.getMinY()); int[] imageBox = getMapWidthHeight(bbox); map.put("width", imageBox[0]); map.put("height", imageBox[1]); map.put("maxResolution", getMaxResolution(bbox)); try{ map.put("boundingBox", info.boundingBox()); map.put("lonLatBoundingBox", info.getLatLonBoundingBox()); } catch(Exception e) { LOGGER.log(Level.WARNING, "Error trying to access bounding box or lonLatBoundingBox for " + info.getName() + "FeatureTypeInfo", e); } //Fields of Access map.put("gwc", isGWCAround() + ""); String gwcLink = baseUrl.substring(0,baseUrl.length()-4) + "gwc/"; map.put("gwcLink", gwcLink); map.put("attributes", info.getAttributes()); return map; } private FeatureTypeInfo lookupType(String namespace, String layer){ NamespaceInfo ns = catalog.getNamespaceByPrefix(namespace); if (ns == null) { throw new RestletException( "No such namespace: " + namespace, Status.CLIENT_ERROR_NOT_FOUND ); } FeatureTypeInfo featureType = null; try { featureType = catalog.getFeatureTypeByName(ns, layer); } catch(Exception e) { throw new RestletException( "No such featuretype: " + namespace + ":" + layer, Status.CLIENT_ERROR_NOT_FOUND ); } if (featureType == null) { throw new RestletException( "No such featuretype: " + namespace + ":" + layer, Status.CLIENT_ERROR_NOT_FOUND ); } return featureType; } private ReferencedEnvelope getBBOX(FeatureTypeInfo layer){ String bboxList; // We need to create a 4326 CRS for comparison to layer's crs CoordinateReferenceSystem latLonCrs = null; try { // get the CRS object for lat/lon 4326 latLonCrs = CRS.decode("EPSG:" + 4326); } catch (NoSuchAuthorityCodeException e) { String msg = "Error looking up SRS for EPSG: " + 4326 + ":" + e.getLocalizedMessage(); //currently does nothing with this string } catch (FactoryException e) { String msg = "Error looking up SRS for EPSG: " + 4326 + ":" + e.getLocalizedMessage(); //currently does nothing with this string } //yoinked from MapPreviewAction try { CoordinateReferenceSystem layerCrs = layer.getCRS(); /* A quick and efficient way to grab the bounding box is to get it * from the featuretype info where the lat/lon bbox is loaded * from the DTO. We do this with layer.getLatLongBoundingBox(). * We need to reproject the bounding box from lat/lon to the layer crs * for display */ Envelope orig_bbox = layer.getLatLonBoundingBox(); if ((orig_bbox.getWidth() == 0) || (orig_bbox.getHeight() == 0)) { orig_bbox.expandBy(0.1); } ReferencedEnvelope bbox = new ReferencedEnvelope(orig_bbox, latLonCrs); if (!CRS.equalsIgnoreMetadata(layerCrs, latLonCrs)) { // first check if we have a native bbox bbox = layer.boundingBox(); } // we now have a bounding box in the same CRS as the layer if ((bbox.getWidth() == 0) || (bbox.getHeight() == 0)) { bbox.expandBy(0.1); } if (layer.isEnabled()) { // expand bbox by 5% to allow large symbolizers to fit the map bbox.expandBy(bbox.getWidth() / 20, bbox.getHeight() / 20); return bbox; } } catch(Exception e) { } return null; } //yoinked from MapPreviewAction private int[] getMapWidthHeight(Envelope bbox) { int width; int height; double ratio = bbox.getHeight() / bbox.getWidth(); if (ratio < 1) { width = 750; height = (int) Math.round(750 * ratio); } else { width = (int) Math.round(550 / ratio); height = 550; } // make sure we reach some minimal dimensions (300 pixels is more or less // the height of the zoom bar) if (width < 300) { width = 300; } if (height < 300) { height = 300; } // add 50 pixels horizontally to account for the zoom bar return new int[] { width + 50, height }; } private double getMaxResolution(ReferencedEnvelope areaOfInterest) { double w = areaOfInterest.getWidth(); double h = areaOfInterest.getHeight(); return ((w > h) ? w : h) / 256; } //returns true if this GeoServer instance uses GWC, false otherwise. private boolean isGWCAround(){ boolean GWCisAround = false; try { Class.forName("org.geowebcache.GeoWebCacheDispatcher"); GWCisAround = true; } catch (ClassNotFoundException cnfe) { // guess it's not there. } return GWCisAround; } }