Author: desruisseaux
Date: Thu Oct 5 14:56:40 2017
New Revision: 1811213
URL: http://svn.apache.org/viewvc?rev=1811213&view=rev
Log:
If the 'non-free:sis-embedded-data' module is present, connect to the embedded
Derby database.
Modified:
sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/sql/Initializer.java
sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/system/DataDirectory.java
sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/setup/About.java
sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/setup/InstallationResources.java
Modified:
sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/sql/Initializer.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/sql/Initializer.java?rev=1811213&r1=1811212&r2=1811213&view=diff
==============================================================================
---
sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/sql/Initializer.java
[UTF-8] (original)
+++
sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/sql/Initializer.java
[UTF-8] Thu Oct 5 14:56:40 2017
@@ -22,6 +22,7 @@ import java.net.URLClassLoader;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
+import java.io.IOException;
import java.util.concurrent.Callable;
import java.util.logging.Level;
import java.util.logging.LogRecord;
@@ -41,6 +42,7 @@ import javax.naming.event.EventContext;
import javax.naming.event.NamingEvent;
import javax.naming.event.NamingExceptionEvent;
import javax.naming.event.ObjectChangeListener;
+import org.apache.sis.setup.InstallationResources;
import org.apache.sis.internal.system.DefaultFactories;
import org.apache.sis.internal.system.DataDirectory;
import org.apache.sis.internal.system.Shutdown;
@@ -93,6 +95,11 @@ public abstract class Initializer {
public static final String JNDI = "jdbc/" + DATABASE;
/**
+ * A pseudo-authority name used by {@link InstallationResources} for the
embedded data resources.
+ */
+ public static final String EMBEDDED = "Embedded";
+
+ /**
* The class loader for JavaDB (i.e. the Derby database distributed with
the JDK), created when first needed.
* This field is never reset to {@code null} even if the classpath changed
because this class loader is for
* a JAR file the JDK installation directory, and we presume that the JDK
installation do not change.
@@ -112,6 +119,7 @@ public abstract class Initializer {
/**
* {@code true} if {@link #connected(DatabaseMetaData)} has been invoked
at least once.
* This is reset to {@code false} if the {@link #source} is changed.
+ * We use this information for logging purpose.
*/
private static boolean connected;
@@ -251,6 +259,10 @@ public abstract class Initializer {
Listener.register((EventContext) env);
}
return source;
+ /*
+ * No Derby shutdown hook for DataSource fetched fron JNDI.
+ * We presume that shutdowns are handled by the container.
+ */
} catch (NameNotFoundException e) {
final LogRecord record =
Messages.getResources(null).getLogRecord(
Level.CONFIG, Messages.Keys.JNDINotSpecified_1, JNDI);
@@ -260,38 +272,51 @@ public abstract class Initializer {
/*
* At this point we determined that there is no JNDI context or no
object binded to "jdbc/SpatialMetadata".
* As a fallback, try to open the Derby database located in
$SIS_DATA/Databases/SpatialMetadata directory.
+ * Only if the SIS_DATA environment variable is not set, verify
first if the 'sis-embedded-data' module is
+ * on the classpath. Note that if SIS_DATA is defined and valid,
it has precedence.
*/
final boolean create;
- final String home =
AccessController.doPrivileged((PrivilegedAction<String>) () ->
System.getProperty(DERBY_HOME_KEY));
- final Path dir = DataDirectory.DATABASES.getDirectory();
- if (dir != null) {
- Path path = dir.resolve(DATABASE);
- if (home != null) try {
+ final boolean isEnvClear = DataDirectory.isEnvClear();
+ if (isEnvClear && (source = embedded()) != null) {
+ create = false;
+ } else {
+ final String home =
AccessController.doPrivileged((PrivilegedAction<String>) () ->
System.getProperty(DERBY_HOME_KEY));
+ final Path dir = DataDirectory.DATABASES.getDirectory();
+ if (dir != null) {
+ Path path = dir.resolve(DATABASE);
+ if (home != null) try {
+ /*
+ * If a "derby.system.home" property is set, we may be
able to get a shorter path by making it
+ * relative to Derby home. The intend is to have a
nicer URL like "jdbc:derby:SpatialMetadata"
+ * instead than
"jdbc:derby:/a/long/path/to/SIS/Data/Databases/SpatialMetadata". In addition
+ * to making loggings and
EPSGDataAccess.getAuthority() output nicer, it also reduces the risk
+ * of encoding issues if the path contains spaces or
non-ASCII characters.
+ */
+ path = Paths.get(home).relativize(path);
+ } catch (IllegalArgumentException | SecurityException e) {
+ // The path can not be relativized. This is okay.
+
Logging.recoverableException(Logging.getLogger(Loggers.SQL), Initializer.class,
"getDataSource", e);
+ }
/*
- * If a "derby.system.home" property is set, we may be
able to get a shorter path by making it
- * relative to Derby home. The intend is to have a nicer
URL like "jdbc:derby:SpatialMetadata"
- * instead than
"jdbc:derby:/a/long/path/to/SIS/Data/Databases/SpatialMetadata". In addition
- * to making loggings and EPSGDataAccess.getAuthority()
output nicer, it also reduces the risk
- * of encoding issues if the path contains spaces or
non-ASCII characters.
+ * Create the Derby data source using the context class
loader if possible,
+ * or otherwise a URL class loader to the JavaDB
distributed with the JDK.
*/
- path = Paths.get(home).relativize(path);
- } catch (IllegalArgumentException | SecurityException e) {
- // The path can not be relativized. This is okay.
-
Logging.recoverableException(Logging.getLogger(Loggers.SQL), Initializer.class,
"getDataSource", e);
+ path = path.normalize();
+ create = !Files.exists(path);
+ source =
forJavaDB(path.toString().replace(path.getFileSystem().getSeparator(), "/"));
+ } else if (home != null) {
+ final Path path = Paths.get(home);
+ create = !Files.exists(path.resolve(DATABASE)) &&
Files.isDirectory(path);
+ source = forJavaDB(DATABASE);
+ } else if (!isEnvClear) {
+ create = false;
+ source = embedded(); // Try only if we did not
already tried after above JNDI check.
+ if (source == null) {
+ return null;
+ }
+ } else {
+ return null;
}
- /*
- * Create the Derby data source using the context class loader
if possible,
- * or otherwise a URL class loader to the JavaDB distributed
with the JDK.
- */
- path = path.normalize();
- create = !Files.exists(path);
- source =
forJavaDB(path.toString().replace(path.getFileSystem().getSeparator(), "/"));
- } else if (home != null) {
- final Path path = Paths.get(home);
- create = !Files.exists(path.resolve(DATABASE)) &&
Files.isDirectory(path);
- source = forJavaDB(DATABASE);
- } else {
- return null;
}
/*
* Register the shutdown hook before to attempt any operation on
the database in order to close
@@ -333,6 +358,34 @@ public abstract class Initializer {
}
/**
+ * If the {@code non-free:sis-embedded-data} module is present on the
classpath,
+ * returns the data source for embedded Derby database. Otherwise returns
{@code null}.
+ *
+ * @see <a href="https://issues.apache.org/jira/browse/SIS-337">SIS-337</a>
+ *
+ * @since 0.8
+ */
+ private static DataSource embedded() {
+ for (InstallationResources res :
DefaultFactories.createServiceLoader(InstallationResources.class)) {
+ if (res.getAuthorities().contains(EMBEDDED)) try {
+ final String[] names = res.getResourceNames(EMBEDDED);
+ for (int i=0; i<names.length; i++) {
+ if (DATABASE.equals(names[i])) {
+ final Object ds = res.getResource(EMBEDDED, i);
+ if (ds instanceof DataSource) {
+ return (DataSource) ds;
+ }
+ }
+ }
+ } catch (IOException e) {
+ Logging.unexpectedException(Logging.getLogger(Loggers.SQL),
Initializer.class, "getDataSource", e);
+ // Continue - the system will fallback on the hard-coded
subset of EPSG definitions.
+ }
+ }
+ return null;
+ }
+
+ /**
* Prepares a log record saying that a connection to the spatial metadata
database has been created.
* This method can be invoked after {@link DataSource#getConnection()}.
When invoked for the first time,
* the record level is set to {@link Level#CONFIG}. On next calls, the
level become {@link Level#FINE}.
Modified:
sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/system/DataDirectory.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/system/DataDirectory.java?rev=1811213&r1=1811212&r2=1811213&view=diff
==============================================================================
---
sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/system/DataDirectory.java
[UTF-8] (original)
+++
sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/system/DataDirectory.java
[UTF-8] Thu Oct 5 14:56:40 2017
@@ -33,7 +33,7 @@ import org.apache.sis.util.resources.Mes
* Sub-directories of {@code SIS_DATA} where SIS looks for EPSG database,
datum shift grids and other resources.
*
* @author Martin Desruisseaux (Geomatys)
- * @version 0.7
+ * @version 0.8
* @since 0.7
* @module
*/
@@ -106,6 +106,40 @@ public enum DataDirectory {
}
/**
+ * Returns the value of {@value #ENV} environment variable, or {@code
null} if none.
+ * This method does not perform any logging and does not verify if the
directory exists.
+ * If the intend is to perform I/O operations, use {@link
#getRootDirectory()} instead.
+ *
+ * @return the {@value #ENV} environment variable, or {@code null} if none.
+ * @throws SecurityException if this method is not allowed to query the
environment variable.
+ *
+ * @see System#getenv(String)
+ *
+ * @since 0.8
+ */
+ public static String getenv() throws SecurityException {
+ return AccessController.doPrivileged((PrivilegedAction<String>) () ->
System.getenv(ENV));
+ }
+
+ /**
+ * Returns {@code true} if the {@value #ENV} environment variable is
unset. In case of doubt, this method
+ * returns {@code false}. This method is used for avoiding or at leat
delaying the log messages emitted by
+ * {@link #getRootDirectory()} when a fallback exists in absence of any
user attempt to configure the system.
+ *
+ * @return {@code true} if the {@value #ENV} environment variable is unset.
+ *
+ * @since 0.8
+ */
+ public static synchronized boolean isEnvClear() {
+ if (rootDirectory == null) try {
+ return getenv() == null;
+ } catch (SecurityException e) {
+ Logging.recoverableException(Logging.getLogger(Loggers.SYSTEM),
DataDirectory.class, "isEnvClear", e);
+ }
+ return false;
+ }
+
+ /**
* Returns the root directory fetched from the {@code SIS_DATA}
environment variable.
* If the environment variable is not set or the directory does not exist,
then this method returns {@code null}.
*
@@ -113,7 +147,7 @@ public enum DataDirectory {
*/
public static synchronized Path getRootDirectory() {
if (rootDirectory == null) try {
- final String dir =
AccessController.doPrivileged((PrivilegedAction<String>) () ->
System.getenv(ENV));
+ final String dir = getenv();
if (dir == null || dir.isEmpty()) {
warning("getRootDirectory", null,
Messages.Keys.DataDirectoryNotSpecified_1, ENV);
} else try {
Modified:
sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/setup/About.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/setup/About.java?rev=1811213&r1=1811212&r2=1811213&view=diff
==============================================================================
---
sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/setup/About.java
[UTF-8] (original)
+++
sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/setup/About.java
[UTF-8] Thu Oct 5 14:56:40 2017
@@ -39,8 +39,6 @@ import java.text.DateFormat;
import java.text.FieldPosition;
import java.nio.file.Path;
import java.nio.charset.Charset;
-import java.security.AccessController;
-import java.security.PrivilegedAction;
import org.apache.sis.util.ArgumentChecks;
import org.apache.sis.util.CharSequences;
import org.apache.sis.util.Exceptions;
@@ -382,7 +380,7 @@ fill: for (int i=0; ; i++) {
if (sections.contains(PATHS)) {
nameKey = Vocabulary.Keys.DataDirectory;
try {
- value =
AccessController.doPrivileged((PrivilegedAction<String>) () ->
System.getenv(DataDirectory.ENV));
+ value = DataDirectory.getenv();
} catch (SecurityException e) {
value = e.toString();
}
Modified:
sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/setup/InstallationResources.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/setup/InstallationResources.java?rev=1811213&r1=1811212&r2=1811213&view=diff
==============================================================================
---
sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/setup/InstallationResources.java
[UTF-8] (original)
+++
sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/setup/InstallationResources.java
[UTF-8] Thu Oct 5 14:56:40 2017
@@ -42,7 +42,7 @@ import java.io.BufferedReader;
* The embedded database is provided as a convenience for avoiding the need to
define a {@code SIS_DATA} directory
* on the local machine.
*
- * <table>
+ * <table class="sis">
* <caption>Authorities supported by Apache SIS</caption>
* <tr><th>Authority</th> <th>Provided by Maven module</th>
<th>Used by class</th></tr>
* <tr><td>{@code "EPSG"}</td> <td>{@code
org.apache.sis.non-free:sis-epsg}</td> <td>{@link
org.apache.sis.referencing.factory.sql.EPSGFactory}</td></tr>
@@ -79,7 +79,7 @@ public abstract class InstallationResour
* The values recognized by SIS are listed below
* (note that this list may be expanded in any future SIS versions):
*
- * <table>
+ * <table class="sis">
* <caption>Authorities supported by Apache SIS</caption>
* <tr><th>Authority</th> <th>Resources</th></tr>
* <tr><td>{@code "EPSG"}</td> <td>SQL installation scripts for EPSG
geodetic dataset.</td></tr>
@@ -104,7 +104,7 @@ public abstract class InstallationResour
* Returns the terms of use of the resources distributed by the specified
authority, or {@code null} if none.
* The terms of use can be returned in either plain text or HTML.
*
- * <table>
+ * <table class="sis">
* <caption>Licenses for some supported authorities</caption>
* <tr>
* <th>Authority</th>
@@ -133,11 +133,11 @@ public abstract class InstallationResour
* Examples:
*
* <ul class="verbose">
- * <li><b>{@code "EPSG"}</b> authority:<br>
+ * <li><b>{@code "EPSG"} authority:</b>
* the resource names are the filenames of all SQL scripts to execute.
One of the first script creates tables,
* followed by a script that populates tables with data, followed by a
script that creates foreigner keys.
* </li>
- * <li><b>{@code "Embedded"}</b> pseudo-authority:<br>
+ * <li><b>{@code "Embedded"} pseudo-authority:</b>
* the database name, which is {@code "SpatialMetadata"}.
* When embedded, this database is read-only.
* </li>