/* * Adds a feature layer to the geopackage. */ void addFeatureLayer( GeoPackage geopkg, FeatureLayer layer, MapLayerInfo mapLayer, WMSMapContent map) throws IOException { FeatureEntry e = new FeatureEntry(); initEntry(e, layer, mapLayer, map); Filter filter = layer.getQuery().getFilter(); GeometryDescriptor gd = mapLayer.getFeature().getFeatureType().getGeometryDescriptor(); if (gd != null) { Envelope bnds = bounds(map); BBOX bboxFilter = filterFactory.bbox( gd.getLocalName(), bnds.getMinX(), bnds.getMinY(), bnds.getMaxX(), bnds.getMaxY(), map.getRequest().getSRS()); filter = filterFactory.and(filter, bboxFilter); } LOGGER.fine("Creating feature entry" + e.getTableName()); geopkg.add(e, layer.getSimpleFeatureSource(), filter); }
void addCoverageLayer( GeoPackage geopkg, GridCoverageLayer layer, MapLayerInfo mapLayer, WMSMapContent map) throws IOException { RasterEntry e = new RasterEntry(); initEntry(e, layer, mapLayer, map); // TODO: ensure this is one of the supported formats AbstractGridFormat format = mapLayer.getCoverage().getStore().getFormat(); LOGGER.fine("Creating raster entry" + e.getTableName()); geopkg.add(e, layer.getCoverage(), format); }
void addTileLayers(GeoPackage geopkg, List<MapLayerInfo> mapLayers, WMSMapContent map) throws IOException { if (mapLayers.isEmpty()) { return; } // figure out a name for the file entry String tileEntryName = null; Map formatOpts = map.getRequest().getFormatOptions(); if (formatOpts.containsKey("tileset_name")) { tileEntryName = (String) formatOpts.get("tileset_name"); } if (tileEntryName == null) { tileEntryName = map.getTitle(); } if (tileEntryName == null && mapLayers.size() == 1) { Iterator<MapLayerInfo> it = mapLayers.iterator(); tileEntryName = it.next().getLayerInfo().getName(); } GridSubset gridSubset = findBestGridSubset(map); int[] minmax = findMinMaxZoom(gridSubset, map); BoundingBox bbox = bbox(map); TileEntry e = new TileEntry(); e.setTableName(tileEntryName); if (mapLayers.size() == 1) { ResourceInfo r = mapLayers.get(0).getResource(); e.setIdentifier(r.getTitle()); e.setDescription(r.getAbstract()); } e.setBounds( new ReferencedEnvelope( findTileBounds(gridSubset, bbox, minmax[0]), map.getCoordinateReferenceSystem())); e.setSrid(srid(map)); GridSet gridSet = gridSubset.getGridSet(); for (int z = minmax[0]; z < minmax[1]; z++) { Grid g = gridSet.getGrid(z); TileMatrix m = new TileMatrix(); m.setZoomLevel(z); m.setMatrixWidth((int) g.getNumTilesWide()); m.setMatrixHeight((int) g.getNumTilesHigh()); m.setTileWidth(gridSubset.getTileWidth()); m.setTileHeight(gridSubset.getTileHeight()); // TODO: not sure about this m.setXPixelSize(g.getResolution()); m.setYPixelSize(g.getResolution()); // m.setXPixelSize(gridSet.getPixelSize()); // m.setYPixelSize(gridSet.getPixelSize()); e.getTileMatricies().add(m); } // figure out the actual bounds of the tiles to be renderered LOGGER.fine("Creating tile entry" + e.getTableName()); geopkg.create(e); // create a prototype getmap request GetMapRequest req = new GetMapRequest(); OwsUtils.copy(map.getRequest(), req, GetMapRequest.class); req.setLayers(mapLayers); String imageFormat = formatOpts.containsKey("format") ? parseFormatFromOpts(formatOpts) : findBestFormat(map); req.setFormat(imageFormat); req.setWidth(gridSubset.getTileWidth()); req.setHeight(gridSubset.getTileHeight()); // count tiles as we generate them int ntiles = 0; // flag determining if tile row indexes we store in database should be inverted boolean flipy = Boolean.valueOf((String) formatOpts.get("flipy")); for (int z = minmax[0]; z < minmax[1]; z++) { long[] intersect = gridSubset.getCoverageIntersection(z, bbox); for (long x = intersect[0]; x <= intersect[2]; x++) { for (long y = intersect[1]; y <= intersect[3]; y++) { BoundingBox box = gridSubset.boundsFromIndex(new long[] {x, y, z}); req.setBbox(new Envelope(box.getMinX(), box.getMaxX(), box.getMinY(), box.getMaxY())); Tile t = new Tile(); t.setZoom(z); t.setColumn((int) x); t.setRow((int) (flipy ? gridSubset.getNumTilesHigh(z) - (y + 1) : y)); WebMap result = webMapService.getMap(req); t.setData(toBytes(result)); geopkg.add(e, t); // images we encode are actually kept around, we need to clean them up if (ntiles++ == TILE_CLEANUP_INTERVAL) { cleanUpImages(); ntiles = 0; } } } } }
@Override public WebMap produceMap(WMSMapContent map) throws ServiceException, IOException { GeoPackage geopkg = new GeoPackage(); geopkg.init(); GetMapRequest req = map.getRequest(); List<Layer> layers = map.layers(); List<MapLayerInfo> mapLayers = req.getLayers(); Preconditions.checkState( layers.size() == mapLayers.size(), "Number of map layers not same as number of rendered layers"); // list of layers to render directly and include as tiles List<MapLayerInfo> tileLayers = new ArrayList(); // check mode, one of: // vector - render vector layers as feature entries and all else as tiles (default) // hybrid - render vector layers as feature entries, raster layers as raster entries, all // others as tile entries // tiled - all layers as a single tile set Map formatOpts = req.getFormatOptions(); Mode mode = formatOpts.containsKey("mode") ? Mode.valueOf(((String) formatOpts.get("mode")).toUpperCase()) : Mode.VECTOR; if (mode == Mode.TILED) { // tiled mode means render all as map tile layer tileLayers.addAll(mapLayers); } else { // hybrid mode, dump as raw vector or raster unless the request specifically asks for a // layer to be rendered as tiles for (int i = 0; i < layers.size(); i++) { Layer layer = layers.get(i); MapLayerInfo mapLayer = mapLayers.get(i); if (layer instanceof FeatureLayer) { addFeatureLayer(geopkg, (FeatureLayer) layer, mapLayer, map); } else if (layer instanceof GridCoverageLayer) { if (mode == Mode.HYBRID) { addCoverageLayer(geopkg, (GridCoverageLayer) layer, mapLayer, map); } else { tileLayers.add(mapLayer); } } else { tileLayers.add(mapLayer); } } } addTileLayers(geopkg, tileLayers, map); geopkg.close(); final File dbFile = geopkg.getFile(); final BufferedInputStream bin = new BufferedInputStream(new FileInputStream(dbFile)); RawMap result = new RawMap(map, bin, MIME_TYPE) { @Override public void writeTo(OutputStream out) throws IOException { String dbFilename = getAttachmentFileName(); if (dbFilename != null) { dbFilename = dbFilename.substring(0, dbFilename.length() - 4) + ".gpkg"; } else { // this shouldn't really ever happen, but fallback anyways dbFilename = "geoserver.gpkg"; } IOUtils.copy(bin, out); out.flush(); // JD: disabling zip compression for now // ZipOutputStream zout = new ZipOutputStream(out); // zout.putNextEntry(new ZipEntry(dbFilename)); // // super.writeTo(zout); // zout.closeEntry(); // zout.close(); bin.close(); try { dbFile.delete(); } catch (Exception e) { LOGGER.log(Level.WARNING, "Error deleting file: " + dbFile.getAbsolutePath(), e); } } }; result.setContentDispositionHeader(map, ".gpkg", true); return result; }