/* (c) 2014 Open Source Geospatial Foundation - all rights reserved * (c) 2001 - 2013 OpenPlans * This code is licensed under the GPL 2.0 license, available at the root * application directory. */ package org.geoserver.importer.mosaic; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FilenameFilter; import java.io.IOException; import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Properties; import java.util.logging.Logger; import org.apache.commons.io.FilenameUtils; import org.apache.commons.io.IOUtils; import org.geotools.data.DataUtilities; import org.geotools.data.FeatureWriter; import org.geotools.data.Transaction; import org.geotools.data.directory.DirectoryDataStore; import org.geotools.data.shapefile.ShapefileDataStore; import org.geotools.data.shapefile.ShapefileDataStoreFactory; import org.geotools.data.shapefile.files.ShpFileType; import org.geotools.data.simple.SimpleFeatureStore; import org.geotools.feature.simple.SimpleFeatureTypeBuilder; import org.geotools.gce.imagemosaic.ImageMosaicConfigHandler; import org.geotools.gce.imagemosaic.ImageMosaicFormat; import org.geotools.gce.imagemosaic.ImageMosaicReader; import org.geotools.gce.imagemosaic.Utils; import org.geotools.geometry.Envelope2D; import org.geotools.geometry.jts.JTS; import org.geotools.util.logging.Logging; import org.opengis.feature.simple.SimpleFeature; import org.opengis.feature.simple.SimpleFeatureType; import org.opengis.geometry.BoundingBox; import org.opengis.referencing.crs.CoordinateReferenceSystem; import com.google.common.base.Predicate; import com.google.common.collect.Iterators; import com.google.common.io.Files; import com.vividsolutions.jts.geom.Polygon; /** * Helper to write out mosaic index shapefile and properties files. * * @author Justin Deoliveira, OpenGeo */ public class MosaicIndex { static Logger LOGGER = Logging.getLogger(MosaicIndex.class); Mosaic mosaic; public MosaicIndex(Mosaic mosaic) { this.mosaic = mosaic; } public File getFile() { return new File(mosaic.getFile(), mosaic.getName() + ".shp"); } public void delete() throws IOException { for (File f : mosaic.getFile().listFiles(new FilenameFilter() { @Override public boolean accept(File dir, String name) { if ("sample_image".equalsIgnoreCase(name)) { return true; } if (!mosaic.getName().equalsIgnoreCase(FilenameUtils.getBaseName(name))) { return false; } String ext = FilenameUtils.getExtension(name); ShpFileType shpFileType = null; if (ext != null) { try { shpFileType = ShpFileType.valueOf(ext.toUpperCase()); } catch (IllegalArgumentException iae) { // the extension is not matching } } return "properties".equalsIgnoreCase(ext) || shpFileType != null; } })) { if (!f.delete()) { // throwing exception here caused sporadic test failures on // windows related to file locking but only in the cleanup // method SystemTestData.tearDown LOGGER.warning("unable to delete mosaic file " + f.getAbsolutePath()); } } } public void write() throws IOException { //delete if already exists delete(); Collection<Granule> granules = mosaic.granules(); if (granules.isEmpty()) { LOGGER.warning("No granules in mosaic, nothing to write"); return; } Granule first = Iterators.find(granules.iterator(), new Predicate<Granule>() { @Override public boolean apply(Granule input) { return input.getEnvelope() != null && input.getEnvelope().getCoordinateReferenceSystem() != null; } }); if (first == null) { throw new IOException("Unable to determine CRS for mosaic"); } Envelope2D envelope = new Envelope2D(first.getEnvelope()); //create index schema SimpleFeatureTypeBuilder typeBuilder = new SimpleFeatureTypeBuilder(); typeBuilder.setName(mosaic.getName()); typeBuilder.setCRS(envelope.getCoordinateReferenceSystem()); typeBuilder.add("the_geom", Polygon.class); typeBuilder.add("location", String.class); if (mosaic.getTimeMode() != TimeMode.NONE) { typeBuilder.add("time", Date.class); } // tell image mosaic to use the index file we are creating File indexerFile = new File(mosaic.getFile(), "indexer.properties"); Properties indexer = new Properties(); indexer.put(Utils.Prop.NAME, mosaic.getName()); indexer.put(Utils.Prop.INDEX_NAME, mosaic.getName()); indexer.put(Utils.Prop.USE_EXISTING_SCHEMA, "true"); FileOutputStream ifos = null; try { ifos = new FileOutputStream(indexerFile); indexer.store(ifos, null); } finally { IOUtils.closeQuietly(ifos); } //create a new shapefile feature store ShapefileDataStoreFactory shpFactory = new ShapefileDataStoreFactory(); DirectoryDataStore dir = new DirectoryDataStore(mosaic.getFile(), new ShapefileDataStoreFactory.ShpFileStoreFactory(shpFactory, new HashMap())); try { dir.createSchema(typeBuilder.buildFeatureType()); FeatureWriter<SimpleFeatureType, SimpleFeature> w = dir.getFeatureWriterAppend(mosaic.getName(), Transaction.AUTO_COMMIT); try { for (Granule g : mosaic.granules()) { if (g.getEnvelope() == null) { LOGGER.warning("Skipping " + g.getFile().getAbsolutePath() + ", no envelope"); } SimpleFeature f = w.next(); f.setDefaultGeometry(JTS.toGeometry((BoundingBox)g.getEnvelope())); f.setAttribute("location", g.getFile().getName()); if (mosaic.getTimeMode() != TimeMode.NONE) { f.setAttribute("time", g.getTimestamp()); } w.write(); //track total bounds envelope.include(g.getEnvelope()); } } finally { w.close(); } } finally { dir.dispose(); } // have the image mosaic write the property file ImageMosaicFormat format = new ImageMosaicFormat(); ImageMosaicReader reader = format.getReader(mosaic.getFile()); reader.dispose(); // if we have to add the time, do so now if (mosaic.getTimeMode() != TimeMode.NONE) { File propertyFile = new File(mosaic.getFile(), mosaic.getName() + ".properties"); FileInputStream fis = null; FileOutputStream fos = null; try { fis = new FileInputStream(propertyFile); Properties props = new Properties(); props.load(fis); fis.close(); props.setProperty("TimeAttribute", "time"); fos = new FileOutputStream(propertyFile); props.store(fos, null); } finally { IOUtils.closeQuietly(fis); IOUtils.closeQuietly(fos); } } } }