blob: 378e402f01c545d1a54fa1c29f7f756d2153d1c6 [file] [log] [blame]
/*
* 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.system;
import java.util.Arrays;
import java.util.EventListener;
import org.apache.sis.util.ArraysExt;
/**
* Listeners for changes in the Apache SIS system. This listener is used only for rare events,
* like OSGi module loaded or unloaded. We use this class instead of OSGi listeners in order
* to keep the SIS library OSGi-independent.
*
* @author Martin Desruisseaux (Geomatys)
* @version 0.6
* @since 0.3
* @module
*/
public abstract class SystemListener implements EventListener {
/**
* The listeners, or {@code null} if none.
*/
private static SystemListener[] listeners;
/**
* The OSGi module symbolic name, as declared in the {@code Bundle-SymbolicName} entry of the
* {@code META-INF/MANIFEST.MF} file. Shall be one of {@link Modules} constants. This is used
* in order to detect which listeners to remove when a module is uninstalled.
*/
private final String module;
/**
* Creates a new listener.
*
* @param module the OSGi module symbolic name, as declared in the {@code Bundle-SymbolicName}
* entry of the {@code META-INF/MANIFEST.MF} file. Shall be one of {@link Modules} constants.
*/
protected SystemListener(final String module) {
this.module = module;
}
/**
* Adds the given listener to the list of listeners to notify when a change occurs.
* This method doesn't check if the given listener is already present in the array,
* unless assertions are enabled.
*
* @param listener the listener to add. Can not be {@code null}.
*/
public static synchronized void add(final SystemListener listener) {
assert (listener != null) && !ArraysExt.contains(listeners, listener);
SystemListener[] list = listeners;
if (list == null) {
list = new SystemListener[1];
} else {
list = Arrays.copyOf(list, list.length + 1);
}
list[list.length - 1] = listener;
listeners = list;
}
/**
* Removes all occurrences (not just the first one) of the given listener.
* Only one occurrence should exist, but this method check all of them as
* a paranoiac check.`
*
* @param listener the listener to remove.
*/
public static synchronized void remove(final SystemListener listener) {
SystemListener[] list = listeners;
if (list != null) {
for (int i=list.length; --i>=0;) {
if (list[i] == listener) {
list = ArraysExt.remove(list, i, 1);
}
}
listeners = list;
}
}
/**
* Removes all listeners for the module of the given name.
*
* @param name the name of the module for which to remove listeners, or {@code null} if the module
* to uninstall does not have symbolic name (in which case it is probably not a SIS module).
*/
static synchronized void removeModule(final String name) {
if (name != null) {
final SystemListener[] list = listeners;
if (list != null) {
int count = 0;
final SystemListener[] modified = new SystemListener[list.length];
for (final SystemListener listener : list) {
if (!name.equals(listener.module)) {
modified[count++] = listener;
}
}
if (count != list.length) {
listeners = Arrays.copyOf(modified, count);
}
}
}
}
/**
* Notifies all registered listeners that the classpath may have changed.
*/
@SuppressWarnings("ForLoopReplaceableByForEach")
public static void fireClasspathChanged() {
final SystemListener[] list;
synchronized (SystemListener.class) {
list = listeners;
}
if (list != null) {
for (int i=0; i<list.length; i++) {
list[i].classpathChanged();
}
}
}
/**
* Invoked when the classpath is likely to have changed.
* When this method is invoked, any classes using {@link java.util.ServiceLoader} are advised to clear their cache.
*/
protected abstract void classpathChanged();
/**
* Invoked when the database content changed.
* When this method is invoked, EPSG and Citations database are advised to clear their cache.
*
* @since 0.6
*/
protected void databaseChanged() {
}
}