sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1728099 - in /sis/branches/JDK8: core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/sql/ core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ core/sis-referencing/src/main/resources/META-INF/services/ ide-p...
Date Tue, 02 Feb 2016 12:26:27 GMT
Author: desruisseaux
Date: Tue Feb  2 12:26:27 2016
New Revision: 1728099

URL: http://svn.apache.org/viewvc?rev=1728099&view=rev
Log:
Initializer now listens changes in JNDI bindings.

Added:
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/DatabaseListener.java
  (with props)
    sis/branches/JDK8/core/sis-referencing/src/main/resources/META-INF/services/org.apache.sis.internal.metadata.sql.Initializer
  (with props)
Modified:
    sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/sql/Initializer.java
    sis/branches/JDK8/ide-project/NetBeans/build.xml

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=1728099&r1=1728098&r2=1728099&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] Tue Feb  2 12:26:27 2016
@@ -20,6 +20,7 @@ import java.util.Locale;
 import java.net.URL;
 import java.net.URLClassLoader;
 import java.util.ServiceLoader;
+import java.util.concurrent.Callable;
 import java.util.logging.Level;
 import java.util.logging.LogRecord;
 import java.lang.reflect.Method;
@@ -28,8 +29,13 @@ import java.sql.Connection;
 import java.sql.SQLException;
 import javax.naming.Context;
 import javax.naming.InitialContext;
-import javax.naming.spi.NamingManager;
+import javax.naming.NamingException;
 import javax.naming.NameNotFoundException;
+import javax.naming.spi.NamingManager;
+import javax.naming.event.EventContext;
+import javax.naming.event.NamingEvent;
+import javax.naming.event.NamingExceptionEvent;
+import javax.naming.event.ObjectChangeListener;
 import org.apache.sis.internal.system.DataDirectory;
 import org.apache.sis.internal.system.Shutdown;
 import org.apache.sis.internal.system.Loggers;
