/* * Constellation - An open source and standard compliant SDI * http://www.constellation-sdi.org * * Copyright 2014 Geomatys. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.constellation.coverage.process; import static org.constellation.coverage.process.AbstractPyramidCoverageDescriptor.IN_COVERAGE_REF; import static org.constellation.coverage.process.AbstractPyramidCoverageDescriptor.ORIGINAL_DATA; import static org.constellation.coverage.process.AbstractPyramidCoverageDescriptor.OUT_PYRAMID_PROVIDER_CONF; import static org.constellation.coverage.process.AbstractPyramidCoverageDescriptor.PROVIDER_OUT_ID; import static org.constellation.coverage.process.AbstractPyramidCoverageDescriptor.PYRAMID_CRS; import static org.constellation.coverage.process.AbstractPyramidCoverageDescriptor.PYRAMID_DATASET; import static org.constellation.coverage.process.AbstractPyramidCoverageDescriptor.PYRAMID_FOLDER; import static org.constellation.coverage.process.AbstractPyramidCoverageDescriptor.PYRAMID_NAME; import static org.constellation.coverage.process.AbstractPyramidCoverageDescriptor.UPDATE; import static org.geotoolkit.parameter.Parameters.getOrCreate; import static org.geotoolkit.parameter.Parameters.value; import java.awt.Dimension; import java.io.File; import java.net.MalformedURLException; import java.util.HashMap; import java.util.Map; import javax.xml.namespace.QName; import org.apache.sis.storage.DataStore; import org.apache.sis.storage.DataStoreException; import org.constellation.configuration.DataBrief; import org.constellation.database.api.jooq.tables.pojos.Data; import org.constellation.database.api.jooq.tables.pojos.Dataset; import org.constellation.database.api.jooq.tables.pojos.Provider; import org.constellation.provider.DataProvider; import org.constellation.provider.DataProviders; import org.geotoolkit.coverage.GridCoverageStack; import org.geotoolkit.coverage.grid.GridCoverage2D; import org.geotoolkit.coverage.grid.ViewType; import org.geotoolkit.coverage.io.GridCoverageReadParam; import org.geotoolkit.coverage.io.GridCoverageReader; import org.geotoolkit.coverage.xmlstore.XMLCoverageStore; import org.geotoolkit.util.NamesExt; import org.geotoolkit.image.interpolation.InterpolationCase; import org.geotoolkit.process.ProcessDescriptor; import org.geotoolkit.process.ProcessException; import org.geotoolkit.process.ProcessFinder; import org.geotoolkit.referencing.OutOfDomainOfValidityException; import org.geotoolkit.storage.coverage.AbstractCoverageStoreFactory; import org.geotoolkit.storage.coverage.CoverageReference; import org.geotoolkit.storage.coverage.CoverageStore; import org.geotoolkit.storage.coverage.CoverageUtilities; import org.geotoolkit.storage.coverage.PyramidalCoverageReference; import org.opengis.coverage.grid.GridCoverage; import org.opengis.geometry.Envelope; import org.opengis.parameter.ParameterValueGroup; import org.opengis.referencing.crs.CoordinateReferenceSystem; import org.opengis.referencing.operation.TransformException; import org.opengis.util.FactoryException; import org.opengis.util.GenericName; import org.opengis.util.NoSuchIdentifierException; /** * Process that create a pyramid "conform" from a CoverageReference. * This pyramid will be defined on the validity domains of inputs {@code pyramidCRS}. * * @author Guilhem Legal (Geomatys) * @author Quentin Boileau (Geomatys) */ public class PyramidCoverageProcess extends AbstractPyramidCoverageProcess { public PyramidCoverageProcess(final ProcessDescriptor desc, final ParameterValueGroup parameter) { super(desc, parameter); } /** * Quick constructor to create process * * @param inCoverageRef * @param pyramidName * @param providerID * @param pyramidFolder * @param domain * @param dataset * @param pyramidCRS */ public PyramidCoverageProcess (final CoverageReference inCoverageRef, final Data orinigalData, final String pyramidName, final String providerID, final File pyramidFolder, final Dataset dataset, final CoordinateReferenceSystem[] pyramidCRS, final Boolean updatePyramid) { this(PyramidCoverageDescriptor.INSTANCE, toParameters(inCoverageRef, orinigalData, pyramidName, providerID, pyramidFolder, dataset, pyramidCRS, updatePyramid)); } private static ParameterValueGroup toParameters(final CoverageReference inCoverageRef, final Data orinigalData, final String pyramidName, final String providerID, final File pyramidFolder, final Dataset dataset, final CoordinateReferenceSystem[] pyramidCRS, final Boolean updatePyramid){ final ParameterValueGroup params = PyramidCoverageDescriptor.INSTANCE.getInputDescriptor().createValue(); fillParameters(inCoverageRef, orinigalData, pyramidName, providerID, pyramidFolder, dataset, pyramidCRS, updatePyramid, params); return params; } @Override protected void execute() throws ProcessException { final CoverageReference inCovRef = value(IN_COVERAGE_REF, inputParameters); final CoordinateReferenceSystem[] pyramidCRSs = value(PYRAMID_CRS, inputParameters); final Data originalData = value(ORIGINAL_DATA, inputParameters); final String providerID = value(PROVIDER_OUT_ID, inputParameters); final File pyramidFolder = value(PYRAMID_FOLDER, inputParameters); final Dataset dataset = value(PYRAMID_DATASET, inputParameters); String pyramidName = value(PYRAMID_NAME, inputParameters); Boolean update = value(UPDATE, inputParameters); if (update == null) { update = Boolean.FALSE; } if (pyramidName == null) { pyramidName = inCovRef.getName().tip().toString(); } Provider providerEntity = providerBusiness.getProvider(providerID); DataProvider dataProvider = null; CoverageStore outputCoverageStore = null; GenericName referenceName = null; //provider already exist -> try to get pyramid Reference if (providerEntity != null) { dataProvider = DataProviders.getInstance().getProvider(providerID); final DataStore mainStore = dataProvider.getMainStore(); if (!(mainStore instanceof CoverageStore)) { throw new ProcessException("Provider "+providerID+" reference a non coverage type store", this, null); } outputCoverageStore = (CoverageStore) mainStore; final ParameterValueGroup configuration = outputCoverageStore.getConfiguration(); String namespace = value(AbstractCoverageStoreFactory.NAMESPACE, configuration); // to avoid error on comparison if (namespace!= null && namespace.equals("no namespace")) { namespace = null; } referenceName = NamesExt.create(namespace, pyramidName); } if (outputCoverageStore == null) { //create XMLCoverageStore try { final File finalPyramidFolder = new File(pyramidFolder, pyramidName); referenceName = NamesExt.create(pyramidName); outputCoverageStore = getOrCreateXMLCoverageStore(finalPyramidFolder); } catch (DataStoreException | MalformedURLException e) { throw new ProcessException(e.getMessage(), this, e); } } //build pyramid final Dimension tileDim = new Dimension(TILE_SIZE, TILE_SIZE); try { final PyramidalCoverageReference outCovRef = (PyramidalCoverageReference) getOrCreateCRef((XMLCoverageStore)outputCoverageStore, referenceName, TIFF_FORMAT, ViewType.GEOPHYSICS); final GridCoverageReader reader = inCovRef.acquireReader(); final GridCoverageReadParam readParam = new GridCoverageReadParam(); readParam.setDeferred(true); final GridCoverage coverage = reader.read(inCovRef.getImageIndex(), readParam); inCovRef.recycle(reader); if (coverage instanceof GridCoverageStack) { throw new ProcessException("CoverageStack implementation not supported.", this, null); } final GridCoverage2D gridCoverage2D = (GridCoverage2D) coverage; final CoordinateReferenceSystem coverageCRS = gridCoverage2D.getCoordinateReferenceSystem(); final Map<Envelope, double[]> map = new HashMap<>(); for (CoordinateReferenceSystem pyramidCRS2D : pyramidCRSs) { final double[] scales = getPyramidScales(gridCoverage2D, outCovRef, pyramidCRS2D); final Envelope finalPyramidEnv = getFixedPyramidEnvelop(pyramidCRS2D, coverage.getEnvelope()); map.put(finalPyramidEnv, scales); //Prepare pyramid's mosaics. CoverageUtilities.getOrCreatePyramid(outCovRef, finalPyramidEnv, tileDim, scales); } pyramidData(inCovRef, outputCoverageStore, referenceName, map, tileDim, update); } catch (DataStoreException | FactoryException | TransformException | OutOfDomainOfValidityException e) { throw new ProcessException(e.getMessage(), this, e); } //finally create provider from store configuration if (dataProvider == null) { dataProvider = createProvider(providerID, outputCoverageStore, dataset.getId()); } if (providerEntity == null) { providerEntity = providerBusiness.getProvider(providerID); } // link original data with the tiled data. if (originalData != null) { final QName qName = new QName(NamesExt.getNamespace(referenceName), referenceName.tip().toString()); final DataBrief pyramidDataBrief = dataBusiness.getDataBrief(qName, providerEntity.getId()); dataBusiness.linkDataToData(originalData.getId(), pyramidDataBrief.getId()); } getOrCreate(OUT_PYRAMID_PROVIDER_CONF, outputParameters).setValue(dataProvider.getSource()); } /** * Create conform pyramid * @param inRef * @param outCoverageStore * @param outName * @param envScales * @param tileDim * @param update * @throws ProcessException */ private void pyramidData(CoverageReference inRef, CoverageStore outCoverageStore, GenericName outName, Map<Envelope, double[]> envScales, Dimension tileDim, Boolean update) throws ProcessException { final ProcessDescriptor desc; try { desc = ProcessFinder.getProcessDescriptor("coverage", "coveragepyramid"); } catch (NoSuchIdentifierException ex) { throw new ProcessException("Process coverage.coveragepyramid not found " + ex.getMessage(),this,ex); } final ParameterValueGroup input = desc.getInputDescriptor().createValue(); input.parameter("coverageref").setValue(inRef); input.parameter("in_coverage_store").setValue(outCoverageStore); input.parameter("tile_size").setValue(tileDim); input.parameter("pyramid_name").setValue(outName.tip().toString()); input.parameter("interpolation_type").setValue(InterpolationCase.NEIGHBOR); input.parameter("resolution_per_envelope").setValue(envScales); input.parameter("reuse_tiles").setValue(update); final org.geotoolkit.process.Process p = desc.createProcess(input); p.call(); } }