Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGFactory.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGFactory.java?rev=1728777&r1=1728776&r2=1728777&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGFactory.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGFactory.java [UTF-8] Fri Feb 5 23:41:50 2016
@@ -18,11 +18,14 @@ package org.apache.sis.referencing.facto
import java.util.Collections;
import java.util.Locale;
+import java.util.Map;
import java.util.Set;
+import java.util.concurrent.TimeUnit;
import java.sql.Connection;
+import java.sql.DatabaseMetaData;
import java.sql.SQLException;
import javax.sql.DataSource;
-import java.util.concurrent.TimeUnit;
+import java.io.IOException;
import org.opengis.util.NameFactory;
import org.opengis.util.FactoryException;
import org.opengis.referencing.crs.CRSFactory;
@@ -41,6 +44,10 @@ import org.apache.sis.referencing.factor
import org.apache.sis.referencing.factory.UnavailableFactoryException;
import org.apache.sis.util.ArgumentChecks;
import org.apache.sis.util.Localized;
+import org.apache.sis.util.ObjectConverters;
+
+// Branch-dependent imports
+import org.apache.sis.internal.jdk7.Path;
/**
@@ -48,7 +55,19 @@ import org.apache.sis.util.Localized;
* when first needed using the {@link DataSource} specified at construction time. The geodetic objects are cached
* for reuse and the idle connections are closed after a timeout.
*
- * <div class="section">Note for subclasses</div>
+ * <p>If no data source has been specified to the constructor, then {@code EPSGFactory} searches for a
+ * default data source in JNDI, or in the directory given by the {@code SIS_DATA} environment variable,
+ * or in the directory given by the {@code "derby.system.home"} property, in that order.
+ * See the {@linkplain org.apache.sis.referencing.factory.sql package documentation} for more information.</p>
+ *
+ * <div class="section">EPSG dataset installation</div>
+ * This class tries to automatically detect the schema that contains the EPSG tables
+ * (see {@link SQLTranslator} for examples of tables to look for). If the tables are not found,
+ * then the {@link #install(Connection)} method will be invoked for creating the EPSG schema.
+ * The {@code install(…)} method can perform its work only if the definition files are reachable
+ * on the classpath, or if the directory containing the files have been specified.
+ *
+ * <div class="section">Data Access Object (DAO)</div>
* If there is no cached object for a given code, then {@code EPSGFactory} creates an {@link EPSGDataAccess} instance
* for performing the actual creation work. Developers who need to customize the geodetic object creation can override
* the {@link #newDataAccess(Connection, SQLTranslator)} method in order to return their own {@link EPSGDataAccess}
@@ -58,6 +77,9 @@ import org.apache.sis.util.Localized;
* @since 0.7
* @version 0.7
* @module
+ *
+ * @see EPSGDataAccess
+ * @see SQLTranslator
*/
public class EPSGFactory extends ConcurrentAuthorityFactory<EPSGDataAccess> implements CRSAuthorityFactory,
CSAuthorityFactory, DatumAuthorityFactory, CoordinateOperationAuthorityFactory, Localized
@@ -110,6 +132,32 @@ public class EPSGFactory extends Concurr
protected final MathTransformFactory mtFactory;
/**
+ * The name of the catalog that contains the EPSG tables, or {@code null} or an empty string.
+ * <ul>
+ * <li>The {@code ""} value retrieves the EPSG schema without a catalog.</li>
+ * <li>The {@code null} value means that the catalog name should not be used to narrow the search.</li>
+ * </ul>
+ */
+ private final String catalog;
+
+ /**
+ * The name of the schema that contains the EPSG tables, or {@code null} or an empty string.
+ * <ul>
+ * <li>The {@code ""} value retrieves the EPSG tables without a schema.
+ * In such case, table names are prefixed by {@value SQLTranslator#TABLE_PREFIX}.</li>
+ * <li>The {@code null} value means that the schema name should not be used to narrow the search.
+ * In such case, {@link SQLTranslator} will tries to automatically detect the schema.</li>
+ * </ul>
+ */
+ private final String schema;
+
+ /**
+ * The path where to search for EPSG definition files if {@code EPSGFactory} needs to create the database,
+ * or {@code null} for searching in the {@linkplain Class#getResource(String) resources} instead.
+ */
+ private final Path scriptDirectory;
+
+ /**
* The translator from the SQL statements using MS-Access dialect to SQL statements using the dialect
* of the actual database. If null, will be created when first needed.
*/
@@ -120,76 +168,121 @@ public class EPSGFactory extends Concurr
*
* @see #getLocale()
*/
- private volatile Locale locale;
+ private final Locale locale;
/**
- * Creates a factory using the default data source and object factories.
- * Invoking this constructor is equivalent to invoking the constructor below with a all arguments set to null.
+ * Creates a factory using the given configuration. The properties recognized by this constructor
+ * are listed in the table below. Any property not listed below will be ignored by this constructor.
+ * All properties are optional and can {@code null} or omitted, in which case default values are used.
+ * Those default values are implementation-specific and may change in any future SIS version.
*
- * @throws FactoryException if the data source can not be obtained.
- */
- public EPSGFactory() throws FactoryException {
- this(null, null, null, null, null, null, null, null);
- }
-
- /**
- * Creates a factory using the given data source and object factories.
+ * <table class="sis">
+ * <caption>Recognized properties</caption>
+ * <tr>
+ * <th>Key</th>
+ * <th>Value class</th>
+ * <th>Description</th>
+ * </tr><tr>
+ * <td>{@code dataSource}</td>
+ * <td>{@link DataSource}</td>
+ * <td>The factory to use for creating {@link Connection}s to the EPSG database.</td>
+ * </tr><tr>
+ * <td>{@code nameFactory}</td>
+ * <td>{@link NameFactory}</td>
+ * <td>The factory to use for creating {@link org.opengis.util.GenericName} instances.</td>
+ * </tr><tr>
+ * <td>{@code datumFactory}</td>
+ * <td>{@link DatumAuthorityFactory}</td>
+ * <td>The factory to use for creating {@link org.opengis.referencing.datum.Datum} instances.</td>
+ * </tr><tr>
+ * <td>{@code csFactory}</td>
+ * <td>{@link CSAuthorityFactory}</td>
+ * <td>The factory to use for creating {@link org.opengis.referencing.cs.CoordinateSystem} instances.</td>
+ * </tr><tr>
+ * <td>{@code crsFactory}</td>
+ * <td>{@link CRSAuthorityFactory}</td>
+ * <td>The factory to use for creating {@link org.opengis.referencing.crs.CoordinateReferenceSystem} instances.</td>
+ * </tr><tr>
+ * <td>{@code copFactory}</td>
+ * <td>{@link CoordinateOperationAuthorityFactory}</td>
+ * <td>The factory to use for creating {@link org.opengis.referencing.operation.CoordinateOperation} instances.</td>
+ * </tr><tr>
+ * <td>{@code mtFactory}</td>
+ * <td>{@link MathTransformFactory}</td>
+ * <td>The factory to use for creating {@link org.opengis.referencing.operation.MathTransform} instances.</td>
+ * </tr><tr>
+ * <td>{@code catalog}</td>
+ * <td>{@link String}</td>
+ * <td>The database catalog that contains the EPSG schema (see {@linkplain #install install}).</td>
+ * </tr><tr>
+ * <td>{@code schema}</td>
+ * <td>{@link String}</td>
+ * <td>The database schema that contains the EPSG tables (see {@linkplain #install install}).</td>
+ * </tr><tr>
+ * <td>{@code scriptDirectory}</td>
+ * <td>{@link java.nio.file.Path}, {@link java.io.File} or {@link java.net.URL}</td>
+ * <td>The directory that contains the EPSG definition files (see {@linkplain #install install}).</td>
+ * </tr><tr>
+ * <td>{@code locale}</td>
+ * <td>{@link Locale}</td>
+ * <td>The locale for producing error messages on a <cite>best effort</cite> basis.</td>
+ * </tr>
+ * </table>
*
- * <div class="section">Default argument values</div>
- * Any or all arguments given to this constructor can be {@code null}, in which case default values are used.
- * Those default values are implementation-specific and may change in any future SIS version.
+ * <p>Default values</p>
+ * <ul>
+ * <li>If no {@code dataSource} is specified, this constructor defaults to the search algorithm described
+ * in the {@linkplain org.apache.sis.referencing.factory.sql package documentation}.</li>
+ * <li>If no {@code catalog} or {@code schema} is specified, {@link SQLTranslator} will try to auto-detect
+ * the schema that contains the EPSG tables.</li>
+ * <li>If no {@code locale} is specified, this constructor defaults to the
+ * {@linkplain Locale#getDefault(Locale.Category) display locale}.</li>
+ * </ul>
*
- * @param dataSource The factory to use for creating {@link Connection}s to the EPSG database.
- * @param nameFactory The factory to use for creating {@link org.opengis.util.GenericName} instances.
- * @param datumFactory The factory to use for creating {@link Datum} instances.
- * @param csFactory The factory to use for creating {@link CoordinateSystem} instances.
- * @param crsFactory The factory to use for creating {@link CoordinateReferenceSystem} instances.
- * @param copFactory The factory to use for creating {@link CoordinateOperation} instances.
- * @param mtFactory The factory to use for creating {@link MathTransform} instances.
- * @param translator The translator from the SQL statements using MS-Access dialect to SQL statements
- * using the dialect of the actual database.
+ * @param properties The data source, authority factories and other configuration properties,
+ * or {@code null} for the default values.
+ * @throws ClassCastException if a property value is not of the expected class.
+ * @throws IllegalArgumentException if a property value is invalid.
* @throws FactoryException if an error occurred while creating the EPSG factory.
*/
- public EPSGFactory(final DataSource dataSource,
- final NameFactory nameFactory,
- final DatumFactory datumFactory,
- final CSFactory csFactory,
- final CRSFactory crsFactory,
- final CoordinateOperationFactory copFactory,
- final MathTransformFactory mtFactory,
- final SQLTranslator translator)
- throws FactoryException
- {
+ public EPSGFactory(Map<String,?> properties) throws FactoryException {
super(EPSGDataAccess.class);
- if (dataSource != null) {
- this.dataSource = dataSource;
- } else try {
- this.dataSource = Initializer.getDataSource();
- if (this.dataSource == null) {
- throw new UnavailableFactoryException(Initializer.unspecified(null));
+ if (properties == null) {
+ properties = Collections.emptyMap();
+ }
+ DataSource ds = (DataSource) properties.get("dataSource");
+ Locale locale = ObjectConverters.convert(properties.get("locale"), Locale.class);
+ schema = ObjectConverters.convert(properties.get("schema"), String.class);
+ catalog = ObjectConverters.convert(properties.get("catalog"), String.class);
+ scriptDirectory = ObjectConverters.convert(properties.get("scriptDirectory"), Path.class);
+ if (locale == null) {
+ locale = Locale.getDefault();
+ }
+ this.locale = locale;
+ if (ds == null) try {
+ ds = Initializer.getDataSource();
+ if (ds == null) {
+ throw new UnavailableFactoryException(Initializer.unspecified(locale));
}
} catch (Exception e) {
throw new UnavailableFactoryException(e.getLocalizedMessage(), e);
}
- this.nameFactory = factory(NameFactory.class, nameFactory);
- this.datumFactory = factory(DatumFactory.class, datumFactory);
- this.csFactory = factory(CSFactory.class, csFactory);
- this.crsFactory = factory(CRSFactory.class, crsFactory);
- this.copFactory = factory(CoordinateOperationFactory.class, copFactory);
- this.mtFactory = factory(MathTransformFactory.class, mtFactory);
- this.translator = translator;
- this.locale = Locale.getDefault();
+ dataSource = ds;
+ nameFactory = factory(NameFactory.class, "nameFactory", properties);
+ datumFactory = factory(DatumFactory.class, "datumFactory", properties);
+ csFactory = factory(CSFactory.class, "csFactory", properties);
+ crsFactory = factory(CRSFactory.class, "crsFactory", properties);
+ copFactory = factory(CoordinateOperationFactory.class, "copFactory", properties);
+ mtFactory = factory(MathTransformFactory.class, "mtFactory", properties);
super.setTimeout(10, TimeUnit.SECONDS);
}
/**
- * Returns the given factory if non-null, or the default factory instance otherwise.
+ * Returns the factory for the given key if it exists, or the default factory instance otherwise.
*/
- private static <F> F factory(final Class<F> type, F factory) {
- if (factory == null) {
- factory = DefaultFactories.forBuildin(type);
- }
- return factory;
+ private static <F> F factory(final Class<F> type, final String key, final Map<String,?> properties) {
+ final F factory = type.cast(properties.get(key));
+ return (factory != null) ? factory : DefaultFactories.forBuildin(type);
}
/**
@@ -214,15 +307,87 @@ public class EPSGFactory extends Concurr
}
/**
- * Sets the locale to use for producing error messages.
- * The given locale will be honored on a <cite>best effort</cite> basis.
- * It does not change the way data are read from the EPSG database.
+ * Creates the EPSG schema in the database and populates the tables with geodetic definitions.
+ * This method is invoked automatically when {@link #newDataAccess()} detects that the EPSG dataset is not installed.
+ * Users can also invoke this method explicitely if they wish to force the dataset installation.
*
- * @param locale The new locale to use for error message.
- */
- public void setLocale(final Locale locale) {
- ArgumentChecks.ensureNonNull("locale", locale);
- this.locale = locale;
+ * <p>This method uses the following properties from the map specified at
+ * {@linkplain #EPSGFactory(Map) construction time}:</p>
+ *
+ * <ul class="verbose">
+ * <li><b>{@code catalog}:</b><br>
+ * a {@link String} giving the name of the database catalog where to create the EPSG schema.
+ * If non-null, that catalog shall exist prior this method call (this method does not create any catalog).
+ * If no catalog is specified or if the catalog is an empty string,
+ * then the EPSG schema will be created without catalog.
+ * If the database does not {@linkplain DatabaseMetaData#supportsCatalogsInTableDefinitions() support
+ * catalogs in table definitions} or in {@linkplain DatabaseMetaData#supportsCatalogsInDataManipulation()
+ * data manipulation}, then this property is ignored.</li>
+ *
+ * <li><b>{@code schema}:</b><br>
+ * a {@link String} giving the name of the database schema where to create the EPSG tables.
+ * That schema shall <strong>not</strong> exist prior this method call;
+ * the schema will be created by this {@code install(…)} method.
+ * If the schema is an empty string, then the tables will be created without schema.
+ * If no schema is specified, then the default schema is {@code "EPSG"}.
+ * If the database does not {@linkplain DatabaseMetaData#supportsSchemasInTableDefinitions() support
+ * schemas in table definitions} or in {@linkplain DatabaseMetaData#supportsSchemasInDataManipulation()
+ * data manipulation}, then this property is ignored.</li>
+ *
+ * <li><b>{@code scriptDirectory}:</b><br>
+ * a {@link java.nio.file.Path}, {@link java.io.File} or {@link java.net.URL} to a directory containing
+ * the SQL scripts to execute. If non-null, that directory shall contain at least files matching the
+ * {@code *Tables*.sql}, {@code *Data*.sql} and {@code *FKeys*.sql} patterns (those files are provided by EPSG).
+ * Files matching the {@code *Patches*.sql}, {@code *Indexes*.sql} and {@code *Grant*.sql} patterns
+ * (provided by Apache SIS) are optional but recommended.
+ * If no directory is specified, then this method will search for resources provided by the
+ * {@code geotk-epsg.jar} bundle.</li>
+ * </ul>
+ *
+ * <p><b>Legal constraint:</b>
+ * the EPSG dataset can not be distributed with Apache SIS at this time for licensing reasons.
+ * Users need to either install the dataset manually (for example with the help of this method),
+ * or add on the classpath a non-Apache bundle like {@code geotk-epsg.jar}.
+ * See <a href="https://issues.apache.org/jira/browse/LEGAL-183">LEGAL-183</a> for more information.</p>
+ *
+ * @param connection Connection to the database where to create the EPSG schema.
+ * @throws IOException if the SQL script can not be found or an I/O error occurred while reading them.
+ * @throws SQLException if an error occurred while writing to the database.
+ */
+ public synchronized void install(final Connection connection) throws IOException, SQLException {
+ ArgumentChecks.ensureNonNull("connection", connection);
+ final EPSGInstaller installer = new EPSGInstaller(connection);
+ try {
+ final boolean ac = connection.getAutoCommit();
+ if (ac) {
+ connection.setAutoCommit(false);
+ }
+ boolean success = false;
+ try {
+ if (!"".equals(schema)) { // Schema may be null.
+ installer.setSchema(schema != null ? schema : Constants.EPSG);
+ if (catalog != null && !catalog.isEmpty()) {
+ installer.prependNamespace(catalog);
+ }
+ }
+ installer.run(scriptDirectory);
+ success = true;
+ } finally {
+ if (ac) {
+ if (success) {
+ connection.commit();
+ } else {
+ connection.rollback();
+ }
+ connection.setAutoCommit(true);
+ }
+ if (!success) {
+ installer.logFailure(locale);
+ }
+ }
+ } finally {
+ installer.close();
+ }
}
/**
@@ -230,9 +395,14 @@ public class EPSGFactory extends Concurr
* This method is invoked automatically when a new worker is required, either because the previous
* one has been disposed after its timeout or because a new one is required for concurrency.
*
- * <p>The default implementation gets a new connection from the {@link #dataSource} and delegates to
- * {@link #newDataAccess(Connection, SQLTranslator)}, which provides an easier overriding point
- * for subclasses wanting to return a custom {@link EPSGDataAccess} instance.</p>
+ * <p>The default implementation performs the following steps:</p>
+ * <ol>
+ * <li>Gets a new connection from the {@link #dataSource}.</li>
+ * <li>If this method is invoked for the first time, verifies if the EPSG tables exists.
+ * If the tables are not found, invokes {@link #install(Connection)}.</li>
+ * <li>Delegates to {@link #newDataAccess(Connection, SQLTranslator)}, which provides an easier
+ * overriding point for subclasses wanting to return a custom {@link EPSGDataAccess} instance.</li>
+ * </ol>
*
* @return Data Access Object (DAO) to use in {@code createFoo(String)} methods.
* @throws FactoryException if the constructor failed to connect to the EPSG database.
@@ -248,12 +418,23 @@ public class EPSGFactory extends Concurr
synchronized (this) {
tr = translator;
if (tr == null) {
- translator = tr = new SQLTranslator(connection.getMetaData());
+ tr = new SQLTranslator(connection.getMetaData(), catalog, schema);
+ try {
+ if (!tr.isTableFound()) {
+ install(connection);
+ tr.setup(connection.getMetaData()); // Set only on success.
+ }
+ } finally {
+ translator = tr; // Set only after installation in order to block other threads.
+ }
}
}
}
- return newDataAccess(connection, tr);
- } catch (Exception e) {
+ if (tr.isTableFound()) {
+ return newDataAccess(connection, tr);
+ }
+ connection.close();
+ } catch (Exception e) { // Really want to catch all exceptions here.
if (connection != null) try {
connection.close();
} catch (SQLException e2) {
@@ -261,6 +442,7 @@ public class EPSGFactory extends Concurr
}
throw new UnavailableFactoryException(e.getLocalizedMessage(), e);
}
+ throw new UnavailableFactoryException(SQLTranslator.tableNotFound(locale));
}
/**
Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/SQLTranslator.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/SQLTranslator.java?rev=1728777&r1=1728776&r2=1728777&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/SQLTranslator.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/SQLTranslator.java [UTF-8] Fri Feb 5 23:41:50 2016
@@ -18,12 +18,10 @@ package org.apache.sis.referencing.facto
import java.util.Map;
import java.util.HashMap;
-import java.util.Collections;
import java.util.Locale;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
-import java.sql.SQLDataException;
import org.apache.sis.util.CharSequences;
import org.apache.sis.util.ArgumentChecks;
import org.apache.sis.util.resources.Errors;
@@ -57,16 +55,18 @@ import org.apache.sis.internal.jdk8.JDK8
* <li>{@code SELECT * FROM "Coordinate Reference System"}</li>
* <li>{@code SELECT * FROM epsg_coordinatereferencesystem} (in the default schema)</li>
* <li>{@code SELECT * FROM epsg.coordinatereferencesystem} (in the {@code "epsg"} schema)</li>
- * <li>{@code SELECT * FROM "EPSG"."Coordinate Reference System"}</li>
+ * <li>{@code SELECT * FROM epsg."Coordinate Reference System"}</li>
* </ul></div>
*
- * In addition to the MS-Access format, EPSG also provides the dataset as <cite>Data Description Language</cite> (DDL)
- * scripts for PostgreSQL, MySQL and Oracle databases. But the table names and some column names in those scripts differ
- * from the ones used in the MS-Access database. The following table summarizes the name changes:
+ * In addition to the file in MS-Access format, EPSG also provides the dataset as SQL files for PostgreSQL,
+ * MySQL and Oracle databases. Those SQL files are used as both <cite>Data Description Language</cite> (DDL)
+ * and <cite>Data Manipulation Language</cite> (DML).
+ * But the table names and some column names in those scripts differ from the ones used in the MS-Access database.
+ * The following table summarizes the name changes:
*
* <table class="sis">
* <caption>Table and column names</caption>
- * <tr><th>Element</th><th>Name in MS-Access database</th> <th>Name in DDL scripts</th></tr>
+ * <tr><th>Element</th><th>Name in MS-Access database</th> <th>Name in SQL scripts</th></tr>
* <tr><td>Table</td> <td>{@code Alias}</td> <td>{@code epsg_alias}</td></tr>
* <tr><td>Table</td> <td>{@code Area}</td> <td>{@code epsg_area}</td></tr>
* <tr><td>Table</td> <td>{@code Coordinate Axis}</td> <td>{@code epsg_coordinateaxis}</td></tr>
@@ -88,8 +88,8 @@ import org.apache.sis.internal.jdk8.JDK8
* <tr><td>Column</td> <td>{@code ORDER}</td> <td>{@code coord_axis_order}</td></tr>
* </table>
*
- * This class auto-detects the schema where the EPSG database seems to be located and whether the table names
- * are the ones used by EPSG in the MS-Access version or the PostgreSQL, MySQL or Oracle version of the database.
+ * By default this class auto-detects the schema that contains the EPSG tables and whether the table names are
+ * the ones used by EPSG in the MS-Access version or the PostgreSQL, MySQL or Oracle version of the database.
* Consequently it is legal to use the MS-Access table names, which are more readable, in a PostgreSQL database.
*
* <div class="section">Thread safety</div>
@@ -129,10 +129,34 @@ public class SQLTranslator {
static final String TABLE_PREFIX = "epsg_";
/**
- * The name of the schema where the tables are located, or {@code null} if none.
- * In the later case, table names are prefixed by {@value #TABLE_PREFIX}.
+ * The name of the catalog that contains the EPSG tables, or {@code null} or an empty string.
+ * <ul>
+ * <li>The {@code ""} value retrieves the EPSG schema without a catalog.</li>
+ * <li>The {@code null} value means that the catalog name should not be used to narrow the search.</li>
+ * </ul>
+ *
+ * <p><b>Consider this field as final.</b> This field is non-final only for construction convenience,
+ * or for updating after the {@link EPSGInstaller} class created the database.</p>
+ *
+ * @see #getCatalog()
+ */
+ private String catalog;
+
+ /**
+ * The name of the schema that contains the EPSG tables, or {@code null} or an empty string.
+ * <ul>
+ * <li>The {@code ""} value retrieves the EPSG tables without a schema.
+ * In such case, table names are prefixed by {@value #TABLE_PREFIX}.</li>
+ * <li>The {@code null} value means that the schema name should not be used to narrow the search.
+ * In such case, {@code SQLTranslator} will tries to automatically detect the schema.</li>
+ * </ul>
+ *
+ * <p><b>Consider this field as final.</b> This field is non-final only for construction convenience,
+ * or for updating after the {@link EPSGInstaller} class created the database.</p>
+ *
+ * @see #getSchema()
*/
- private final String schema;
+ private String schema;
/**
* Mapping from words used in the MS-Access database to words used in the ANSI versions of EPSG databases.
@@ -148,7 +172,8 @@ public class SQLTranslator {
* {@code true} if this class needs to quote table names. This quoting should be done only if the database
* uses the MS-Access table names, even if we are targeting a PostgreSQL, MySQL or Oracle database.
*
- * <p><b>Consider this field as final.</b> This field is non-final only for construction convenience.</p>
+ * <p><b>Consider this field as final.</b> This field is non-final only for construction convenience,
+ * or for updating after the {@link EPSGInstaller} class created the database.</p>
*/
private boolean quoteTableNames;
@@ -159,79 +184,144 @@ public class SQLTranslator {
private final String quote;
/**
- * Creates a new adapter for the database described by the given metadata.
- * This constructor:
+ * {@code true} if one of the {@link #SENTINEL} tables exist.
+ * If {@code false}, then {@link EPSGInstaller} needs to be run.
*
- * <ul>
- * <li>gets the characters to use for quoting identifiers,</li>
- * <li>finds the schema where are located the EPSG tables,</li>
- * <li>detects if the table names are the ones used in MS-Access database or in the DDL scripts.</li>
- * </ul>
+ * @see #isTableFound()
+ */
+ private boolean isTableFound;
+
+ /**
+ * Creates a new SQL translator for the database described by the given metadata.
+ * This constructor detects automatically the dialect: the characters to use for quoting identifiers,
+ * and whether the table names are the ones used in the MS-Access database or in the SQL scripts.
*
- * <div class="note"><b>API design note:</b>
- * this constructor is for sub-classing only. Otherwise, instances of {@code SQLTranslator} should not need to be
- * created explicitely since instantiations are performed automatically by {@link EPSGFactory} when first needed.</div>
+ * <p>If the given catalog or schema name is non-null, then the {@linkplain DatabaseMetaData#getTables
+ * search for EPSG tables} will be restricted to the catalog or schema of that name.
+ * An empty string ({@code ""}) means to search for tables without catalog or schema.
+ * A {@code null} value means that the catalog or schema should not be used to narrow the search.</p>
*
- * @param md Information about the database.
+ * @param md Information about the database.
+ * @param catalog The catalog where to look for EPSG schema, or {@code null} if any.
+ * @param schema The schema where to look for EPSG tables, or {@code null} if any.
* @throws SQLException if an error occurred while querying the database metadata.
*/
- protected SQLTranslator(final DatabaseMetaData md) throws SQLException {
+ public SQLTranslator(final DatabaseMetaData md, final String catalog, final String schema) throws SQLException {
ArgumentChecks.ensureNonNull("md", md);
- quote = md.getIdentifierQuoteString();
- schema = findSchema(md);
- if (quoteTableNames) {
- /*
- * MS-Access database uses a column named "ORDER" in the "Coordinate Axis" table.
- * This column has been renamed "coord_axis_order" in DLL scripts.
- * We need to check which name our current database uses.
- */
- final ResultSet result = md.getColumns(null, schema, "Coordinate Axis", "ORDER");
- try {
- if (result.next()) {
- accessToAnsi = Collections.emptyMap();
- } else {
- accessToAnsi = Collections.singletonMap("ORDER", "coord_axis_order");
- }
- } finally {
- result.close();
- }
- } else {
- accessToAnsi = new HashMap<String,String>(4);
- accessToAnsi.put("ORDER", "coord_axis_order"); // A column, not a table.
- accessToAnsi.put("Coordinate_Operation", "coordoperation");
- accessToAnsi.put("Parameter", "param");
- }
- };
+ quote = md.getIdentifierQuoteString().trim();
+ accessToAnsi = new HashMap<String,String>(4);
+ this.catalog = catalog;
+ this.schema = schema;
+ setup(md);
+ }
/**
- * Returns the schema where the EPSG tables seems to be located.
+ * Sets the value of all non-final fields. This method performs two steps:
+ *
+ * <ol class="verbose">
+ * <li>Finds the schema that seems to contain the EPSG tables. If there is more than one schema containing the
+ * tables, gives precedence to the schema named "EPSG" if one is found. If there is no schema named "EPSG",
+ * takes an arbitrary schema. It may be the empty string if the tables are not contained in a schema.</li>
+ *
+ * <li>Fills the {@link #accessToAnsi} map. That map translates the table and column names used in the SQL
+ * statements into the names used by the database. Two conventions are understood: the names used in
+ * the MS-Access database or the names used in the SQL scripts. Both of them are distributed by EPSG.</li>
+ * </ol>
*/
- private String findSchema(final DatabaseMetaData md) throws SQLException {
+ final void setup(final DatabaseMetaData md) throws SQLException {
final boolean toUpperCase = md.storesUpperCaseIdentifiers();
for (int i = SENTINEL.length; --i >= 0;) {
String table = SENTINEL[i];
if (toUpperCase && i != MIXED_CASE) {
table = table.toUpperCase(Locale.US);
}
- final ResultSet result = md.getTables(null, null, table, null);
+ final ResultSet result = md.getTables(catalog, schema, table, null);
try {
if (result.next()) {
+ isTableFound = true;
quoteTableNames = (i == MIXED_CASE);
- /*
- * If there is more than one schema containing the tables, give precedence to the schema
- * named "EPSG" if one is found. If there is no "EPSG" schema, take an arbitrary schema.
- */
- String schema;
do {
- schema = result.getString("TABLE_SCHEM");
+ catalog = result.getString("TABLE_CAT");
+ schema = result.getString("TABLE_SCHEM");
} while (!Constants.EPSG.equalsIgnoreCase(schema) && result.next());
- return schema;
+ if (schema == null) schema = "";
+ break;
}
} finally {
result.close();
}
}
- throw new SQLDataException(Errors.format(Errors.Keys.TableNotFound_1, SENTINEL[MIXED_CASE]));
+ /*
+ * At this point the catalog and schema have been found or confirmed, or are still null
+ * if we did not found them. Now fill the 'accessToAnsi' map.
+ */
+ boolean translateColumns = true;
+ accessToAnsi.clear();
+ if (quoteTableNames) {
+ /*
+ * MS-Access database uses a column named "ORDER" in the "Coordinate Axis" table.
+ * This column has been renamed "coord_axis_order" in DLL scripts.
+ * We need to check which name our current database uses.
+ */
+ final ResultSet result = md.getColumns(catalog, schema, "Coordinate Axis", "ORDER");
+ try {
+ translateColumns = !result.next();
+ } finally {
+ result.close();
+ }
+ } else {
+ accessToAnsi.put("Coordinate_Operation", "coordoperation");
+ accessToAnsi.put("Parameter", "param");
+ }
+ if (translateColumns) {
+ accessToAnsi.put("ORDER", "coord_axis_order");
+ }
+ };
+
+ /**
+ * Returns the catalog that contains the EPSG schema. This is the catalog specified at construction time
+ * if it was non-null, or the catalog discovered by the constructor otherwise.
+ * Note that this method may still return {@code null} if the EPSG tables were not found or if the database
+ * does not {@linkplain DatabaseMetaData#supportsCatalogsInDataManipulation() supports catalogs}.
+ *
+ * @return The catalog that contains the EPSG schema, or {@code null}.
+ */
+ public String getCatalog() {
+ return catalog;
+ }
+
+ /**
+ * Returns the schema that contains the EPSG tables. This is the schema specified at construction time
+ * if it was non-null, or the schema discovered by the constructor otherwise.
+ * Note that this method may still return {@code null} if the EPSG tables were not found or if the database
+ * does not {@linkplain DatabaseMetaData#supportsSchemasInDataManipulation() supports schemas}.
+ *
+ * @return The schema that contains the EPSG tables, or {@code null}.
+ */
+ public String getSchema() {
+ return schema;
+ }
+
+ /**
+ * Returns whether the EPSG tables have been found.
+ * If {@code false}, then {@link EPSGInstaller} needs to be run.
+ */
+ final boolean isTableFound() {
+ return isTableFound;
+ }
+
+ /**
+ * Returns the error message for the exception to throw if the EPSG tables are not found and we can not create them.
+ */
+ static String tableNotFound(final Locale locale) {
+ return Errors.getResources(locale).getString(Errors.Keys.TableNotFound_1, SENTINEL[MIXED_CASE]);
+ }
+
+ /**
+ * If the given string is empty, returns {@code null} instead.
+ */
+ private static String nonEmpty(final String s) {
+ return (s != null && !s.isEmpty()) ? s : null;
}
/**
@@ -242,7 +332,9 @@ public class SQLTranslator {
* @return The SQL statement adapted to the dialect of the target database.
*/
public String apply(final String sql) {
- if (schema == null && accessToAnsi.isEmpty() && quote.trim().isEmpty()) {
+ final String catalog = nonEmpty(this.catalog);
+ final String schema = nonEmpty(this.schema);
+ if (quote.isEmpty() && accessToAnsi.isEmpty() && schema == null && catalog == null) {
return sql;
}
final StringBuilder ansi = new StringBuilder(sql.length() + 16);
@@ -267,6 +359,9 @@ public class SQLTranslator {
if (CharSequences.isUpperCase(name)) {
ansi.append(JDK8.getOrDefault(accessToAnsi, name, name));
} else {
+ if (catalog != null) {
+ ansi.append(quote).append(catalog).append(quote).append('.');
+ }
if (schema != null) {
ansi.append(quote).append(schema).append(quote).append('.');
}
Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/package-info.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/package-info.java?rev=1728777&r1=1728776&r2=1728777&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/package-info.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/package-info.java [UTF-8] Fri Feb 5 23:41:50 2016
@@ -17,10 +17,12 @@
/**
* Factories for geodetic objects defined in a SQL database.
- * Every classes in this package require a connection to a database, which may be on Apache Derby (a.k.a. JavaDB),
- * PostgreSQL or MS-Access. The connection is obtained by the first of the following data sources which is found:
+ * The main class in this package is {@link org.apache.sis.referencing.factory.sql.EPSGFactory},
+ * which requires a {@link javax.sql.DataSource} providing connections to an EPSG database.
+ * By default Apache SIS used Apache Derby (a.k.a. JavaDB), but the database can also be PostgreSQL or MS-Access.
+ * The connection is obtained by the first of the following data sources which is found:
*
- * <ol>
+ * <ol class="verbose">
* <li>If a {@linkplain javax.naming.InitialContext JNDI context} exists,
* the {@link javax.sql.DataSource} registered under the {@code "java:comp/env/jdbc/SpatialMetadata"} name.</li>
* <li>If the {@code SIS_DATA} {@linkplain System#getenv(String) environment variable} is defined,
@@ -38,12 +40,18 @@
* A widely-used factory is the <a href="http://www.epsg.org">EPSG geodetic dataset</a>.
* EPSG codes are numerical identifiers.
* For example {@code "EPSG::4326"} is the EPSG identifier for the <cite>"WGS 84"</cite> geographic CRS.
- * However, the Apache SIS implementation accepts names as well as numeric identifiers.
- * For example {@code createProjectedCRS("NTF (Paris) / Lambert zone II")} and {@code createProjectedCRS("27572")}
- * both fetch the same object. However names may be ambiguous since the same name may be used for more than one object.
+ * As an extension, the Apache SIS implementation accepts names as well as numeric identifiers.
+ * For example the two following method calls fetch the same object:
+ *
+ * <ul>
+ * <li>{@code createProjectedCRS("NTF (Paris) / Lambert zone II")}</li>
+ * <li>{@code createProjectedCRS("27572")}</li>
+ * </ul>
+ *
+ * However names may be ambiguous since the same name may be used for more than one object.
* This is the case of <cite>"WGS 84"</cite> for example. If such an ambiguity is found, an exception will be thrown.
*
- * <p>When an error is discovered in a Coordinate Reference System definition, the EPSG group does not apply the
+ * <p>When an error is discovered in a Coordinate Reference System (CRS) definition, the EPSG group does not apply the
* correction directly on the erroneous object (unless the correction is very minor).
* Instead, the erroneous object is deprecated and a new one is created.
* Apache SIS handles deprecated objects as below:</p>
@@ -51,8 +59,7 @@
* <ul>
* <li>Deprecated objects are not listed in the collection returned by the
* {@link org.apache.sis.referencing.factory.sql.EPSGDataAccess#getAuthorityCodes getAuthorityCodes(…)} method.</li>
- * <li>However if the code of a deprecated object is given directly to {@code getAuthorityCodes(…).contains(…)},
- * {@code getDescriptionText(…)} or any {@code createFoo(…)} method, it will be recognized.</li>
+ * <li>All method expecting an EPSG code in argument accept also the codes of deprecated objects.</li>
* <li>If a deprecated object is created by a call to {@code createFoo(…)}, a warning will be logged
* with a message proposing a replacement.</li>
* </ul>
Modified: sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/sql/EPSGFactoryTest.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/sql/EPSGFactoryTest.java?rev=1728777&r1=1728776&r2=1728777&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/sql/EPSGFactoryTest.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/sql/EPSGFactoryTest.java [UTF-8] Fri Feb 5 23:41:50 2016
@@ -16,9 +16,11 @@
*/
package org.apache.sis.referencing.factory.sql;
+import java.util.Map;
import java.util.Set;
import java.util.List;
import java.util.Locale;
+import java.util.HashMap;
import java.util.Iterator;
import java.util.Collections;
import javax.measure.unit.Unit;
@@ -101,8 +103,12 @@ public final strictfp class EPSGFactoryT
@BeforeClass
public static void createFactory() throws FactoryException {
final GeodeticObjectFactory f = new GeodeticObjectFactory();
+ final Map<String,Object> properties = new HashMap<String,Object>(6);
+ assertNull(properties.put("datumFactory", f));
+ assertNull(properties.put("csFactory", f));
+ assertNull(properties.put("crsFactory", f));
try {
- factory = new EPSGFactory(null, null, f, f, f, null, null, null);
+ factory = new EPSGFactory(properties);
} catch (UnavailableFactoryException e) {
Logging.getLogger(Loggers.CRS_FACTORY).warning(e.toString());
// Leave INSTANCE to null. This will have the effect of skipping tests.
Modified: sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/report/CoordinateOperationMethods.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/report/CoordinateOperationMethods.java?rev=1728777&r1=1728775&r2=1728777&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/report/CoordinateOperationMethods.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/report/CoordinateOperationMethods.java [UTF-8] Fri Feb 5 23:41:50 2016
@@ -25,7 +25,6 @@ import java.util.Collections;
import java.io.IOException;
import org.opengis.util.FactoryException;
import org.opengis.util.GenericName;
-import org.opengis.metadata.Identifier;
import org.opengis.metadata.extent.GeographicBoundingBox;
import org.opengis.parameter.*;
import org.opengis.referencing.operation.*;
@@ -51,6 +50,7 @@ import org.apache.sis.util.Numbers;
// Branch-dependent imports
import org.apache.sis.internal.jdk8.JDK8;
+import org.opengis.referencing.ReferenceIdentifier;
/**
@@ -249,7 +249,7 @@ public strictfp class CoordinateOperatio
* ──────────────── EPSG IDENTIFIERS ────────────────────────────────────
*/
final StringBuilder buffer = new StringBuilder();
- for (final Identifier id : method.getIdentifiers()) {
+ for (final ReferenceIdentifier id : method.getIdentifiers()) {
if (Constants.EPSG.equalsIgnoreCase(id.getCodeSpace())) {
if (buffer.length() != 0) {
buffer.append(", ");
@@ -386,7 +386,7 @@ public strictfp class CoordinateOperatio
private void writeName(final ParameterDescriptor<?> param) throws IOException {
final int td = openTag("td class=\"sep\"");
openTag("details");
- final Identifier name = param.getName();
+ final ReferenceIdentifier name = param.getName();
final String codeSpace = name.getCodeSpace();
if (Constants.EPSG.equalsIgnoreCase(codeSpace)) {
println("summary", escape(name.getCode()));
@@ -535,8 +535,8 @@ public strictfp class CoordinateOperatio
/**
* Returns the first EPSG code found in the given collection, or {@code null} if none.
*/
- private static String getFirstEpsgCode(final Iterable<? extends Identifier> identifiers) {
- for (final Identifier id : identifiers) {
+ private static String getFirstEpsgCode(final Iterable<? extends ReferenceIdentifier> identifiers) {
+ for (final ReferenceIdentifier id : identifiers) {
if (Constants.EPSG.equalsIgnoreCase(id.getCodeSpace())) {
return id.getCode();
}
Modified: sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java?rev=1728777&r1=1728776&r2=1728777&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java [UTF-8] Fri Feb 5 23:41:50 2016
@@ -184,6 +184,7 @@ import org.junit.BeforeClass;
org.apache.sis.referencing.factory.IdentifiedObjectFinderTest.class,
org.apache.sis.referencing.factory.MultiAuthoritiesFactoryTest.class,
org.apache.sis.referencing.factory.sql.EPSGFactoryTest.class,
+ org.apache.sis.referencing.factory.sql.EPSGInstallerTest.class,
org.apache.sis.referencing.EPSGFactoryFallbackTest.class,
org.apache.sis.referencing.AuthorityFactoriesTest.class,
org.apache.sis.referencing.CRSTest.class,
@@ -200,7 +201,7 @@ import org.junit.BeforeClass;
org.apache.sis.geometry.CurveExtremumTest.class,
org.apache.sis.geometry.EnvelopesTest.class,
- org.apache.sis.distance.LatLonPointRadiusTest.class, // Pending refactoring in a geometry package.
+ org.apache.sis.distance.LatLonPointRadiusTest.class, // Pending refactoring in a geometry package.
org.apache.sis.referencing.operation.builder.LinearTransformBuilderTest.class,
org.apache.sis.internal.referencing.ServicesForMetadataTest.class,
Modified: sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/jdk7/Files.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/jdk7/Files.java?rev=1728777&r1=1728776&r2=1728777&view=diff
==============================================================================
--- sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/jdk7/Files.java [UTF-8] (original)
+++ sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/jdk7/Files.java [UTF-8] Fri Feb 5 23:41:50 2016
@@ -25,6 +25,7 @@ import java.io.OutputStreamWriter;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
+import java.io.InputStream;
import java.io.RandomAccessFile;
import java.nio.channels.ByteChannel;
import java.nio.charset.Charset;
@@ -124,6 +125,20 @@ public final class Files {
}
/**
+ * Creates a new input stream. The input stream is intentionally not buffered;
+ * it is caller's responsibility to provide buffering.
+ *
+ * @param path The path of the file to read.
+ * @return The input stream.
+ * @throws IOException if an error occurred while creating the input stream.
+ *
+ * @since 0.7
+ */
+ public static InputStream newInputStream(final Path path) throws IOException {
+ return new FileInputStream(path);
+ }
+
+ /**
* Creates a new buffered reader for the given character encoding.
*
* @param path The path of the file to read.
Modified: sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/jdk8/JDK8.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/jdk8/JDK8.java?rev=1728777&r1=1728776&r2=1728777&view=diff
==============================================================================
--- sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/jdk8/JDK8.java [UTF-8] (original)
+++ sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/jdk8/JDK8.java [UTF-8] Fri Feb 5 23:41:50 2016
@@ -220,6 +220,22 @@ public final class JDK8 {
}
/**
+ * Replaces the values for all entries in the given map.
+ *
+ * @param <K> The type of keys.
+ * @param <V> The type of values.
+ * @param map The map from where to replace the values.
+ * @param function The function performing the value replacements.
+ *
+ * @since 0.7
+ */
+ public static <K,V> void replaceAll(final Map<K,V> map, BiFunction<? super K, ? super V, ? extends V> function) {
+ for (final Map.Entry<K,V> entry : map.entrySet()) {
+ entry.setValue(function.apply(entry.getKey(), entry.getValue()));
+ }
+ }
+
+ /**
* Atomically computes and stores the value for the given key. This is a substitute for
* {@link ConcurrentMap#compute(java.lang.Object, java.util.function.BiFunction)}
* on pre-JDK8 branches.
Modified: sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/system/DataDirectory.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/system/DataDirectory.java?rev=1728777&r1=1728776&r2=1728777&view=diff
==============================================================================
--- sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/system/DataDirectory.java [UTF-8] (original)
+++ sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/system/DataDirectory.java [UTF-8] Fri Feb 5 23:41:50 2016
@@ -114,7 +114,7 @@ public enum DataDirectory {
public static synchronized Path getRootDirectory() {
if (rootDirectory == null) try {
final String dir = System.getenv(ENV);
- if (dir == null) {
+ if (dir == null || dir.isEmpty()) {
warning("getRootDirectory", null, Messages.Keys.DataDirectoryNotSpecified_1, ENV);
} else try {
final Path path = Paths.get(dir);
Modified: sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/util/MetadataServices.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/util/MetadataServices.java?rev=1728777&r1=1728776&r2=1728777&view=diff
==============================================================================
--- sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/util/MetadataServices.java [UTF-8] (original)
+++ sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/util/MetadataServices.java [UTF-8] Fri Feb 5 23:41:50 2016
@@ -16,6 +16,7 @@
*/
package org.apache.sis.internal.util;
+import java.util.Locale;
import org.opengis.metadata.citation.Citation;
import org.apache.sis.internal.simple.CitationConstant;
import org.apache.sis.internal.system.Modules;
@@ -111,4 +112,23 @@ public class MetadataServices extends Op
public Citation createCitation(final String key) {
return null;
}
+
+ /**
+ * Returns information about the Apache SIS configuration to be reported in {@link org.apache.sis.setup.About}.
+ * This method is invoked only for aspects that depends on other modules than {@code sis-utility}.
+ *
+ * <p>Current keys are:</p>
+ * <ul>
+ * <li>{@code "EPSG"}: version of EPSG database.</li>
+ * </ul>
+ *
+ * @param key A key identifying the information to return.
+ * @param locale Language to use if possible.
+ * @return The information, or {@code null} if none.
+ *
+ * @see org.apache.sis.internal.metadata.ReferencingServices#getInformation(String)
+ */
+ public String getInformation(String key, Locale locale) {
+ return null;
+ }
}
Modified: sis/trunk/core/sis-utility/src/main/java/org/apache/sis/setup/About.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-utility/src/main/java/org/apache/sis/setup/About.java?rev=1728777&r1=1728776&r2=1728777&view=diff
==============================================================================
--- sis/trunk/core/sis-utility/src/main/java/org/apache/sis/setup/About.java [UTF-8] (original)
+++ sis/trunk/core/sis-utility/src/main/java/org/apache/sis/setup/About.java [UTF-8] Fri Feb 5 23:41:50 2016
@@ -48,6 +48,8 @@ import org.apache.sis.util.resources.Voc
import org.apache.sis.util.collection.TreeTable;
import org.apache.sis.util.collection.TreeTables;
import org.apache.sis.util.collection.DefaultTreeTable;
+import org.apache.sis.internal.util.MetadataServices;
+import org.apache.sis.internal.util.Constants;
import org.apache.sis.internal.system.Loggers;
import org.apache.sis.internal.system.Modules;
import org.apache.sis.internal.system.Shutdown;
@@ -233,6 +235,13 @@ fill: for (int i=0; ; i++) {
break;
}
case 4: {
+ if (sections.contains(VERSIONS)) {
+ nameKey = Vocabulary.Keys.GeodeticDataset;
+ value = MetadataServices.getInstance().getInformation(Constants.EPSG, locale);
+ }
+ break;
+ }
+ case 5: {
newSection = LOCALIZATION;
if (sections.contains(LOCALIZATION)) {
final Locale current = Locale.getDefault();
@@ -247,7 +256,7 @@ fill: for (int i=0; ; i++) {
}
break;
}
- case 5: {
+ case 6: {
if (sections.contains(LOCALIZATION)) {
final TimeZone current = TimeZone.getDefault();
if (current != null) {
@@ -268,7 +277,7 @@ fill: for (int i=0; ; i++) {
}
break;
}
- case 6: {
+ case 7: {
if (sections.contains(LOCALIZATION)) {
nameKey = Vocabulary.Keys.CurrentDateTime;
final DateFormat df = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, formatLocale);
@@ -279,7 +288,7 @@ fill: for (int i=0; ; i++) {
}
break;
}
- case 7: {
+ case 8: {
if (sections.contains(LOCALIZATION)) {
final Charset current = Charset.defaultCharset();
if (current != null) {
@@ -299,7 +308,7 @@ fill: for (int i=0; ; i++) {
}
break;
}
- case 8: {
+ case 9: {
newSection = LOGGING;
if (sections.contains(LOGGING)) {
nameKey = Vocabulary.Keys.Implementation;
@@ -308,7 +317,7 @@ fill: for (int i=0; ; i++) {
}
break;
}
- case 9: {
+ case 10: {
if (sections.contains(LOGGING)) {
nameKey = Vocabulary.Keys.Level;
final Level level = Logging.getLogger("").getLevel(); // Root logger level.
@@ -325,7 +334,7 @@ fill: for (int i=0; ; i++) {
}
break;
}
- case 10: {
+ case 11: {
newSection = PATHS;
if (sections.contains(PATHS)) {
nameKey = Vocabulary.Keys.UserHome;
@@ -333,14 +342,14 @@ fill: for (int i=0; ; i++) {
}
break;
}
- case 11: {
+ case 12: {
if (sections.contains(PATHS)) {
nameKey = Vocabulary.Keys.CurrentDirectory;
value = getProperty("user.dir");
}
break;
}
- case 12: {
+ case 13: {
if (sections.contains(PATHS)) {
nameKey = Vocabulary.Keys.DataDirectory;
value = System.getenv(DataDirectory.ENV);
@@ -357,21 +366,21 @@ fill: for (int i=0; ; i++) {
}
break;
}
- case 13: {
+ case 14: {
if (sections.contains(PATHS)) {
nameKey = Vocabulary.Keys.TemporaryFiles;
value = getProperty("java.io.tmpdir");
}
break;
}
- case 14: {
+ case 15: {
if (sections.contains(PATHS)) {
nameKey = Vocabulary.Keys.JavaHome;
value = javaHome = getProperty("java.home");
}
break;
}
- case 15: {
+ case 16: {
newSection = LIBRARIES;
if (sections.contains(LIBRARIES)) {
nameKey = Vocabulary.Keys.JavaExtensions;
@@ -379,7 +388,7 @@ fill: for (int i=0; ; i++) {
}
break;
}
- case 16: {
+ case 17: {
if (sections.contains(LIBRARIES)) {
nameKey = Vocabulary.Keys.Classpath;
value = classpath(getProperty("java.class.path"), false);
@@ -546,7 +555,7 @@ pathTree: for (int j=0; ; j++) {
for (final Map.Entry<File,CharSequence> entry : files.entrySet()) {
CharSequence title = entry.getValue();
if (title != null) {
- continue; // This file has already been processed by a recursive method invocation.
+ continue; // This file has already been processed by a recursive method invocation.
}
final File file = entry.getKey();
if (file.isFile() && file.canRead()) {
@@ -571,7 +580,7 @@ pathTree: for (int j=0; ; j++) {
if (classpath(attributes.getValue(Attributes.Name.CLASS_PATH),
file.getParentFile(), false, files))
{
- break; // Necessary for avoiding ConcurrentModificationException.
+ break; // Necessary for avoiding ConcurrentModificationException.
}
}
}
@@ -609,7 +618,7 @@ pathTree: for (int j=0; ; j++) {
if (s1 >= 0) {
final int s0 = CharSequences.lastIndexOf(name, File.separatorChar, 0, s1) + 1;
final StringBuilder buffer = new StringBuilder(s2 - s0).append(name, s0, s2);
- buffer.setCharAt(s1-s0, '-');
+ buffer.setCharAt(s1 - s0, '-');
if (CharSequences.regionMatches(name, s2+1, buffer)) {
buffer.setLength(0);
node.setValue(NAME, buffer.append(name, 0, s0).append("(…)").append(name, s2, length));
Modified: sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java?rev=1728777&r1=1728776&r2=1728777&view=diff
==============================================================================
--- sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java [UTF-8] (original)
+++ sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java [UTF-8] Fri Feb 5 23:41:50 2016
@@ -276,6 +276,11 @@ public final class Errors extends Indexe
public static final short EmptyProperty_1 = 23;
/**
+ * An error occurred in file “{0}” at Line {1}.
+ */
+ public static final short ErrorInFileAtLine_2 = 216;
+
+ /**
* Error in “{0}”: {1}
*/
public static final short ErrorIn_2 = 190;
Modified: sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties?rev=1728777&r1=1728776&r2=1728777&view=diff
==============================================================================
--- sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties [ISO-8859-1] (original)
+++ sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties [ISO-8859-1] Fri Feb 5 23:41:50 2016
@@ -67,6 +67,7 @@ EmptyDictionary = The
EmptyEnvelope2D = Envelope must be at least two-dimensional and non-empty.
EmptyProperty_1 = Property named \u201c{0}\u201d shall not be empty.
ErrorIn_2 = Error in \u201c{0}\u201d: {1}
+ErrorInFileAtLine_2 = An error occurred in file \u201c{0}\u201d at Line {1}.
ExcessiveArgumentSize_3 = Argument \u2018{0}\u2019 shall not contain more than {1} elements. A number of {2} is excessive.
ExcessiveListSize_2 = A size of {1} elements is excessive for the \u201c{0}\u201d list.
ExcessiveNumberOfDimensions_1 = For this algorithm, {0} is an excessive number of dimensions.
Modified: sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties?rev=1728777&r1=1728776&r2=1728777&view=diff
==============================================================================
--- sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties [ISO-8859-1] (original)
+++ sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties [ISO-8859-1] Fri Feb 5 23:41:50 2016
@@ -64,6 +64,7 @@ EmptyDictionary = Le d
EmptyEnvelope2D = L\u2019enveloppe doit avoir au moins deux dimensions et ne pas \u00eatre vide.
EmptyProperty_1 = La propri\u00e9t\u00e9 nomm\u00e9e \u00ab\u202f{0}\u202f\u00bb ne doit pas \u00eatre vide.
ErrorIn_2 = Erreur dans \u00ab\u202f{0}\u202f\u00bb\u2008: {1}
+ErrorInFileAtLine_2 = Une erreur est survenue dans le fichier \u00ab\u202f{0}\u202f\u00bb \u00e0 la ligne {1}.
ExcessiveArgumentSize_3 = L\u2019argument \u2018{0}\u2019 ne peut pas contenir plus de {1} \u00e9l\u00e9ments. Un nombre de {2} est excessif.
ExcessiveListSize_2 = Une taille de {1} \u00e9l\u00e9ments est excessive pour la liste \u00ab\u202f{0}\u202f\u00bb.
ExcessiveNumberOfDimensions_1 = Pour cet algorithme, {0} est un trop grand nombre de dimensions.
Modified: sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Messages.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Messages.java?rev=1728777&r1=1728776&r2=1728777&view=diff
==============================================================================
--- sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Messages.java [UTF-8] (original)
+++ sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Messages.java [UTF-8] Fri Feb 5 23:41:50 2016
@@ -67,6 +67,11 @@ public final class Messages extends Inde
public static final short AmbiguousEllipsoid_1 = 30;
/**
+ * Can not create the {0} schema in database.
+ */
+ public static final short CanNotCreateSchema_1 = 41;
+
+ /**
* Can not instantiate the object of type ‘{0}’ identified by “{1}”. Reason is:{2}
*/
public static final short CanNotInstantiateForIdentifier_3 = 35;
@@ -113,6 +118,11 @@ public final class Messages extends Inde
public static final short CreatedNamedObject_2 = 16;
/**
+ * Creating {0} schema in the “{1}” database.
+ */
+ public static final short CreatingSchema_2 = 39;
+
+ /**
* {0} dataset version {1} on “{2}” version {3}.
*/
public static final short DataBase_4 = 28;
@@ -193,6 +203,11 @@ public final class Messages extends Inde
public static final short IncompleteParsing_1 = 14;
/**
+ * Inserted {0} records in {1} seconds.
+ */
+ public static final short InsertDuration_2 = 40;
+
+ /**
* No object associated to the “{0}” JNDI name.
*/
public static final short JNDINotSpecified_1 = 32;
Modified: sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Messages.properties
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Messages.properties?rev=1728777&r1=1728776&r2=1728777&view=diff
==============================================================================
--- sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Messages.properties [ISO-8859-1] (original)
+++ sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Messages.properties [ISO-8859-1] Fri Feb 5 23:41:50 2016
@@ -16,6 +16,7 @@
#
AlreadyRegistered_2 = {0} \u201c{1}\u201d is already registered. The second instance will be ignored.
AmbiguousEllipsoid_1 = Ambiguity between inverse flattening and semi minor axis length for \u201c{0}\u201d. Using inverse flattening.
+CanNotCreateSchema_1 = Can not create the {0} schema in database.
# In following message, the first characters of parameter {2} should be a line separator ("\r", "\n" or "\r\n").
CanNotInstantiateForIdentifier_3 = Can not instantiate the object of type \u2018{0}\u2019 identified by \u201c{1}\u201d. Reason is:{2}
ChangedContainerCapacity_2 = Changed the container capacity from {0} to {1} elements.
@@ -26,6 +27,7 @@ CreatedNamedObject_2 = Creat
CreatedIdentifiedObject_3 = Created an instance of \u2018{0}\u2019 named \u201c{1}\u201d with the \u201c{2}\u201d identifier.
CreateDuration_2 = Created an instance of \u2018{0}\u2019 in {1} seconds.
CreateDurationFromIdentifier_3 = Created an instance of \u2018{0}\u2019 from the \u201c{1}\u201d identifier in {2} seconds.
+CreatingSchema_2 = Creating {0} schema in the \u201c{1}\u201d database.
DataBase_4 = {0} dataset version {1} on \u201c{2}\u201d version {3}.
DataDirectory_2 = Environment variable {0} specifies the \u201c{1}\u201d data directory.
DataDirectoryDoesNotExist_2 = The {0} environment variable is defined, but the given \u201c{1}\u201d value is not an existing directory.
@@ -41,6 +43,7 @@ IgnoredPropertiesAfterFirst_1 = Ignor
IgnoredPropertyAssociatedTo_1 = Ignored property associated to \u2018{0}\u2019.
IgnoredServiceProvider_3 = More than one service provider of type \u2018{0}\u2019 are declared for \u201c{1}\u201d. Only the first provider (an instance of \u2018{2}\u2019) will be used.
IncompleteParsing_1 = Parsing of \u201c{0}\u201d done, but some elements were ignored.
+InsertDuration_2 = Inserted {0} records in {1} seconds.
JNDINotSpecified_1 = No object associated to the \u201c{0}\u201d JNDI name.
LoadingDatumShiftFile_1 = Loading datum shift file \u201c{0}\u201d.
LocalesDiscarded = Text were discarded for some locales.
Modified: sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Messages_fr.properties
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Messages_fr.properties?rev=1728777&r1=1728776&r2=1728777&view=diff
==============================================================================
--- sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Messages_fr.properties [ISO-8859-1] (original)
+++ sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Messages_fr.properties [ISO-8859-1] Fri Feb 5 23:41:50 2016
@@ -23,6 +23,7 @@
#
AlreadyRegistered_2 = Le {0} \u00ab\u202f{1}\u202f\u00bb est d\u00e9j\u00e0 inscrit dans le registre. La seconde instance sera ignor\u00e9e.
AmbiguousEllipsoid_1 = Ambigu\u00eft\u00e9 entre l\u2019aplatissement et la longueur du semi-axe mineur pour \u00ab\u202f{0}\u202f\u00bb. Utilise l\u2019aplatissement.
+CanNotCreateSchema_1 = Ne peut pas cr\u00e9er le sch\u00e9ma {0} dans la base de donn\u00e9es.
# In following message, the first characters of parameter {2} should be a line separator ("\r", "\n" or "\r\n").
CanNotInstantiateForIdentifier_3 = Ne peut pas cr\u00e9er l\u2019objet de type \u2018{0}\u2019 identifi\u00e9 par \u00ab\u202f{1}\u202f\u00bb. La raison est\u00a0:{2}
ChangedContainerCapacity_2 = Changement de la capacit\u00e9 du conteneur de {0} vers {1} \u00e9l\u00e9ments.
@@ -33,6 +34,7 @@ CreatedNamedObject_2 = Cr\u0
CreatedIdentifiedObject_3 = Cr\u00e9ation d\u2019une instance de \u2018{0}\u2019 nomm\u00e9e \u00ab\u202f{1}\u202f\u00bb avec l\u2019identifiant \u00ab\u202f{2}\u202f\u00bb.
CreateDuration_2 = Cr\u00e9ation d\u2019une instance de \u2018{0}\u2019 en {1} secondes.
CreateDurationFromIdentifier_3 = Cr\u00e9ation d\u2019une instance de \u2018{0}\u2019 \u00e0 partir de l\u2019identifiant \u00ab\u202f{1}\u202f\u00bb en {2} secondes.
+CreatingSchema_2 = Cr\u00e9ation du sch\u00e9ma {0} dans la base de donn\u00e9es \u00ab\u202f{1}\u202f\u00bb.
DataBase_4 = Base de donn\u00e9es {0} version {1} sur \u00ab\u202f{2}\u202f\u00bb version {3}.
DataDirectory_2 = La variable environnementale {0} sp\u00e9cifie le r\u00e9pertoire de donn\u00e9es \u00ab\u202f{1}\u202f\u00bb.
DataDirectoryDoesNotExist_2 = La variable environnementale {0} est bien d\u00e9finie, mais sa valeur \u00ab\u202f{1}\u202f\u00bb n\u2019est pas un r\u00e9pertoire existant.
@@ -48,6 +50,7 @@ IgnoredPropertiesAfterFirst_1 = Des p
IgnoredPropertyAssociatedTo_1 = Une propri\u00e9t\u00e9 associ\u00e9e \u00e0 \u2018{0}\u2019 a \u00e9t\u00e9 ignor\u00e9e.
IgnoredServiceProvider_3 = Plusieurs fournisseurs de service de type \u2018{0}\u2019 sont d\u00e9clar\u00e9s pour \u00ab\u202f{1}\u202f\u00bb. Seul le premier fournisseur (une instance de \u2018{2}\u2019) sera utilis\u00e9.
IncompleteParsing_1 = La lecture de \u00ab\u202f{0}\u202f\u00bb a \u00e9t\u00e9 faite, mais en ignorant certains \u00e9l\u00e9ments.
+InsertDuration_2 = {0} enregistrements ont \u00e9t\u00e9 ajout\u00e9s en {1} secondes.
JNDINotSpecified_1 = Aucun objet n\u2019est associ\u00e9 au nom JNDI \u00ab\u202f{0}\u202f\u00bb.
LoadingDatumShiftFile_1 = Chargement du fichier de changement de r\u00e9f\u00e9rentiel \u00ab\u202f{0}\u202f\u00bb.
LocalesDiscarded = Des textes ont \u00e9t\u00e9 ignor\u00e9s pour certaines langues.
Modified: sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary.java?rev=1728777&r1=1728776&r2=1728777&view=diff
==============================================================================
--- sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary.java [UTF-8] (original)
+++ sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary.java [UTF-8] Fri Feb 5 23:41:50 2016
@@ -206,6 +206,11 @@ public final class Vocabulary extends In
public static final short EllipsoidalHeight = 18;
/**
+ * Geodetic dataset
+ */
+ public static final short GeodeticDataset = 95;
+
+ /**
* Height
*/
public static final short Height = 69;
Modified: sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary.properties
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary.properties?rev=1728777&r1=1728776&r2=1728777&view=diff
==============================================================================
--- sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary.properties [ISO-8859-1] (original)
+++ sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary.properties [ISO-8859-1] Fri Feb 5 23:41:50 2016
@@ -44,6 +44,7 @@ DittoMark = \u2033
DublinJulian = Dublin Julian
Ellipsoid = Ellipsoid
EllipsoidalHeight = Ellipsoidal height
+GeodeticDataset = Geodetic dataset
Height = Height
Identifier = Identifier
Implementation = Implementation
Modified: sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary_fr.properties
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary_fr.properties?rev=1728777&r1=1728776&r2=1728777&view=diff
==============================================================================
--- sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary_fr.properties [ISO-8859-1] (original)
+++ sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary_fr.properties [ISO-8859-1] Fri Feb 5 23:41:50 2016
@@ -51,6 +51,7 @@ DittoMark = \u2033
DublinJulian = Julien Dublin
Ellipsoid = Ellipso\u00efde
EllipsoidalHeight = Hauteur ellipso\u00efdale
+GeodeticDataset = Base de donn\u00e9es g\u00e9od\u00e9sique
Height = Hauteur
Identifier = Identifiant
Implementation = Impl\u00e9mentation
Modified: sis/trunk/ide-project/NetBeans/build.xml
URL: http://svn.apache.org/viewvc/sis/trunk/ide-project/NetBeans/build.xml?rev=1728777&r1=1728776&r2=1728777&view=diff
==============================================================================
--- sis/trunk/ide-project/NetBeans/build.xml (original)
+++ sis/trunk/ide-project/NetBeans/build.xml Fri Feb 5 23:41:50 2016
@@ -157,6 +157,13 @@
</fileset>
</concat>
+ <!-- Initializer implementations to be loaded by ServiceLoader. -->
+ <concat destfile="${build.classes.dir}/META-INF/services/org.apache.sis.internal.metadata.sql.Initializer" encoding="UTF-8" fixlastline="yes">
+ <fileset dir="${project.root}">
+ <include name="*/*/src/main/resources/META-INF/services/org.apache.sis.internal.metadata.sql.Initializer"/>
+ </fileset>
+ </concat>
+
<!-- DataStoreProvider implementations to be loaded by ServiceLoader. -->
<concat destfile="${build.classes.dir}/META-INF/services/org.apache.sis.storage.DataStoreProvider" encoding="UTF-8" fixlastline="yes">
<fileset dir="${project.root}">
Modified: sis/trunk/ide-project/NetBeans/nbproject/project.properties
URL: http://svn.apache.org/viewvc/sis/trunk/ide-project/NetBeans/nbproject/project.properties?rev=1728777&r1=1728776&r2=1728777&view=diff
==============================================================================
--- sis/trunk/ide-project/NetBeans/nbproject/project.properties [ISO-8859-1] (original)
+++ sis/trunk/ide-project/NetBeans/nbproject/project.properties [ISO-8859-1] Fri Feb 5 23:41:50 2016
@@ -80,7 +80,7 @@ rome.version = 0.9
jdom1.version = 1.0
jdom2.version = 2.0.4
jee.version = 6.0
-osgi.version = 5.0.0
+osgi.version = 6.0.0
netcdf.version = 4.4.2
joda-time.version = 2.2
httpclient.version = 4.2.6
|