All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.orekit.data.DataProvidersManager Maven / Gradle / Ivy

Go to download

OREKIT (ORbits Extrapolation KIT) is a low level space dynamics library. It provides basic elements (orbits, dates, attitude, frames ...) and various algorithms to handle them (conversions, analytical and numerical propagation, pointing ...).

There is a newer version: 12.2
Show newest version
/* Copyright 2002-2019 CS Systèmes d'Information
 * Licensed to CS Systèmes d'Information (CS) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * CS licenses this file to You 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.orekit.data;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.Pattern;

import org.orekit.errors.OrekitException;
import org.orekit.errors.OrekitMessages;

/** Singleton class managing all supported {@link DataProvider data providers}.

 * 

* This class is the single point of access for all data loading features. It * is used for example to load Earth Orientation Parameters used by IERS frames, * to load UTC leap seconds used by time scales, to load planetary ephemerides ... * *

* It is user-customizable: users can add their own data providers at will. This * allows them for example to use a database or an existing data loading library * in order to embed an Orekit enabled application in a global system with its * own data handling mechanisms. There is no upper limitation on the number of * providers, but often each application will use only a few. *

* *

* If the list of providers is empty when attempting to {@link #feed(String, DataLoader) * feed} a file loader, the {@link #addDefaultProviders()} method is called * automatically to set up a default configuration. This default configuration * contains one {@link DataProvider data provider} for each component of the * path-like list specified by the java property orekit.data.path. * See the {@link #feed(String, DataLoader) feed} method documentation for further * details. The default providers configuration is not set up if the list * is not empty. If users want to have both the default providers and additional * providers, they must call explicitly the {@link #addDefaultProviders()} method. *

* *

* The default configuration uses a predefined set of {@link DataFilter data filters} * that already handled gzip-compressed files (recognized by the {@code .gz} suffix) * and Unix-compressed files (recognized by the {@code .Z} suffix). * Users can {@link #addFilter(DataFilter) add} custom filters for handling specific * types of filters (decompression, deciphering...). *

* * @author Luc Maisonobe * @see DirectoryCrawler * @see ClasspathCrawler */ public class DataProvidersManager { /** Name of the property defining the root directories or zip/jar files path for default configuration. */ public static final String OREKIT_DATA_PATH = "orekit.data.path"; /** Supported data providers. */ private final List providers; /** Supported filters. * @since 9.2 */ private final List filters; /** Number of predefined filters. */ private final int predefinedFilters; /** Loaded data. */ private final Set loaded; /** Build an instance with default configuration. *

* This is a singleton, so the constructor is private. *

*/ private DataProvidersManager() { providers = new ArrayList(); filters = new ArrayList<>(); loaded = new LinkedHashSet(); // set up predefined filters addFilter(new GzipFilter()); addFilter(new UnixCompressFilter()); predefinedFilters = filters.size(); } /** Get the unique instance. * @return unique instance of the manager. */ public static DataProvidersManager getInstance() { return LazyHolder.INSTANCE; } /** Add the default providers configuration. *

* The default configuration contains one {@link DataProvider data provider} * for each component of the path-like list specified by the java property * orekit.data.path. *

*

* If the property is not set or is null, no data will be available to the library * (for example no pole corrections will be applied and only predefined UTC steps * will be taken into account). No errors will be triggered in this case. *

*

* If the property is set, it must contains a list of existing directories or zip/jar * archives. One {@link DirectoryCrawler} instance will be set up for each * directory and one {@link ZipJarCrawler} instance (configured to look for the * archive in the filesystem) will be set up for each zip/jar archive. The list * elements in the java property are separated using the standard path separator for * the operating system as returned by {@link System#getProperty(String) * System.getProperty("path.separator")}. This standard path separator is ":" on * Linux and Unix type systems and ";" on Windows types systems. *

*/ public void addDefaultProviders() { // get the path containing all components final String path = System.getProperty(OREKIT_DATA_PATH); if ((path != null) && !"".equals(path)) { // extract the various components for (final String name : path.split(System.getProperty("path.separator"))) { if (!"".equals(name)) { final File file = new File(name); // check component if (!file.exists()) { if (DataProvider.ZIP_ARCHIVE_PATTERN.matcher(name).matches()) { throw new OrekitException(OrekitMessages.UNABLE_TO_FIND_FILE, name); } else { throw new OrekitException(OrekitMessages.DATA_ROOT_DIRECTORY_DOES_NOT_EXIST, name); } } if (file.isDirectory()) { addProvider(new DirectoryCrawler(file)); } else if (DataProvider.ZIP_ARCHIVE_PATTERN.matcher(name).matches()) { addProvider(new ZipJarCrawler(file)); } else { throw new OrekitException(OrekitMessages.NEITHER_DIRECTORY_NOR_ZIP_OR_JAR, name); } } } } } /** Add a data provider to the supported list. * @param provider data provider to add * @see #removeProvider(DataProvider) * @see #clearProviders() * @see #isSupported(DataProvider) * @see #getProviders() */ public void addProvider(final DataProvider provider) { providers.add(provider); } /** Remove one provider. * @param provider provider instance to remove * @return instance removed (null if the provider was not already present) * @see #addProvider(DataProvider) * @see #clearProviders() * @see #isSupported(DataProvider) * @see #getProviders() * @since 5.1 */ public DataProvider removeProvider(final DataProvider provider) { for (final Iterator iterator = providers.iterator(); iterator.hasNext();) { final DataProvider current = iterator.next(); if (current == provider) { iterator.remove(); return provider; } } return null; } /** Remove all data providers. * @see #addProvider(DataProvider) * @see #removeProvider(DataProvider) * @see #isSupported(DataProvider) * @see #getProviders() */ public void clearProviders() { providers.clear(); } /** Add a data filter. * @param filter filter to add * @see #applyAllFilters(NamedData) * @see #clearFilters() * @since 9.2 */ public void addFilter(final DataFilter filter) { filters.add(filter); } /** Remove all data filters, except the predefined ones. * @see #addFilter(DataFilter) * @since 9.2 */ public void clearFilters() { for (int i = filters.size() - 1; i >= predefinedFilters; --i) { filters.remove(i); } } /** Apply all the relevant data filters, taking care of layers. *

* If several filters can be applied, they will all be applied * as a stack, even recursively if required. This means that if * filter A applies to files with names of the form base.ext.a * and filter B applies to files with names of the form base.ext.b, * then providing base.ext.a.b.a will result in filter A being * applied on top of filter B which itself is applied on top of * another instance of filter A. *

* @param original original named data * @return fully filtered named data * @exception IOException if some data stream cannot be filtered * @see #addFilter(DataFilter) * @see #clearFilters() * @since 9.2 */ public NamedData applyAllFilters(final NamedData original) throws IOException { NamedData top = original; for (boolean filtering = true; filtering;) { filtering = false; for (final DataFilter filter : filters) { final NamedData filtered = filter.filter(top); if (filtered != top) { // the filter has been applied, we need to restart the loop top = filtered; filtering = true; break; } } } return top; } /** Check if some provider is supported. * @param provider provider to check * @return true if the specified provider instance is already in the supported list * @see #addProvider(DataProvider) * @see #removeProvider(DataProvider) * @see #clearProviders() * @see #getProviders() * @since 5.1 */ public boolean isSupported(final DataProvider provider) { for (final DataProvider current : providers) { if (current == provider) { return true; } } return false; } /** Get an unmodifiable view of the list of supported providers. * @return unmodifiable view of the list of supported providers * @see #addProvider(DataProvider) * @see #removeProvider(DataProvider) * @see #clearProviders() * @see #isSupported(DataProvider) */ public List getProviders() { return Collections.unmodifiableList(providers); } /** Get an unmodifiable view of the set of data file names that have been loaded. *

* The names returned are exactly the ones that were given to the {@link * DataLoader#loadData(InputStream, String) DataLoader.loadData} method. *

* @return unmodifiable view of the set of data file names that have been loaded * @see #feed(String, DataLoader) * @see #clearLoadedDataNames() */ public Set getLoadedDataNames() { return Collections.unmodifiableSet(loaded); } /** Clear the set of data file names that have been loaded. * @see #getLoadedDataNames() */ public void clearLoadedDataNames() { loaded.clear(); } /** Feed a data file loader by browsing all data providers. *

* If this method is called with an empty list of providers, a default * providers configuration is set up. This default configuration contains * only one {@link DataProvider data provider}: a {@link DirectoryCrawler} * instance that loads data from files located somewhere in a directory hierarchy. * This default provider is not added if the list is not empty. If users * want to have both the default provider and other providers, they must add it * explicitly. *

*

* The providers are used in the order in which they were {@link #addProvider(DataProvider) * added}. As soon as one provider is able to feed the data loader, the loop is * stopped. If no provider is able to feed the data loader, then the last error * triggered is thrown. *

* @param supportedNames regular expression for file names supported by the visitor * @param loader data loader to use * @return true if some data has been loaded */ public boolean feed(final String supportedNames, final DataLoader loader) { final Pattern supported = Pattern.compile(supportedNames); // set up a default configuration if no providers have been set if (providers.isEmpty()) { addDefaultProviders(); } // monitor the data that the loader will load final DataLoader monitoredLoader = new MonitoringWrapper(loader); // crawl the data collection OrekitException delayedException = null; for (final DataProvider provider : providers) { try { // try to feed the visitor using the current provider if (provider.feed(supported, monitoredLoader)) { return true; } } catch (OrekitException oe) { // remember the last error encountered delayedException = oe; } } if (delayedException != null) { throw delayedException; } return false; } /** Data loading monitoring wrapper class. */ private class MonitoringWrapper implements DataLoader { /** Wrapped loader. */ private final DataLoader loader; /** Simple constructor. * @param loader loader to monitor */ MonitoringWrapper(final DataLoader loader) { this.loader = loader; } /** {@inheritDoc} */ public boolean stillAcceptsData() { // delegate to monitored loader return loader.stillAcceptsData(); } /** {@inheritDoc} */ public void loadData(final InputStream input, final String name) throws IOException, ParseException, OrekitException { // delegate to monitored loader loader.loadData(input, name); // monitor the fact new data has been loaded loaded.add(name); } } /** Holder for the manager singleton. *

* We use the Initialization on demand holder idiom to store * the singletons, as it is both thread-safe, efficient (no * synchronization) and works with all versions of java. *

*/ private static class LazyHolder { /** Unique instance. */ private static final DataProvidersManager INSTANCE = new DataProvidersManager(); /** Private constructor. *

This class is a utility class, it should neither have a public * nor a default constructor. This private constructor prevents * the compiler from generating one automatically.

*/ private LazyHolder() { } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy