package org.constellation.admin; import static org.geotoolkit.parameter.Parameters.getOrCreate; import java.awt.Dimension; import java.io.File; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.UUID; import java.util.logging.Level; import java.util.logging.Logger; import javax.inject.Inject; import javax.xml.namespace.QName; import org.apache.sis.geometry.GeneralDirectPosition; import org.apache.sis.storage.DataStoreException; import org.apache.sis.util.logging.Logging; import org.constellation.admin.exception.ConstellationException; import org.constellation.admin.util.IOUtilities; import org.constellation.api.ProviderType; import org.constellation.business.IDataBusiness; import org.constellation.business.IProcessBusiness; import org.constellation.business.IProviderBusiness; import org.constellation.configuration.ConfigDirectory; import org.constellation.configuration.ConfigurationException; import org.constellation.configuration.CstlConfigurationRuntimeException; import org.constellation.configuration.DataBrief; import org.constellation.configuration.ProviderConfiguration; import org.constellation.dto.ProviderPyramidChoiceList; import org.constellation.database.api.jooq.tables.pojos.CstlUser; import org.constellation.database.api.jooq.tables.pojos.Provider; import org.constellation.database.api.jooq.tables.pojos.Style; import org.constellation.database.api.jooq.tables.pojos.TaskParameter; import org.constellation.database.api.repository.ProviderRepository; import org.constellation.database.api.repository.UserRepository; import org.constellation.provider.CoverageData; import org.constellation.provider.DataProvider; import org.constellation.provider.DataProviderFactory; import org.constellation.provider.DataProviders; import org.constellation.provider.configuration.ProviderParameters; import org.constellation.util.ParamUtilities; import org.geotoolkit.coverage.GridSampleDimension; import org.geotoolkit.coverage.grid.GeneralGridGeometry; import org.geotoolkit.coverage.grid.ViewType; import org.geotoolkit.coverage.io.CoverageStoreException; import org.geotoolkit.coverage.io.GridCoverageReader; import org.geotoolkit.coverage.xmlstore.XMLCoverageReference; import org.geotoolkit.coverage.xmlstore.XMLCoverageStore; import org.geotoolkit.coverage.xmlstore.XMLCoverageStoreFactory; import org.geotoolkit.data.FeatureStoreFactory; import org.geotoolkit.data.FeatureStoreFinder; import org.geotoolkit.data.FileFeatureStoreFactory; import org.geotoolkit.image.interpolation.InterpolationCase; import org.geotoolkit.observation.ObservationStoreFactory; import org.geotoolkit.parameter.Parameters; import org.geotoolkit.process.Process; import org.geotoolkit.process.ProcessDescriptor; import org.geotoolkit.process.ProcessFinder; import org.geotoolkit.storage.DataStoreFactory; import org.geotoolkit.util.FileUtilities; import org.geotoolkit.utility.parameter.ParametersExt; import org.opengis.geometry.Envelope; import org.opengis.metadata.Identifier; import org.opengis.parameter.GeneralParameterValue; import org.opengis.parameter.ParameterDescriptorGroup; import org.opengis.parameter.ParameterValue; import org.opengis.parameter.ParameterValueGroup; import org.opengis.util.NoSuchIdentifierException; import org.springframework.context.annotation.Primary; import org.springframework.stereotype.Component; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.support.TransactionCallback; import com.google.common.base.Optional; import java.net.URISyntaxException; import org.geotoolkit.util.NamesExt; import org.geotoolkit.storage.coverage.CoverageReference; import org.geotoolkit.storage.coverage.CoverageStoreFactory; import org.geotoolkit.storage.coverage.CoverageStoreFinder; import org.geotoolkit.storage.coverage.CoverageUtilities; import org.geotoolkit.storage.coverage.Pyramid; import org.geotoolkit.storage.coverage.PyramidalCoverageReference; import org.opengis.util.GenericName; @Component("providerBusiness") @Primary public class ProviderBusiness implements IProviderBusiness { private static final Logger LOGGER = Logging.getLogger("org.constellation.admin"); /** * Identifier of the possible provider types. * @deprecated Used for current provider management mechanism. Removed when providers will be simplified in * DataStoreSource. */ static enum SPI_NAMES { COVERAGE_SPI_NAME("coverage-store"), FEATURE_SPI_NAME("feature-store"), OBSERVATION_SPI_NAME("observation-store"); public final String name; private SPI_NAMES(final String providerSPIName) { name = providerSPIName; } } private static final String CONFORM_PREFIX = "conform_"; @Inject private UserRepository userRepository; @Inject private ProviderRepository providerRepository; @Inject private org.constellation.security.SecurityManager securityManager; @Inject private IDataBusiness dataBusiness; @Inject private IProcessBusiness processBusiness; @Override public List<Provider> getProviders() { return providerRepository.findAll(); } @Override public Provider getProvider(final String identifier) { return providerRepository.findByIdentifier(identifier); } @Override public Provider getProvider(final int id) { return providerRepository.findOne(id); } @Override public List<String> getProviderIds() { final List<String> ids = new ArrayList<>(); final List<Provider> providers = providerRepository.findAll(); for (Provider p : providers) { ids.add(p.getIdentifier()); } return ids; } @Override @Transactional public void removeProvider(final String identifier) { providerRepository.deleteByIdentifier(identifier); } @Override @Transactional public void removeAll() { final List<Provider> providers = providerRepository.findAll(); for (Provider p : providers) { final DataProvider dp = DataProviders.getInstance().getProvider(p.getIdentifier()); try{ DataProviders.getInstance().removeProvider(dp); }catch(ConfigurationException ex){ LOGGER.log(Level.WARNING,ex.getLocalizedMessage(),ex); } providerRepository.delete(p.getId()); final File provDir = ConfigDirectory.getDataIntegratedDirectory(p.getIdentifier()); FileUtilities.deleteDirectory(provDir); } } @Override public List<Provider> getProviderChildren(final String identifier) { return providerRepository.findChildren(identifier); } @Override public List<org.constellation.database.api.jooq.tables.pojos.Data> getDatasFromProviderId(Integer id) { return providerRepository.findDatasByProviderId(id); } @Override @Transactional public void updateParent(String providerIdentifier, String newParentIdentifier) { final Provider provider = getProvider(providerIdentifier); provider.setParent(newParentIdentifier); providerRepository.update(provider); } @Override public List<Style> getStylesFromProviderId(Integer providerId) { return providerRepository.findStylesByProviderId(providerId); } @Override @Transactional public Provider storeProvider(final String identifier, final String parent, final ProviderType type, final String serviceName, final GeneralParameterValue config) throws IOException { Provider provider = new Provider(); Optional<CstlUser> user = userRepository.findOne(securityManager.getCurrentUserLogin()); if (user.isPresent()) { provider.setOwner(user.get().getId()); } provider.setParent(parent); provider.setType(type.name()); provider.setConfig(IOUtilities.writeParameter(config)); provider.setIdentifier(identifier); // TODO very strange !!!! provider.setImpl(serviceName); return providerRepository.insert(provider); } @Override public Set<GenericName> test(final String providerIdentifier, final ProviderConfiguration configuration) throws DataStoreException, ConfigurationException { final String type = configuration.getType(); final String subType = configuration.getSubType(); final Map<String, String> inParams = configuration.getParameters(); final DataProviderFactory providerService = DataProviders.getInstance().getFactory(type); final ParameterDescriptorGroup sourceDesc = providerService.getProviderDescriptor(); ParameterValueGroup sources = sourceDesc.createValue(); sources.parameter("id").setValue(providerIdentifier); sources.parameter("providerType").setValue(type); sources = fillProviderParameter(type, subType, inParams, sources); return DataProviders.getInstance().testProvider(providerIdentifier, providerService, sources); } /** * {@inheritDoc} */ @Override @Transactional public Provider create(final String id, final DataStoreFactory spi, ParameterValueGroup spiConfiguration) throws ConfigurationException { if (getProvider(id) != null) { throw new ConfigurationException("A provider already exists for name "+id); } final String providerType; if (spi instanceof CoverageStoreFactory) { providerType = SPI_NAMES.COVERAGE_SPI_NAME.name; } else if (spi instanceof FeatureStoreFactory) { providerType = SPI_NAMES.FEATURE_SPI_NAME.name; } else if (spi instanceof ObservationStoreFactory) { providerType = SPI_NAMES.OBSERVATION_SPI_NAME.name; } else { throw new ConfigurationException("No provider can be created for following factory and parameters : " + spi.getDisplayName() + "\n"+spiConfiguration); } final DataProviderFactory pFactory = DataProviders.getInstance().getFactory(providerType); final ParameterValueGroup providerConfig = pFactory.getProviderDescriptor().createValue(); providerConfig.parameter("id").setValue(id); providerConfig.parameter("providerType").setValue(providerType); final ParameterValueGroup choice = providerConfig.groups("choice").get(0).addGroup(spiConfiguration.getDescriptor().getName().getCode()); org.apache.sis.parameter.Parameters.copy(spiConfiguration, choice); return create(id, pFactory.getName(), providerConfig); } /** * {@inheritDoc} */ @Override @Transactional public Provider create(final String id, final ProviderConfiguration config) throws ConfigurationException { final String type = config.getType(); final String subType = config.getSubType(); final Map<String,String> inParams = config.getParameters(); final DataProviderFactory providerService = DataProviders.getInstance().getFactory(type); final ParameterDescriptorGroup sourceDesc = providerService.getProviderDescriptor(); ParameterValueGroup sources = sourceDesc.createValue(); sources.parameter("id").setValue(id); sources.parameter("providerType").setValue(type); sources = fillProviderParameter(type, subType, inParams, sources); return create(id, providerService.getName(), sources); } /** * {@inheritDoc} */ @Override @Transactional public Provider create(final String id, final String providerSPIName, final ParameterValueGroup providerConfig) throws ConfigurationException { final DataProviderFactory providerSPI = DataProviders.getInstance().getFactory(providerSPIName); ///// // WARNING : createProvider() will create provider, data list and dataset records in repositories. ///// DataProviders.getInstance().createProvider(id, providerSPI, providerConfig, null); return getProvider(id); } @Override @Transactional public void update(final String id, final ProviderConfiguration config) throws ConfigurationException { final String type = config.getType(); final String subType = config.getSubType(); final Map<String, String> inParams = config.getParameters(); final DataProviderFactory providerService = DataProviders.getInstance().getFactory(type); final ParameterDescriptorGroup sourceDesc = providerService.getProviderDescriptor(); ParameterValueGroup sources = sourceDesc.createValue(); sources.parameter("id").setValue(id); sources.parameter("providerType").setValue(type); sources = fillProviderParameter(type, subType, inParams, sources); final DataProvider old = DataProviders.getInstance().getProvider(id); if (old != null) { // Provider already exists, update config old.updateSource(sources); } } protected ParameterValueGroup fillProviderParameter(String type, String subType, Map<String, String> inParams, ParameterValueGroup sources)throws ConfigurationException { if("sld".equals(type)){ final String sldPath = inParams.get("path"); String folderPath = sldPath.substring(0, sldPath.lastIndexOf('/')); sources.groups("sldFolder").get(0).parameter("path").setValue(folderPath); }else if("observation-store".equals(type)){ switch (subType) { // TODO : Remove this hacky switch / case when input map will have the right identifier for url parameter. case "observation-file": final ParameterValueGroup ncObsParams = sources.groups("choice").get(0).addGroup("ObservationFileParameters"); ncObsParams.parameter("identifier").setValue("observationFile"); ncObsParams.parameter("namespace").setValue("no namespace"); ncObsParams.parameter("url").setValue(new File(inParams.get("path"))); break; case "observation-xml": final ParameterValueGroup xmlObsParams = sources.groups("choice").get(0).addGroup("ObservationXmlFileParameters"); xmlObsParams.parameter("identifier").setValue("observationXmlFile"); xmlObsParams.parameter("namespace").setValue("no namespace"); xmlObsParams.parameter("url").setValue(new File(inParams.get("path"))); break; default: LOGGER.log(Level.WARNING, "error on subtype definition"); } } //url parameter is sometimes named path String path = inParams.get("path"); String url = inParams.get("url"); if(path!=null && url==null) url = path; if(path==null && url!=null) path = url; //try to fix path and url to valid urls path = toValidURL(path); url = toValidURL(url); if(path!=null) inParams.put("path", path); if(url!=null) inParams.put("url", url); if("feature-store".equals(type)){ boolean foundProvider = false; try { URL rurl = path==null ? null : new URL(path); if (rurl != null) { final File file = new File(rurl.toURI()); final File[] candidates; if (file.isDirectory()) { candidates = file.listFiles(); } else { candidates = new File[]{file}; } Arrays.sort(candidates); search: for (File candidate : candidates) { final String candidateName = candidate.getName().toLowerCase(); //loop on features file factories final Iterator<FeatureStoreFactory> ite = FeatureStoreFinder.getAllFactories(null).iterator(); while (ite.hasNext()) { final FeatureStoreFactory factory = ite.next(); if (factory instanceof FileFeatureStoreFactory) { final FileFeatureStoreFactory fileFactory = (FileFeatureStoreFactory) factory; for (String tempExtension : fileFactory.getFileExtensions()) { if (candidateName.endsWith(tempExtension) && !tempExtension.endsWith("dbf")) { //found a factory which can handle it final ParameterValueGroup params = sources.groups("choice").get(0).addGroup( factory.getParametersDescriptor().getName().getCode()); if(candidates.length>1 && file.isDirectory()){ rurl = new URL(rurl.toString()+candidateName); } params.parameter("url").setValue(rurl); params.parameter("namespace").setValue("no namespace"); foundProvider = true; break search; } } } else { final ParameterValueGroup testParams = factory.getParametersDescriptor().createValue(); try { testParams.parameter("namespace").setValue("no namespace"); final ParameterValue pv = ParametersExt.getOrCreateValue(testParams, "url"); pv.setValue(rurl); if (factory.canProcess(testParams)) { final ParameterValueGroup params = sources.groups("choice").get(0).addGroup( factory.getParametersDescriptor().getName().getCode()); params.parameter("url").setValue(rurl); params.parameter("namespace").setValue("no namespace"); foundProvider = true; break search; } } catch (Exception ex) { //parameter might not exist } } } } } if (subType!=null && !subType.isEmpty()) { final FeatureStoreFactory featureFactory = FeatureStoreFinder.getFactoryById(subType); final ParameterValueGroup cvgConfig = Parameters.toParameter(inParams, featureFactory.getParametersDescriptor(), true); final ParameterValueGroup choice = ParametersExt.getOrCreateGroup(sources.groups("choice").get(0),cvgConfig.getDescriptor().getName().getCode()); ParametersExt.deepCopy(cvgConfig, choice); foundProvider = true; } if(!foundProvider) { throw new ConfigurationException("No provider found to resolve the data!"); } } catch (MalformedURLException e) { LOGGER.log(Level.WARNING, "unable to create url from path", e); } catch (URISyntaxException e) { LOGGER.log(Level.WARNING, "unable to create url from path", e); } }else if("coverage-store".equals(type)){ final CoverageStoreFactory cvgFactory = CoverageStoreFinder.getFactoryById(subType); final ParameterValueGroup cvgConfig = Parameters.toParameter(inParams, cvgFactory.getParametersDescriptor(), true); final ParameterValueGroup choice = sources.groups("choice").get(0).addGroup(cvgConfig.getDescriptor().getName().getCode()); org.apache.sis.parameter.Parameters.copy(cvgConfig, choice); } return sources; } private static String toValidURL(String candidate){ if(candidate==null) return candidate; try { new URL(candidate); } catch (MalformedURLException ex) { try { return new File(candidate).toURI().toURL().toString(); } catch (MalformedURLException ex1) { //we have try } } return candidate; } /** * {@inheritDoc} */ @Override public ProviderPyramidChoiceList listPyramids(final String id, final String layerName) throws DataStoreException { final ProviderPyramidChoiceList choices = new ProviderPyramidChoiceList(); final List<Provider> childrenRecs = getProviderChildren(id); for(Provider childRec : childrenRecs){ final DataProvider provider = DataProviders.getInstance().getProvider(childRec.getIdentifier()); final CoverageData cacheData = (CoverageData) provider.get(layerName); if(cacheData!=null){ final PyramidalCoverageReference cacheRef = (PyramidalCoverageReference) cacheData.getOrigin(); final Collection<Pyramid> pyramids = cacheRef.getPyramidSet().getPyramids(); if(pyramids.isEmpty()) continue; //TODO what do we do if there are more then one pyramid ? //it the current state of constellation there is only one pyramid final Pyramid pyramid = pyramids.iterator().next(); final Identifier crsid = pyramid.getCoordinateReferenceSystem().getIdentifiers().iterator().next(); final ProviderPyramidChoiceList.CachePyramid cache = new ProviderPyramidChoiceList.CachePyramid(); cache.setCrs(crsid.getCode()); cache.setScales(pyramid.getScales()); cache.setProviderId(provider.getId()); cache.setDataId(layerName); cache.setConform(childRec.getIdentifier().startsWith("conform_")); choices.getPyramids().add(cache); } } return choices; } /** * {@inheritDoc} */ @Override public DataBrief createPyramidConform(final String providerId, final String dataName, final String namespace, final int userOwnerId) throws ConstellationException { final QName qName = new QName(namespace, dataName); final DataBrief inData = dataBusiness.getDataBrief(qName, providerId); if (inData != null){ // Execute in transaction to ensure that taskParameter is in Database before run // process in Quartz scheduler. Map<String, Object> result = SpringHelper.executeInTransaction(new TransactionCallback<Map<String, Object>>() { @Override public Map<String, Object> doInTransaction(TransactionStatus transactionStatus) { return preparePyramidConform(inData, userOwnerId); } }); final DataBrief outData = (DataBrief) result.get("outData"); final Process process = (Process) result.get("process"); final Integer taskParameterId = (Integer) result.get("taskParameterId"); final String taskName = (String) result.get("taskName"); //run pyramid process in Quartz processBusiness.runProcess(taskName, process, taskParameterId, userOwnerId); return outData; } throw new ConstellationException("Data "+qName+" not found in provider identifier "+providerId); } /** * Prepare pyramid conform for a data. * This method should not be called alone, but before * {@link org.constellation.business.IProcessBusiness#runProcess(String, org.geotoolkit.process.Process, Integer, Integer)}. * * This method need to be called in a Transaction * * @param inData Data to pyramid * @param userOwnerId owner of the pyramid * @return a Map with : * <ul> * <li>"ouData" : new pyramid DataBrief</li> * <li>"process" : pyramid process to execute</li> * <li>"taskParameterId" : task parameter id linked to process</li> * <li>"taskName" : name of the task</li> * </ul> * @throws ConstellationException */ private Map<String, Object> preparePyramidConform(final DataBrief inData, final int userOwnerId) throws ConstellationException { final String dataName = inData.getName(); final String namespace = inData.getNamespace(); final String providerId = inData.getProvider(); final Integer datasetID = inData.getDatasetId(); GenericName name = NamesExt.create(namespace,dataName); //get data final DataProvider inProvider = DataProviders.getInstance().getProvider(providerId); if (inProvider == null) { throw new ConstellationException("Provider " + providerId + " does not exist"); } final org.constellation.provider.Data providerData = inProvider.get(name); if (providerData == null) { throw new ConstellationException("Data " + dataName + " does not exist in provider " + providerId); } Envelope dataEnv; try { //use data crs dataEnv = providerData.getEnvelope(); } catch (DataStoreException ex) { throw new ConstellationException("Failed to extract envelope for data " + dataName + ". " + ex.getMessage(),ex); } final Object origin = providerData.getOrigin(); if(!(origin instanceof CoverageReference)) { throw new ConstellationException("Cannot create pyramid conform for no raster data, it is not supported yet!"); } //init coverage reference and grid geometry final CoverageReference inRef = (CoverageReference) origin; final GeneralGridGeometry gg; try { final GridCoverageReader reader = inRef.acquireReader(); gg = reader.getGridGeometry(inRef.getImageIndex()); inRef.recycle(reader); } catch (CoverageStoreException ex) { throw new ConstellationException("Failed to extract grid geometry for data " + dataName + ". " + ex.getMessage(),ex); } //create the output folder for pyramid PyramidalCoverageReference outRef; final String pyramidProviderId = CONFORM_PREFIX + UUID.randomUUID().toString(); //create the output provider final DataProvider outProvider; final DataBrief pyramidDataBrief; try { //create the output folder for pyramid final File providerDirectory = ConfigDirectory.getDataIntegratedDirectory(providerId); final File pyramidDirectory = new File(providerDirectory, pyramidProviderId); pyramidDirectory.mkdirs(); final String namespaceToSend = namespace != null && ! namespace.isEmpty() ? namespace:"no namespace"; //create output store final ParameterValueGroup storeParams = XMLCoverageStoreFactory.PARAMETERS_DESCRIPTOR.createValue(); getOrCreate(XMLCoverageStoreFactory.NAMESPACE, storeParams).setValue(namespaceToSend); getOrCreate(XMLCoverageStoreFactory.PATH, storeParams).setValue(pyramidDirectory.toURI().toURL()); getOrCreate(XMLCoverageStoreFactory.CACHE_TILE_STATE, storeParams).setValue(true); XMLCoverageStore outStore = (XMLCoverageStore) CoverageStoreFinder.open(storeParams); if (outStore == null) { throw new ConstellationException("Failed to create pyramid layer "); } XMLCoverageReference covRef = (XMLCoverageReference)outStore.create(name, ViewType.GEOPHYSICS, "TIFF"); // create provider final DataProviderFactory factory = DataProviders.getInstance().getFactory("coverage-store"); final ParameterValueGroup pparams = factory.getProviderDescriptor().createValue(); ParametersExt.getOrCreateValue(pparams, ProviderParameters.SOURCE_ID_DESCRIPTOR.getName().getCode()).setValue(pyramidProviderId); ParametersExt.getOrCreateValue(pparams, ProviderParameters.SOURCE_TYPE_DESCRIPTOR.getName().getCode()).setValue("coverage-store"); final ParameterValueGroup choiceparams = ParametersExt.getOrCreateGroup(pparams, factory.getStoreDescriptor().getName().getCode()); final ParameterValueGroup xmlpyramidparams = ParametersExt.getOrCreateGroup(choiceparams, XMLCoverageStoreFactory.PARAMETERS_DESCRIPTOR.getName().getCode()); ParametersExt.getOrCreateValue(xmlpyramidparams, XMLCoverageStoreFactory.PATH.getName().getCode()).setValue(pyramidDirectory.toURI().toURL()); ParametersExt.getOrCreateValue(xmlpyramidparams, XMLCoverageStoreFactory.NAMESPACE.getName().getCode()).setValue(namespaceToSend); outProvider = DataProviders.getInstance().createProvider(pyramidProviderId, factory, pparams, datasetID); name = covRef.getName(); outStore = (XMLCoverageStore) outProvider.getMainStore(); outRef = (XMLCoverageReference) outStore.getCoverageReference(name); // Update the parent attribute of the created provider updateParent(outProvider.getId(), providerId); final QName qName = new QName(NamesExt.getNamespace(name), name.tip().toString()); //set rendered attribute to false to indicates that this pyramid can have stats. dataBusiness.updateDataRendered(qName, outProvider.getId(), false); //set hidden value to true for the pyramid conform data pyramidDataBrief = dataBusiness.getDataBrief(qName, pyramidProviderId); dataBusiness.updateHidden(pyramidDataBrief.getId(),true); } catch (Exception ex) { throw new ConstellationException("Failed to create pyramid provider " + ex.getMessage(),ex); } //get the fill value for no data try { final GridCoverageReader reader = inRef.acquireReader(); final List<GridSampleDimension> sampleDimensions = reader.getSampleDimensions(inRef.getImageIndex()); inRef.recycle(reader); if (sampleDimensions != null) { final int nbBand = sampleDimensions.size(); double[] fillValue = new double[nbBand]; Arrays.fill(fillValue, Double.NaN); for (int i = 0; i < nbBand; i++) { final double[] nodata = sampleDimensions.get(i).geophysics(true).getNoDataValues(); if (nodata != null && nodata.length > 0) { fillValue[i] = nodata[0]; } } } } catch (CoverageStoreException ex) { throw new ConstellationException("Failed to extract no-data values for resampling " + ex.getMessage(),ex); } //calculate scales final Map<Envelope, double[]> resolutionPerEnvelope = new HashMap<>(); final double geospanX = dataEnv.getSpan(0); final double baseScale = geospanX / gg.getExtent().getSpan(0); final int tileSize = 256; double scale = geospanX / tileSize; final GeneralDirectPosition ul = new GeneralDirectPosition(dataEnv.getCoordinateReferenceSystem()); ul.setOrdinate(0, dataEnv.getMinimum(0)); ul.setOrdinate(1, dataEnv.getMaximum(1)); final List<Double> scalesList = new ArrayList<>(); while (true) { if (scale <= baseScale) { //fit to exact match to preserve base quality. scale = baseScale; } scalesList.add(scale); if (scale <= baseScale) { break; } scale = scale / 2; } final double[] scales = new double[scalesList.size()]; for (int i = 0; i < scales.length; i++) scales[i] = scalesList.get(i); resolutionPerEnvelope.put(dataEnv, scales); //Prepare pyramid's mosaics. final Dimension tileDim = new Dimension(tileSize, tileSize); try { CoverageUtilities.getOrCreatePyramid(outRef, dataEnv, tileDim, scales); } catch (Exception ex) { throw new ConstellationException("Failed to create pyramid and mosaics in store " + ex.getMessage(),ex); } //prepare process final ProcessDescriptor desc; try { desc = ProcessFinder.getProcessDescriptor("coverage", "coveragepyramid"); } catch (NoSuchIdentifierException ex) { throw new ConstellationException("Process coverage.coveragepyramid not found " + ex.getMessage(),ex); } Map<String, Object> result = new HashMap<>(); result.put("outData", pyramidDataBrief); //add task in scheduler try { final ParameterValueGroup input = desc.getInputDescriptor().createValue(); input.parameter("coverageref").setValue(inRef); input.parameter("in_coverage_store").setValue(outRef.getStore()); input.parameter("tile_size").setValue(new Dimension(tileSize, tileSize)); input.parameter("pyramid_name").setValue(outRef.getName().tip().toString()); input.parameter("interpolation_type").setValue(InterpolationCase.NEIGHBOR); input.parameter("resolution_per_envelope").setValue(resolutionPerEnvelope); final org.geotoolkit.process.Process p = desc.createProcess(input); result.put("process", p); String taskName = "conform_pyramid_" + providerId + ":" + dataName + "_" + System.currentTimeMillis(); TaskParameter taskParameter = new TaskParameter(); taskParameter.setProcessAuthority(desc.getIdentifier().getAuthority().toString()); taskParameter.setProcessCode(desc.getIdentifier().getCode()); taskParameter.setDate(System.currentTimeMillis()); taskParameter.setInputs(ParamUtilities.writeParameterJSON(input)); taskParameter.setOwner(userOwnerId); taskParameter.setName(taskName); taskParameter.setType("INTERNAL"); taskParameter = processBusiness.addTaskParameter(taskParameter); result.put("taskParameterId", taskParameter.getId()); result.put("taskName", taskName); } catch ( IOException ex) { throw new ConstellationException("Unable to run pyramid process on scheduler",ex); } return result; } @Override public List<Integer> getProviderIdsAsInt() { final List<Integer> ids = new ArrayList<>(); final List<Provider> providers = providerRepository.findAll(); for (Provider p : providers) { ids.add(p.getId()); } return ids; } }