/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2013 - 2016, Open Source Geospatial Foundation (OSGeo) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. */ package org.geotools.gce.imagemosaic; import java.io.File; import java.io.IOException; import java.util.logging.Level; import java.util.logging.Logger; import org.geotools.data.Query; import org.geotools.data.simple.SimpleFeatureCollection; import org.geotools.data.simple.SimpleFeatureIterator; import org.geotools.gce.imagemosaic.Utils.Prop; import org.geotools.gce.imagemosaic.catalog.GranuleCatalog; import org.opengis.feature.simple.SimpleFeature; import org.opengis.feature.simple.SimpleFeatureType; /** * This class is responsible for walking through the target schema and check all the located granules. * * <p> * Its role is basically to simplify the construction of the mosaic by implementing a visitor pattern for the files that we have to use for the index. * * * @author Carlo Cancellieri - GeoSolutions SAS * * @TODO check the schema structure * */ class ImageMosaicDatastoreWalker extends ImageMosaicWalker { /** Default Logger * */ final static Logger LOGGER = org.geotools.util.logging.Logging .getLogger(ImageMosaicDatastoreWalker.class); /** * @param updateFeatures if true update catalog with loaded granules * @param imageMosaicConfigHandler TODO */ public ImageMosaicDatastoreWalker(ImageMosaicConfigHandler configHandler, ImageMosaicEventHandlers eventHandler) { super(configHandler, eventHandler); } /** * run the walker on the store */ public void run() { SimpleFeatureIterator it = null; try { configHandler.indexingPreamble(); startTransaction(); // start looking into catalog final GranuleCatalog catalog = configHandler.getCatalog(); String locationAttrName = configHandler.getRunConfiguration() .getParameter(Prop.LOCATION_ATTRIBUTE); String requestedTypeName = configHandler.getRunConfiguration() .getParameter(Prop.TYPENAME); String location = configHandler.getRunConfiguration() .getParameter(Prop.LOCATION_ATTRIBUTE); for (String typeName : catalog.getTypeNames()) { if (requestedTypeName != null && !requestedTypeName.equals(typeName)) { continue; } if (!Utils.isValidMosaicSchema(catalog.getType(typeName), location)) { LOGGER.log(Level.FINE, "Skipping invalid mosaic index table " + typeName); continue; } // how many rows for this feature type? final Query query = new Query(typeName); int numFiles = catalog.getGranulesCount(query); if (numFiles <= 0) { // empty table? LOGGER.log(Level.FINE, "No rows in the typeName: " + typeName); continue; } setNumFiles(numFiles); // cool, now let's walk over the features final SimpleFeatureCollection coll = catalog.getGranules(query); SimpleFeatureType schema = coll.getSchema(); if (schema.getDescriptor(locationAttrName) == null) { LOGGER.fine("Skipping feature type " + typeName + " as the location attribute " + locationAttrName + " is not part of the schema"); continue; } else if (schema.getGeometryDescriptor() == null) { LOGGER.fine("Skipping feature type " + typeName + " as it does not have a footprint column"); continue; } // create an iterator it = coll.features(); // TODO setup index name while (it.hasNext()) { // get next element final SimpleFeature feature = it.next(); Object locationAttrObj = feature.getAttribute(locationAttrName); File file = null; if (locationAttrObj instanceof String) { final String path = (String) locationAttrObj; if (Boolean.getBoolean(configHandler.getRunConfiguration() .getParameter(Prop.ABSOLUTE_PATH))) { // absolute files file = new File(path); // check this is _really_ absolute if (!checkFile(file)) { file = null; } } if (file == null) { // relative files file = new File(configHandler.getRunConfiguration() .getParameter(Prop.ROOT_MOSAIC_DIR), path); // check this is _really_ relative if (!(file.exists() && file.canRead() && file.isFile())) { // let's try for absolute, despite what the config says // absolute files file = new File(path); // check this is _really_ absolute if (!(checkFile(file))) { file = null; } } } // final check if (file == null) { // SKIP and log // empty table? super.skipFile(path); continue; } } else if (locationAttrObj instanceof File) { file = (File) locationAttrObj; } else { eventHandler.fireException(new IOException( "Location attribute type not recognized for column name: " + locationAttrName)); stop(); break; } // process this file handleFile(file); } } // next table // close transaction // did we cancel? if (getStop()) { rollbackTransaction(); } else { commitTransaction(); } } catch (Exception e) { LOGGER.log(Level.WARNING, "Failure occurred while collecting the granules", e); try { rollbackTransaction(); } catch (IOException e1) { throw new IllegalStateException(e1); } } finally { // close read iterator if (it != null) { try { it.close(); } catch (Exception e) { LOGGER.log(Level.FINE, e.getLocalizedMessage(), e); } } // close transaction try { closeTransaction(); } catch (Exception e) { final String message = "Unable to close indexing" + e.getLocalizedMessage(); if (LOGGER.isLoggable(Level.WARNING)) { LOGGER.log(Level.WARNING, message, e); } // notify listeners eventHandler.fireException(e); } // close indexing try { configHandler.indexingPostamble(!getStop()); } catch (Exception e) { final String message = "Unable to close indexing" + e.getLocalizedMessage(); if (LOGGER.isLoggable(Level.WARNING)) { LOGGER.log(Level.WARNING, message, e); } // notify listeners eventHandler.fireException(e); } } } }