/*
* Geotoolkit - An Open Source Java GIS Toolkit
* http://www.geotoolkit.org
*
* (C) 2016, Geomatys
*
* 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.geotoolkit.coverage.landsat;
import java.io.IOException;
import java.net.URI;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.ParseException;
import org.opengis.metadata.Metadata;
import org.opengis.parameter.ParameterValueGroup;
import org.opengis.util.FactoryException;
import org.apache.sis.storage.DataStoreException;
import org.geotoolkit.storage.DataNode;
import org.geotoolkit.storage.DefaultDataNode;
import org.geotoolkit.storage.coverage.AbstractCoverageStore;
import org.geotoolkit.storage.coverage.CoverageStoreFactory;
import org.geotoolkit.storage.coverage.CoverageType;
import org.geotoolkit.util.NamesExt;
import org.geotoolkit.utility.parameter.ParametersExt;
import static org.geotoolkit.coverage.landsat.LandsatConstants.*;
import org.geotoolkit.storage.DataStores;
/**
* Store adapted to Landsat 8 comportement.
*
* @author Remi Marechal (Geomatys)
* @version 1.0
* @since 1.0
*/
public class LandsatCoverageStore extends AbstractCoverageStore {
private final DataNode root = new DefaultDataNode();
/**
* The current parent landsat8 directory.
*/
private final Path origin;
/**
* Parset to convert file metadata into {@link Metadata}.
*
* @see LandsatMetadataParser
*/
private final LandsatMetadataParser metadataParser;
/**
* DirectoryStream.Filter on metadata files.
*/
public static final DirectoryStream.Filter<Path> METADATA_FILTER = new DirectoryStream.Filter<Path>() {
@Override
public boolean accept(Path entry) throws IOException {
return entry.getFileName().toString().toLowerCase().endsWith("mtl.txt");
}
};
/**
*
* @param path
* @throws DataStoreException
*/
public LandsatCoverageStore(Path path) throws DataStoreException {
this(toParameters(path.toUri()));
}
/**
*
* @param path
* @throws DataStoreException
*/
public LandsatCoverageStore(URI uri) throws DataStoreException {
this(toParameters(uri));
}
/**
* Build Landsat Coverage store from params.<br>
*
* Params must contain path to find data and metadata path.
*
* @param params
* @throws DataStoreException
*/
public LandsatCoverageStore(ParameterValueGroup params)
throws DataStoreException {
super(params);
final Object uri = ParametersExt.getOrCreateValue(params, LandsatStoreFactory.PATH.getName().getCode()).getValue();
final Path path;
if (uri != null) {
path = Paths.get((URI) uri);
} else {
throw new DataStoreException("Landsat8 store : path must be setted.");
}
//-- add 3 Coverage References : REFLECTIVE, PANCHROMATIQUE, THERMIC.
metadataParser = getMetadataParser(path);
origin = metadataParser.getPath().getParent();
final String sceneName = getSceneName();
final LandsatCoverageReference reflectiveRef = new LandsatCoverageReference(this, NamesExt.create(getDefaultNamespace(),
sceneName+"-"+REFLECTIVE_LABEL), origin, metadataParser);
root.getChildren().add(reflectiveRef);
final LandsatCoverageReference panchroRef = new LandsatCoverageReference(this, NamesExt.create(getDefaultNamespace(),
sceneName+"-"+PANCHROMATIC_LABEL), origin, metadataParser);
root.getChildren().add(panchroRef);
final LandsatCoverageReference thermicRef = new LandsatCoverageReference(this, NamesExt.create(getDefaultNamespace(),
sceneName+"-"+THERMAL_LABEL), origin, metadataParser);
root.getChildren().add(thermicRef);
}
/**
* Set current URL into {@link ParameterValueGroup}.
*
* @param url Landsat 8 path.
* @return
*/
private static ParameterValueGroup toParameters(URI uri) {
final ParameterValueGroup params = LandsatStoreFactory.PARAMETERS_DESCRIPTOR.createValue();
ParametersExt.getOrCreateValue(params, LandsatStoreFactory.PATH.getName().getCode()).setValue(uri);
return params;
}
/**
* {@inheritDoc }.
*/
@Override
public DataNode getRootNode() throws DataStoreException {
return root;
}
/**
* {@inheritDoc }.
*/
@Override
public CoverageStoreFactory getFactory() {
return (CoverageStoreFactory) DataStores.getFactoryById(LandsatStoreFactory.NAME);
}
/**
* {@inheritDoc }.
*/
@Override
public CoverageType getType() {
return CoverageType.GRID;
}
/**
* {@inheritDoc }.
*/
@Override
public void close() throws DataStoreException {
//-- close nothing
}
/**
* {@inheritDoc }
* Moreover, the returned metadata are the globales metadatas for Landsat.
* {@link #getMetadata(java.lang.String) } with the groupname {@link LandsatConstants#GENERAL_LABEL}.
*
* @return Metadata for all Landsat8 coverage types.
* @throws DataStoreException
*/
@Override
public Metadata getMetadata() throws DataStoreException {
try {
return metadataParser.getMetadata(GENERAL_LABEL);
} catch (FactoryException | ParseException ex) {
throw new DataStoreException(ex);
}
}
//**************************************************************************//
//********** added methods only effectives for Landsat utilisation *********//
//**************************************************************************//
/**
* Returns part of {@linkplain #getMetadata() global Landsat 8 metadatas},
* in relation with only Landsat 8 group name datas.
* The valid group name are {@link LandsatConstants#GENERAL_LABEL},
* {@link LandsatConstants#REFLECTIVE_LABEL},
* {@link LandsatConstants#PANCHROMATIC_LABEL},
* {@link LandsatConstants#THERMAL_LABEL}.
*
* @return Reflective Landsat 8 metadatas.
* @throws DataStoreException
*/
public Metadata getMetadata(String groupNameLabel) throws DataStoreException {
try {
return metadataParser.getMetadata(REFLECTIVE_LABEL);
} catch (FactoryException | ParseException ex) {
throw new DataStoreException(ex);
}
}
/**
* Returns Landsat datas name from theirs metadatas.
* May return null if the Landsat scene doesn't own name.
*
* @return Landsat metadata name if exist, else return {@code null}.
*/
public String getSceneName() {
return metadataParser.getValue(false, SCENE_ID);
}
/**
* Search into current directory or file stipulate by path and return {@link LandsatMetadataParser}.
*
* @param landsatPath
* @return the found Landsat metadata path.
* @throws DataStoreException if impossible to found metadata file.
*/
private LandsatMetadataParser getMetadataParser(final Path landsatPath)
throws DataStoreException {
try {
if (Files.isDirectory(landsatPath)) {
//search metadata file
try (DirectoryStream<Path> stream = Files.newDirectoryStream(landsatPath, METADATA_FILTER)) {
for (Path candidate : stream) {
//will throw IOException if metadata not valid
return createMetadataParser(candidate);
}
}
} else {
return createMetadataParser(landsatPath);
}
} catch (IOException ex) {
throw new DataStoreException(ex);
}
throw new DataStoreException("Impossible to find Metadata file for Landsat from Path : "+landsatPath);
}
/**
* Returns {@link LandsatMetadataParser} if given path is conform to be a Landsat metadata path (should finish by "_MTL.txt")
* and also check if the metadata file {@linkplain LandsatMetadataParser#isValid() is valid}.
*
* @param file studied metadata file
* @param isMandatory if {@link Path} is not conform and {@code true} then throw Exception whereas {@code false} will return {@code null}.
* @return {@link LandsatMetadataParser} if possible.
* @throws IOException if problem during parsing metadata.
* @throws DataStoreException if appropriate Landsat metadata file
*/
private LandsatMetadataParser createMetadataParser(final Path file) throws IOException, DataStoreException {
if (METADATA_FILTER.accept(file)) {
//-- return terminate if the file is valid.
final LandsatMetadataParser parser = new LandsatMetadataParser(file);
if (parser.isValid())
return parser;
}
throw new DataStoreException("Invalid metadata file :"+file.toString());
}
}