/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2007-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.imageio.netcdf; import java.io.File; import java.io.IOException; import java.io.Serializable; import java.net.URL; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; import javax.xml.bind.Marshaller; import javax.xml.bind.Unmarshaller; import org.apache.commons.io.FileUtils; import org.apache.commons.io.FilenameUtils; import org.geotools.coverage.grid.io.FileSetManager; import org.geotools.coverage.grid.io.FileSystemFileSetManager; import org.geotools.coverage.io.catalog.DataStoreConfiguration; import org.geotools.data.DataStoreFactorySpi; import org.geotools.feature.NameImpl; import org.geotools.gce.imagemosaic.Utils; import org.geotools.gce.imagemosaic.catalog.index.Indexer; import org.geotools.gce.imagemosaic.catalog.index.Indexer.Collectors; import org.geotools.gce.imagemosaic.catalog.index.Indexer.Collectors.Collector; import org.geotools.gce.imagemosaic.catalog.index.Indexer.Coverages; import org.geotools.gce.imagemosaic.catalog.index.Indexer.Coverages.Coverage; import org.geotools.gce.imagemosaic.catalog.index.IndexerUtils; import org.geotools.gce.imagemosaic.catalog.index.ObjectFactory; import org.geotools.gce.imagemosaic.catalog.index.ParametersType; import org.geotools.gce.imagemosaic.catalog.index.SchemaType; import org.geotools.gce.imagemosaic.catalog.index.SchemasType; import org.geotools.gce.imagemosaic.properties.DefaultPropertiesCollectorSPI; import org.geotools.gce.imagemosaic.properties.PropertiesCollector; import org.geotools.gce.imagemosaic.properties.PropertiesCollectorFinder; import org.geotools.gce.imagemosaic.properties.PropertiesCollectorSPI; import org.geotools.imageio.netcdf.Slice2DIndex.Slice2DIndexManager; import org.geotools.imageio.netcdf.utilities.NetCDFUtilities; import org.geotools.referencing.factory.gridshift.DataUtilities; import org.geotools.resources.coverage.CoverageUtilities; import org.geotools.util.Utilities; import org.geotools.util.logging.Logging; import org.opengis.feature.type.Name; /** * A class used to store any auxiliary indexing information * such as the low level indexer definition as well as the * datastore properties configuration specifying where to * build that index. * * Since 14.x is it also possible to store the catalog into * a PostGis based DB * * * @author Daniele Romagnoli, GeoSolutions SAS */ public class AncillaryFileManager implements FileSetManager{ /** * The Ancillary file manager will parse different type of * auxiliary files: an XML based indexer specifying the * definition of the low level index describing the * multidim granules catalog, as well as datastore * properties file containing the configuration of the * PostGIS DB where the catalog should be stored. */ enum AuxiliaryFileType { INDEXER_XML { File lookup(String baseName, File parentDirectory, File destinationDirectory) { File file; // CASE 1: side file (for backward compatibility) // Compose the path to an optional XML auxiliary file in the same directory of the input file // (filename.xml) String optionalAuxiliaryPath = parentDirectory.getAbsolutePath() + File.separator + baseName + INDEX_SUFFIX; file = new File(optionalAuxiliaryPath); if (!file.exists() || !file.canRead()) { // CASE 2: side file in hidden folder (for retrocompatibility) // Compose the path to an optional XML auxiliary file inside a directory of with the same // name of the file but with a dot before (.filename/filename.xml) optionalAuxiliaryPath = parentDirectory.getAbsolutePath() + File.separator + "." + baseName + File.separator + baseName + INDEX_SUFFIX; file = new File(optionalAuxiliaryPath); if (!file.exists() || !file.canRead()) { file = null; } } if (file == null) { // CASE 3: the recent approach using HASH of the file to prevent conflicts // With files with same name file = new File(destinationDirectory, baseName + INDEX_SUFFIX); } return file; } }, INDEXER_DATASTORE { File lookup (String baseName, File parentDirectory, File destinationDirectory) { File file = null; // CASE 1: side file (for backward compatibility) // Compose the path to an optional datastore file in the same directory of the input file String optionalAuxiliaryDatastorePath = parentDirectory.getAbsolutePath() + File.separator + DEFAULT_DATASTORE_PROPERTIES; file = new File(optionalAuxiliaryDatastorePath); if (!file.exists() || !file.canRead()) { // CASE 2: side file in hidden folder (for backward compatibility) // Compose the path to an optional datastore file inside a directory with the same // name of the file but with a dot before (.filename/mddatastore.properties) optionalAuxiliaryDatastorePath = parentDirectory.getAbsolutePath() + File.separator + "." + baseName + File.separator + DEFAULT_DATASTORE_PROPERTIES; file = new File(optionalAuxiliaryDatastorePath); if (!file.exists() || !file.canRead()) { file = null; } } if (file == null) { // CASE 3: the recent approach using HASH of the file to prevent conflicts // With files with same name file = new File(destinationDirectory, DEFAULT_DATASTORE_PROPERTIES); if (!file.exists() || !file.canRead()) { file = null; } } return file; } }; abstract File lookup (String baseName, File parentDirectory, File destinationDirectory); } private FileSetManager fileSetManager; private final static Logger LOGGER = Logging.getLogger(AncillaryFileManager.class.toString()); private static ObjectFactory OBJECT_FACTORY = new ObjectFactory(); /** Default schema name */ static final String DEFAULT_SCHEMA_NAME = "def"; private final static Set<String> CUT_EXTENSIONS = new HashSet<String>(); private static final Set<PropertiesCollectorSPI> pcSPIs = PropertiesCollectorFinder.getPropertiesCollectorSPI(); private static JAXBContext CONTEXT = null; // contains information about dimensions that will produce multiple bands indexed by the dimension name private final Map<String, MultipleBandsDimensionInfo> multipleBandsDimensionsInfo = new HashMap<>(); static { try { CONTEXT = JAXBContext.newInstance("org.geotools.gce.imagemosaic.catalog.index"); } catch (Exception e) { LOGGER.log(Level.INFO, e.getMessage(), e); } CUT_EXTENSIONS.add("nc"); CUT_EXTENSIONS.add("ncml"); } private Indexer indexer; private static final String INDEX_SUFFIX = ".xml"; private static final String COVERAGE_NAME = "coverageName"; private static final String DEFAULT_DATASTORE_PROPERTIES = "mddatastore.properties"; /** * The list of Slice2D indexes */ private final List<Slice2DIndex> slicesIndexList = new ArrayList<Slice2DIndex>(); /** * The Slice2D index manager */ Slice2DIndexManager slicesIndexManager; /** The map of coverages elements */ Map<String, Coverage> coveragesMapping = new HashMap<String, Coverage>(); /** coverage Name to variable mapping */ Map<Name, String> variablesMap = null; /** specify whether the auxiliary file contains explicit schema definition to be forced */ boolean imposedSchema = false; /** A propertyCollectors map */ private Map<String, PropertiesCollector> collectors = null; private File destinationDir; /** The main NetCDF file */ private File ncFile; /** The parent folder of the main File */ private File parentDirectory; /** File storing the slices index (index, Tsection, Zsection) */ private File slicesIndexFile; /** File storing the datastore properties */ private File datastoreIndexFile; /** File storing the coverages indexer */ private File indexerFile; public AncillaryFileManager(final File netcdfFile, final String indexFilePath) throws IOException, JAXBException, NoSuchAlgorithmException { this(netcdfFile, indexFilePath, null); } public AncillaryFileManager(final File netcdfFile, final String indexFilePath, final String datastoreFilePath) throws IOException, JAXBException, NoSuchAlgorithmException { org.geotools.util.Utilities.ensureNonNull("file", netcdfFile); if (!netcdfFile.exists()) { throw new IllegalArgumentException("The specified file doesn't exist: " + netcdfFile); } // Set files fileSetManager = new FileSystemFileSetManager(); ncFile = netcdfFile; parentDirectory = new File(ncFile.getParent()); // Look for external folder configuration final String baseFolder = NetCDFUtilities.EXTERNAL_DATA_DIR; File baseDir = null; if (baseFolder != null) { baseDir = new File(baseFolder); // Check it again in case it has been deleted in the meantime: baseDir = NetCDFUtilities.isValidDir(baseDir) ? baseDir : null; } String mainFilePath = ncFile.getCanonicalPath(); // Selection of the hashcode for creating a unique directory of the auxiliary files MessageDigest md = MessageDigest.getInstance("SHA-1"); md.update(mainFilePath.getBytes()); String hashCode = convertToHex(md.digest()); String mainName = FilenameUtils.getName(mainFilePath); //TODO: Improve that check on extensions. String extension = FilenameUtils.getExtension(mainName); String baseName = cutExtension(extension) ? FilenameUtils.removeExtension(mainName) : mainName; String outputLocalFolder = "." + baseName + "_" + hashCode; destinationDir = new File(parentDirectory, outputLocalFolder); // append base file folder tree to the optional external data dir if (baseDir != null) { destinationDir = new File(baseDir, outputLocalFolder); } boolean createdDir = false; if (!destinationDir.exists()) { createdDir = destinationDir.mkdirs(); // Creation of an origin.txt file with the absolute file path internally written File origin = new File(destinationDir, "origin.txt"); FileUtils.write(origin, ncFile.getAbsolutePath()); } // Init auxiliary file names slicesIndexFile = new File(destinationDir, baseName + ".idx"); indexerFile = lookupFile(indexFilePath, baseName, AuxiliaryFileType.INDEXER_XML); if (!createdDir) { // Check for index to be reset only in case we didn't created a new directory. checkReset(ncFile, slicesIndexFile, destinationDir); } fileSetManager.addFile(destinationDir.getAbsolutePath()); // init initIndexer(); datastoreIndexFile = lookupFile(datastoreFilePath, baseName, AuxiliaryFileType.INDEXER_DATASTORE); } /** * Use different approaches to look for the specified file since it can be provided * externally (as from the imageMosaic sharing the same indexer between multiple * NetCDF files), it can be contained into a .DIR folder or it can be contained * into a HASHNAME folder. * * @param auxFilePath * @param baseName */ private File lookupFile(String filePath, String baseName, AuxiliaryFileType type ) { // CASE 1: file externally provided File file = null; if (filePath != null) { file = new File(filePath); if (!file.exists() || !file.canRead()) { file = null; } } if (file != null) { return file; } else { file = type.lookup(baseName, parentDirectory, destinationDir); } return file; } private static boolean cutExtension(String extension) { return CUT_EXTENSIONS.contains(extension); } /** * Check whether the file have been updated. * @param ncFile * @param slicesIndexFile * @param destinationDir * @throws IOException */ private static void checkReset(final File mainFile, final File slicesIndexFile, final File destinationDir) throws IOException { // TODO: Consider acquiring a LOCK on the file if (slicesIndexFile.exists()) { final long mainFileTime = mainFile.lastModified(); final long indexTime = slicesIndexFile.lastModified(); // Check whether the NetCDF time is more recent with respect to the auxiliary indexes if (mainFileTime > indexTime) { // Need to delete all the auxiliary files and start from scratch final Collection<File> listedFiles = FileUtils.listFiles(destinationDir, null, true); for (File file: listedFiles) { // Preserve summary file which contains mapping between coverages and underlying variables if (!file.getAbsolutePath().endsWith(INDEX_SUFFIX)) { FileUtils.deleteQuietly(file); } } } } } /** * Write indexer to disk * @throws IOException * @throws JAXBException * * TODO: Need to check for thread safety */ public void writeToDisk() throws IOException, JAXBException { // Write collected information Slice2DIndexManager.writeIndexFile(slicesIndexFile, slicesIndexList); if (!indexerFile.exists()) { storeIndexer(indexerFile, coveragesMapping); } } /** * Write to disk the variable summary, a simple text file containing variable names. * * @param indexerFile * @param coveragesMapping * @throws JAXBException */ private void storeIndexer(final File indexerFile, final Map<String, Coverage> coveragesMapping) throws JAXBException { if (coveragesMapping == null || coveragesMapping.isEmpty()) { throw new IllegalArgumentException("No valid coverages name to be written"); } // Create the main indexer final Indexer indexer = OBJECT_FACTORY.createIndexer(); Coverages coverages = OBJECT_FACTORY.createIndexerCoverages(); indexer.setCoverages(coverages); // create coverages final List<Coverage> coveragesList = coverages.getCoverage(); final Collection <Coverage> inputCoverages = coveragesMapping.values(); for (Coverage cov: inputCoverages) { // Create a coverage object final Coverage coverage = OBJECT_FACTORY.createIndexerCoveragesCoverage(); coverage.setName(cov.getName()); coverage.setOrigName(cov.getOrigName()); coveragesList.add(coverage); // Create the schema object final SchemaType schema = OBJECT_FACTORY.createSchemaType(); coverage.setSchema(schema); final SchemaType inputSchema = cov.getSchema(); schema.setAttributes(inputSchema.getAttributes()); schema.setName(inputSchema.getName()); } // Marshalling the indexer to XML on disk Marshaller marshaller = CONTEXT.createMarshaller(); marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); marshaller.marshal(indexer, indexerFile); } /** * Return a {@link Name} representation of the coverage name * @param varName * @return */ public Name getCoverageName(String varName) { final Collection<Coverage> coverages = coveragesMapping.values(); for (Coverage cov: coverages) { if (varName.equalsIgnoreCase(cov.getOrigName())) { return new NameImpl(cov.getName()); } } return null; } /** * Dispose the Manager */ public void dispose() { try { slicesIndexList.clear(); if (slicesIndexManager != null) { slicesIndexManager.dispose(); } } catch (IOException e) { if (LOGGER.isLoggable(Level.WARNING)) { LOGGER.warning("Errors Disposing the indexer." + e.getLocalizedMessage()); } } finally { slicesIndexManager = null; } } /** * Return a {@link Slice2DIndex} related to the provided imageIndex * @param imageIndex * @return * @throws IOException */ public Slice2DIndex getSlice2DIndex(final int imageIndex) throws IOException { Slice2DIndex variableIndex; if (slicesIndexManager != null) { variableIndex = slicesIndexManager.getSlice2DIndex(imageIndex); } else { variableIndex = slicesIndexList.get(imageIndex); } return variableIndex; } public File getSlicesIndexFile() { return slicesIndexFile; } public File getIndexerFile() { return indexerFile; } public File getDestinationDir() { return destinationDir; } public File getDatastoreIndexFile() { return datastoreIndexFile; } public void addSlice(final Slice2DIndex variableIndex) { slicesIndexList.add(variableIndex); } public Coverage addCoverage(String varName) { // Create a new coverage to be added. Coverage coverage = OBJECT_FACTORY.createIndexerCoveragesCoverage(); coverage.setName(varName); coverage.setOrigName(varName); addCoverage(coverage); return coverage; } private Coverage addCoverage(Coverage coverage) { if (variablesMap == null) { variablesMap = new HashMap<Name, String>(); coveragesMapping = new HashMap<String, Coverage>(); } coveragesMapping.put(coverage.getName(), coverage); variablesMap.put(new NameImpl(coverage.getName()), coverage.getOrigName()); return coverage; } public void initSliceManager() throws IOException { slicesIndexManager = new Slice2DIndexManager(slicesIndexFile); slicesIndexManager.open(); } public void resetSliceManager() throws IOException { if (slicesIndexManager != null) { slicesIndexManager.dispose(); } // clean existing index slicesIndexList.clear(); } /** * Get the list of Names for the underlying coverage list * @return */ public List<Name> getCoveragesNames() { final List<Name> names = new ArrayList<Name>(); Collection<Coverage> coverages = coveragesMapping.values(); for (Coverage cov: coverages) { names.add(new NameImpl(cov.getName())); } return names; } /** * Retrieve basic indexer properties by scanning the indexer XML instance. * @throws JAXBException */ private void initIndexer() throws JAXBException { if (indexerFile.exists() && indexerFile.canRead()) { Unmarshaller unmarshaller = CONTEXT.createUnmarshaller(); if (unmarshaller != null) { indexer = (Indexer) unmarshaller.unmarshal(indexerFile); // indexed information about dimensions that supports multiple bands initMultipleBandsDimensionsInfo(indexer); // Parsing schemas final SchemasType schemas = indexer.getSchemas(); Map<String, String> schemaMapping = new HashMap<String, String>(); if (schemas != null) { // Map schema names to schema attributes string List<SchemaType> schemaElements = schemas.getSchema(); for (SchemaType schemaElement: schemaElements) { schemaMapping.put(schemaElement.getName(), schemaElement.getAttributes()); } } // Parsing properties collectors initPropertiesCollectors(); // Parsing coverages initCoverages(schemaMapping); } } } /** * Init the coverages naming and schema mappings */ private void initCoverages(Map<String,String> schemaMapping) { final Coverages coverages = indexer.getCoverages(); if (coverages != null) { final List<Coverage> coverageElements = coverages.getCoverage(); // Loop over coverages for (Coverage coverageElement : coverageElements) { // get the coverageName String coverageName = coverageElement.getName(); if (coverageName == null) { // null coverageName... try to setup it through name collector coverageName = getCoverageNameFromCollector(coverageElement.getNameCollector()); } // Get the origName for that coverage String origName = coverageElement.getOrigName(); if (origName != null && !origName.isEmpty()) { origName = origName.trim(); } else { origName = coverageName; } // Get the coverage schema and attributes final SchemaType coverageSchema = coverageElement.getSchema(); String coverageSchemaRef = null; String schemaAttributes = null; if (coverageSchema != null) { imposedSchema = true; schemaAttributes = coverageSchema.getAttributes(); coverageSchemaRef = coverageSchema.getRef(); } // initialize schemaName with the coverageName unless there isn't a schema // reference String schemaName = coverageName; // in case of coverageSchemaRef not null, link to that reference schema if (coverageSchemaRef == null || coverageSchemaRef.trim().length() == 0) { schemaMapping.put(coverageName, schemaAttributes); } else { schemaName = coverageSchemaRef; schemaAttributes = schemaMapping.get(schemaName); } // Add the newly created indexer coverage final Coverage coverage = createCoverate(coverageName, origName, schemaAttributes, schemaName); addCoverage(coverage); } } } /** * Create a Coverage indexer object with the specified set of properties * @param coverageName name of the coverage * @param origName name of the underlying variable * @param schemaAttributes schema definition attributes * @param schemaName schema name * @return */ private Coverage createCoverate(String coverageName, String origName, String schemaAttributes, String schemaName) { SchemaType schema = OBJECT_FACTORY.createSchemaType(); Coverage coverage = OBJECT_FACTORY.createIndexerCoveragesCoverage(); coverage.setOrigName(origName); coverage.setName(coverageName); coverage.setSchema(schema); schema.setAttributes(schemaAttributes); schema.setName(schemaName); return coverage; } /** * Get the coverageName using the specified nameCollector * * @param nameCollector The name of the propertiesCollector which will be used to setup * the coverage name * @return */ private String getCoverageNameFromCollector(final String nameCollector) { String coverageName = null; if (collectors != null && collectors.containsKey(nameCollector)) { Map<String, Object> keyValues = new HashMap<String, Object>(); PropertiesCollector collector = collectors.get(nameCollector); collector.collect(ncFile); collector.setProperties(keyValues); collector.reset(); coverageName = (String) keyValues.get(COVERAGE_NAME); } return coverageName; } /** * Initialize the propertiesCollectors machinery */ private void initPropertiesCollectors() { final Collectors collectors = indexer.getCollectors(); if (collectors != null) { List<Collector> collectorList = collectors.getCollector(); if (collectorList != null) { this.collectors = new HashMap<String, PropertiesCollector>(); // Scan the collectors list defined inside the indexer for (Collector collector: collectorList) { final String collectorName = collector.getName(); final String spiName = collector.getSpi(); final String value = collector.getValue(); final String mapped = collector.getMapped(); PropertiesCollectorSPI selectedSPI = null; // Look for a matching property collector in the set of registered ones for (PropertiesCollectorSPI spi : pcSPIs) { if (spi.isAvailable() && spi.getName().equalsIgnoreCase(spiName)) { selectedSPI = spi; break; } } if (selectedSPI == null) { if (LOGGER.isLoggable(Level.INFO)) { LOGGER.info("Unable to find a PropertyCollector for this INTERNAL_STORE_SPI: " + spiName); } continue; } // property names final String propertyNames[] = new String[]{mapped != null ? mapped : COVERAGE_NAME}; // create the PropertiesCollector final PropertiesCollector pc = selectedSPI.create(DefaultPropertiesCollectorSPI.REGEX_PREFIX + value, Arrays.asList(propertyNames)); if (pc != null) { this.collectors.put(collectorName, pc); } } } } } public String getTypeName(String coverageName) { return coveragesMapping.get(coverageName).getSchema().getName(); } /** * Add the default schema to this coverage * @param coverage * @return */ public String setSchema(Coverage coverage, final String schemaName, final String schemaDef) { Utilities.ensureNonNull("coverage", coverage); Utilities.ensureNonNull("schemaName", schemaName); if (coverage != null) { SchemaType schema = coverage.getSchema(); if (schema == null) { schema = OBJECT_FACTORY.createSchemaType(); coverage.setSchema(schema); } schema.setName(schemaName); if(schemaDef!=null){ schema.setAttributes(schemaDef); } return schemaName; } return null; } /** * @param varName * @return */ public boolean acceptsVariable(String varName) { Utilities.ensureNonNull("varName", varName); if (indexer == null || indexer.getCoverages() == null) { return true; } for (Coverage filteringCoverage: indexer.getCoverages().getCoverage()) { if (varName.equalsIgnoreCase(filteringCoverage.getName()) || varName.equalsIgnoreCase(filteringCoverage.getOrigName())) { return true; } } return false; } public boolean isImposedSchema() { return imposedSchema; } @Override public void addFile(String filePath) { fileSetManager.addFile(filePath); } @Override public List<String> list() { return fileSetManager.list(); } @Override public void removeFile(String filePath) { fileSetManager.removeFile(filePath); } @Override public void purge() { try { resetSliceManager(); } catch (IOException e) { LOGGER.log(Level.FINER, e.getMessage(), e); } fileSetManager.purge(); } public static String convertToHex(byte[] data) { StringBuilder buf = new StringBuilder(); for (byte b : data) { int halfbyte = (b >>> 4) & 0x0F; int two_halfs = 0; do { buf.append((0 <= halfbyte) && (halfbyte <= 9) ? (char) ('0' + halfbyte) : (char) ('a' + (halfbyte - 10))); halfbyte = b & 0x0F; } while (two_halfs++ < 1); } return buf.toString(); } /** * Create the {@link DataStoreConfiguration} using the external * datastoreIndexFile if provided, or the H2 based default. * @return * @throws IOException */ public DataStoreConfiguration getDatastoreConfiguration() throws IOException { DataStoreConfiguration datastoreConfiguration = null; if (datastoreIndexFile != null) { URL datastoreURL = DataUtilities.fileToURL(datastoreIndexFile); Properties properties = CoverageUtilities.loadPropertiesFromURL(datastoreURL); if (properties != null) { final String SPIClass = properties.getProperty("SPI"); try { // create a datastore as instructed final DataStoreFactorySpi spi = (DataStoreFactorySpi) Class.forName(SPIClass) .newInstance(); Map<String, Serializable> datastoreParams = Utils.filterDataStoreParams( properties, spi); // create a datastore configuration using the specified SPI and datastoreParams datastoreConfiguration = new DataStoreConfiguration(spi, datastoreParams); datastoreConfiguration.setDatastoreSpi(spi); datastoreConfiguration.setParams(datastoreParams); datastoreConfiguration.setShared(true); // update params for the shared case checkStoreWrapping(datastoreConfiguration); } catch (Exception e) { final IOException ioe = new IOException(); throw (IOException) ioe.initCause(e); } } } else { File parentFile = slicesIndexFile.getParentFile(); String database = FilenameUtils.removeExtension( FilenameUtils.getName(slicesIndexFile.getCanonicalPath())).replace(".", ""); datastoreConfiguration = new DataStoreConfiguration( DataStoreConfiguration.getDefaultParams(database, parentFile)); } return datastoreConfiguration; } /** * Check whether the dataStore needs to be wrapped * (as an instance, to allow long typeNames and attributes). * * @param datastoreConfiguration * @throws IOException */ private void checkStoreWrapping(DataStoreConfiguration datastoreConfiguration) throws IOException { Map<String, Serializable> params = datastoreConfiguration.getParams(); String param = getParameter(Utils.Prop.WRAP_STORE); if (param != null && param.trim().equalsIgnoreCase("true")) { params.put(Utils.Prop.WRAP_STORE, true); params.put(Utils.Prop.PARENT_LOCATION, DataUtilities.fileToURL(getDestinationDir()) .toString()); } } public String getParameter (String parameterKey) { ParametersType indexerParams = indexer != null ? indexer.getParameters() : null; return IndexerUtils.getParam(indexerParams, parameterKey); } public boolean getParameterAsBoolean (String parameterKey) { ParametersType indexerParams = indexer != null ? indexer.getParameters() : null; String param = IndexerUtils.getParam(indexerParams, parameterKey); return Boolean.valueOf(param); } /** * Utility method that wil retrieve from the indexer file information about multiple bands * dimensions and will parse that information and index it by the dimensions names. */ private void initMultipleBandsDimensionsInfo(Indexer indexer) { if (indexer.getMultipleBandsDimensions() == null || indexer.getMultipleBandsDimensions().getMultipleBandsDimension() == null) { // no multiple bands dimensions in the data set return; } for (Indexer.MultipleBandsDimensions.MultipleBandsDimension multipleBandsDimension : indexer.getMultipleBandsDimensions().getMultipleBandsDimension()) { // multiple bands dimensions are ignored by default NetCDFUtilities.addIgnoredDimension(multipleBandsDimension.getName()); // index by the dimensions name the multiple bands information multipleBandsDimensionsInfo.put(multipleBandsDimension.getName(), new MultipleBandsDimensionInfo(multipleBandsDimension.getBandsNames())); } } /** * This method will return the multiple bands information associated with the provided * dimension name or NULL if the dimensions is single band. */ MultipleBandsDimensionInfo getMultipleBandsDimensionInfo(String dimensionName) { // simple lookup in the hash table, if the dimensions is single band we simply return NULL return multipleBandsDimensionsInfo.get(dimensionName); } }