/* * 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.constellation.coverage.process.StyledPyramidCoverageDescriptor.STYLE; 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.Set; import java.util.logging.Level; import javax.xml.namespace.QName; import org.apache.sis.storage.DataStore; import org.apache.sis.storage.DataStoreException; import org.constellation.business.IStyleBusiness; import org.constellation.configuration.DataBrief; import org.constellation.configuration.TargetNotFoundException; 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.process.StyleProcessReference; import org.constellation.provider.DataProvider; import org.constellation.provider.DataProviders; import org.constellation.provider.Providers; 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.map.CoverageMapLayer; import org.geotoolkit.map.MapBuilder; import org.geotoolkit.map.MapContext; 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.PyramidalCoverageReference; import org.geotoolkit.style.MutableStyle; 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; import org.springframework.beans.factory.annotation.Autowired; /** * * @author Guilhem Legal (Geomatys) * @author Quentin Boileau (Geomatys) */ public class StyledPyramidCoverageProcess extends AbstractPyramidCoverageProcess { @Autowired private IStyleBusiness styleBusiness; public StyledPyramidCoverageProcess(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 * @param styleRef */ public StyledPyramidCoverageProcess (final CoverageReference inCoverageRef, final Data orinigalData, final String pyramidName, final String providerID, final File pyramidFolder, final Dataset dataset, final CoordinateReferenceSystem[] pyramidCRS, final StyleProcessReference styleRef, final Boolean updatePyramid) { this(StyledPyramidCoverageDescriptor.INSTANCE, toParameters(inCoverageRef, orinigalData, pyramidName, providerID, pyramidFolder, dataset, pyramidCRS, styleRef, 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 StyleProcessReference styleRef, final Boolean updatePyramid){ final ParameterValueGroup params = StyledPyramidCoverageDescriptor.INSTANCE.getInputDescriptor().createValue(); fillParameters(inCoverageRef, orinigalData, pyramidName, providerID, pyramidFolder, dataset, pyramidCRS, updatePyramid, params); getOrCreate(STYLE, params).setValue(styleRef); 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); final StyleProcessReference styleRef = value(STYLE, 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; 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; } try { final Set<GenericName> names = outputCoverageStore.getNames(); referenceName = NamesExt.create(namespace, pyramidName); final CoverageReference coverageReference; if (names.contains(referenceName)) { coverageReference = outputCoverageStore.getCoverageReference(referenceName); } else { coverageReference = outputCoverageStore.create(referenceName); } if (!(coverageReference instanceof PyramidalCoverageReference)) { throw new ProcessException("Provider "+providerID+" don't store pyramidal coverages.", this, null); } } catch (DataStoreException e) { throw new ProcessException(e.getMessage(), this, e); } } 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); } } //get layer style final MutableStyle style; try { style = styleBusiness.getStyle(styleRef.getId()); } catch (TargetNotFoundException ex) { throw new ProcessException("Style not found: " + ex.getMessage(), this, ex); } //build pyramid try { 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; for (CoordinateReferenceSystem pyramidCRS2D : pyramidCRSs) { final PyramidalCoverageReference outCovRef = (PyramidalCoverageReference) getOrCreateCRef((XMLCoverageStore) outputCoverageStore, referenceName, PNG_FORMAT, ViewType.RENDERED); final double[] scales = getPyramidScales((GridCoverage2D) coverage, outCovRef, pyramidCRS2D); final Envelope finalPyramidEnv = getFixedPyramidEnvelop(pyramidCRS2D, coverage.getEnvelope()); pyramidStyledData(inCovRef, finalPyramidEnv, scales, outCovRef, style, update); } } catch (DataStoreException | FactoryException | OutOfDomainOfValidityException | TransformException 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 a mapcontext with our input coverage and pyramid it into output Pyramidal CoverageStore * @param reference * @param dataEnv * @param scales * @param outputRef * @param style * @throws ProcessException */ private void pyramidStyledData(CoverageReference reference, Envelope dataEnv, double[] scales, PyramidalCoverageReference outputRef, MutableStyle style, boolean update) throws ProcessException { final MapContext context = MapBuilder.createContext(); final CoverageMapLayer layer = MapBuilder.createCoverageLayer(reference, style); context.items().add(layer); final ProcessDescriptor desc; try { desc = ProcessFinder.getProcessDescriptor("engine2d", "mapcontextpyramid"); } catch (NoSuchIdentifierException ex) { Providers.LOGGER.log(Level.WARNING, ex.getMessage(), ex); throw new ProcessException("Process engine2d.mapcontextpyramid not found "+ex.getMessage(), this, ex); } final ParameterValueGroup input = desc.getInputDescriptor().createValue(); input.parameter("context").setValue(context); input.parameter("extent").setValue(dataEnv); input.parameter("tilesize").setValue(new Dimension(TILE_SIZE, TILE_SIZE)); input.parameter("scales").setValue(scales); input.parameter("container").setValue(outputRef); input.parameter("update").setValue(update); final org.geotoolkit.process.Process p = desc.createProcess(input); p.call(); } }