@@ -43,7 +49,7 @@ import java.nio.file.Paths;
 
 
 /**
- * Manages the unique {@link DataSource} instances to the {@code $SIS_DATA/Databases/SpatialMetadata}
database.
+ * Manages the unique {@link DataSource} instance to the {@code $SIS_DATA/Databases/SpatialMetadata}
database.
  * This includes initialization of a new database if none existed. The schemas will be created
by subclasses of
  * this {@code Initializer} class, which must be registered in the following file:
  *
@@ -69,6 +75,11 @@ public abstract class Initializer {
     private static final String HOME_KEY = "derby.system.home";
 
     /**
+     * Name of the JNDI resource to lookup in the {@code "java:comp/env"} context.
+     */
+    public static final String JNDI = "jdbc/" + DATABASE;
+
+    /**
      * The unique, SIS-wide, data source to the {@code $SIS_DATA/Databases/SpatialMetadata}
database.
      * Created when first needed, and cleared on shutdown.
      *
@@ -91,6 +102,92 @@ public abstract class Initializer {
     protected abstract void createSchema(Connection connection) throws SQLException;
 
     /**
+     * Invoked when the JNDI data source associated to {@code "jdbc/SpatialMetadata"} changed.
+     */
+    protected abstract void dataSourceChanged();
+
+    /**
+     * A JNDI listener for being informed of changes in the {@link DataSource} associated
to {@code "jdbc/SpatialMetadata"}.
+     * This listener clears the {@link Initializer#source} field, so the next call to {@link
Initializer#getDataSource()}
+     * will fetch a new one.
+     */
+    private static final class Listener implements ObjectChangeListener, Callable<Object>
{
+        /**
+         * The context where this listener has been registered.
+         * Used for unregistering the listener after the data source has been cleared.
+         */
+        private final EventContext context;
+
+        /**
+         * Creates a new listener for the given JNDI context.
+         */
+        private Listener(final EventContext context) {
+            this.context = context;
+        }
+
+        /**
+         * Registers a new listener for the given JNDI context.
+         */
+        static void register(final EventContext context) throws NamingException {
+            final Listener listener = new Listener(context);
+            context.addNamingListener(JNDI, EventContext.OBJECT_SCOPE, listener);
+            Shutdown.register(listener);
+        }
+
+        /**
+         * Invoked when the JVM is shutting down, or when the Servlet or OSGi bundle is uninstalled.
+         * This method unregisters the listener from the JNDI context.
+         */
+        @Override
+        public Object call() throws NamingException {
+            synchronized (Initializer.class) {
+                // Do not clear the DataSource - the shutdown hook for Derby needs it.
+                context.removeNamingListener(this);
+            }
+            return null;
+        }
+
+        /**
+         * Invoked when the data source associated to {@code "jdbc/SpatialMetadata"} changed.
+         * This method clears the {@link Initializer#source}, unregisters this listener
+         * and notifies other SIS modules.
+         *
+         * @param event Ignored. May be null.
+         */
+        @Override
+        public void objectChanged(NamingEvent event) {
+            try {
+                synchronized (Initializer.class) {
+                    source = null;
+                    Shutdown.unregister(this);
+                    context.removeNamingListener(this);
+                }
+            } catch (NamingException e) {
+                /*
+                 * Not a fatal error since the listener may be unregistered anyway, or may
be unregistered
+                 * automatically by other kinds of JNDI events. Even if the listener is not
unregistered,
+                 * it will hurt to badly: the DataSource would only be fetched more often
than necessary.
+                 */
+                Logging.recoverableException(Logging.getLogger(Loggers.SYSTEM), Listener.class,
"objectChanged", e);
+            }
+            for (Initializer init : ServiceLoader.load(Initializer.class)) {
+                init.dataSourceChanged();
+            }
+        }
+
+        /**
+         * Invoked if JNDI lost connection to the server while preparing the {@code NamingEvent}.
+         * Clears the data source anyway. In the worst case scenario, the application will
fetch
+         * it again from a the JNDI context.
+         */
+        @Override public void namingExceptionThrown(NamingExceptionEvent event) {
+            Logging.unexpectedException(Logging.getLogger(Loggers.SYSTEM),
+                    Listener.class, "namingExceptionThrown", event.getException());
+            objectChanged(null);
+        }
+    }
+
+    /**
      * Returns the data source for the SIS-wide "SpatialMetadata" database.
      * This method returns the first of the following steps that succeed:
      *
@@ -119,10 +216,14 @@ public abstract class Initializer {
         if (source == null) {
             if (hasJNDI()) try {
                 final Context env = (Context) InitialContext.doLookup("java:comp/env");
-                return source = (DataSource) env.lookup("jdbc/" + DATABASE);
+                source = (DataSource) env.lookup(JNDI);
+                if (env instanceof EventContext) {
+                    Listener.register((EventContext) env);
+                }
+                return source;
             } catch (NameNotFoundException e) {
                 final LogRecord record = Messages.getResources(null).getLogRecord(
-                        Level.CONFIG, Messages.Keys.JNDINotSpecified_1, "jdbc/" + DATABASE);
+                        Level.CONFIG, Messages.Keys.JNDINotSpecified_1, JNDI);
                 record.setLoggerName(Loggers.SQL);
                 Logging.log(Initializer.class, "getDataSource", record);
             }

Added: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/DatabaseListener.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/DatabaseListener.java?rev=1728099&view=auto
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/DatabaseListener.java
(added)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/DatabaseListener.java
[UTF-8] Tue Feb  2 12:26:27 2016
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF 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.apache.sis.internal.referencing;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+import org.opengis.util.FactoryException;
+import org.apache.sis.referencing.CRS;
+import org.apache.sis.referencing.factory.MultiAuthoritiesFactory;
+import org.apache.sis.internal.metadata.sql.Initializer;
+import org.apache.sis.internal.system.Loggers;
+import org.apache.sis.util.logging.Logging;
+
+
+/**
+ * Invoked when a new database is created or when the data source changed.
+ * This listener is registered in the following file:
+ *
+ * {@preformat text
+ *   META-INF/services/org.apache.sis.internal.metadata.sql.Initializer
+ * }
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @since   0.7
+ * @version 0.7
+ * @module
+ */
+public final class DatabaseListener extends Initializer {
+    /**
+     * To be invoked by refection.
+     */
+    public DatabaseListener() {
+    }
+
+    /**
+     * Invoked when a new database is created.
+     *
+     * @param connection Connection to the empty database.
+     * @throws SQLException if an error occurred while populating the database.
+     */
+    @Override
+    protected void createSchema(Connection connection) throws SQLException {
+    }
+
+    /**
+     * Invoked when the data source changed.
+     */
+    @Override
+    protected void dataSourceChanged() {
+        try {
+            ((MultiAuthoritiesFactory) CRS.getAuthorityFactory(null)).reload();
+        } catch (FactoryException e) {
+            // Should never happen for a null argument given to CRS.getAuthorityFactory(…).
+            Logging.unexpectedException(Logging.getLogger(Loggers.CRS_FACTORY), CRS.class,
"getAuthorityFactory", e);
+        }
+    }
+}

Propchange: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/DatabaseListener.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/DatabaseListener.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain;charset=UTF-8

Added: sis/branches/JDK8/core/sis-referencing/src/main/resources/META-INF/services/org.apache.sis.internal.metadata.sql.Initializer
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/resources/META-INF/services/org.apache.sis.internal.metadata.sql.Initializer?rev=1728099&view=auto
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/resources/META-INF/services/org.apache.sis.internal.metadata.sql.Initializer
(added)
+++ sis/branches/JDK8/core/sis-referencing/src/main/resources/META-INF/services/org.apache.sis.internal.metadata.sql.Initializer
[UTF-8] Tue Feb  2 12:26:27 2016
@@ -0,0 +1,2 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more contributor license
agreements.
+org.apache.sis.internal.referencing.DatabaseListener

Propchange: sis/branches/JDK8/core/sis-referencing/src/main/resources/META-INF/services/org.apache.sis.internal.metadata.sql.Initializer
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sis/branches/JDK8/core/sis-referencing/src/main/resources/META-INF/services/org.apache.sis.internal.metadata.sql.Initializer
------------------------------------------------------------------------------
    svn:mime-type = text/plain;charset=UTF-8

Modified: sis/branches/JDK8/ide-project/NetBeans/build.xml
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/ide-project/NetBeans/build.xml?rev=1728099&r1=1728098&r2=1728099&view=diff
==============================================================================
--- sis/branches/JDK8/ide-project/NetBeans/build.xml (original)
+++ sis/branches/JDK8/ide-project/NetBeans/build.xml Tue Feb  2 12:26:27 2016
@@ -152,6 +152,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}">



Mime
View raw message