FELIX-1628: fileinstall should load configurations as soon as config admin is available
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@824270 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/fileinstall/src/main/java/org/apache/felix/fileinstall/internal/DirectoryWatcher.java b/fileinstall/src/main/java/org/apache/felix/fileinstall/internal/DirectoryWatcher.java
index 3d8dd83..734dacc 100644
--- a/fileinstall/src/main/java/org/apache/felix/fileinstall/internal/DirectoryWatcher.java
+++ b/fileinstall/src/main/java/org/apache/felix/fileinstall/internal/DirectoryWatcher.java
@@ -77,6 +77,7 @@
public final static String TMPDIR = "felix.fileinstall.tmpdir";
public final static String FILTER = "felix.fileinstall.filter";
public final static String START_NEW_BUNDLES = "felix.fileinstall.bundles.new.start";
+ public final static String NO_INITIAL_DELAY = "felix.fileinstall.noInitialDelay";
File watchedDirectory;
File tmpDir;
@@ -86,6 +87,7 @@
String filter;
BundleContext context;
String originatingFileName;
+ boolean noInitialDelay;
// Map of all installed artifacts
Map/* <File, Artifact> */ currentManagedArtifacts = new HashMap/* <File, Artifact> */();
@@ -111,6 +113,7 @@
tmpDir = getFile(properties, TMPDIR, new File("./tmp"));
startBundles = getBoolean(properties, START_NEW_BUNDLES, true); // by default, we start bundles.
filter = (String) properties.get(FILTER);
+ noInitialDelay = getBoolean(properties, NO_INITIAL_DELAY, false);
FilenameFilter flt;
if (filter != null && filter.length() > 0)
@@ -127,6 +130,18 @@
flt = null;
}
scanner = new Scanner(watchedDirectory, flt);
+
+ if (noInitialDelay)
+ {
+ log("Starting initial scan", null);
+ initializeCurrentManagedBundles();
+ scanner.initialize(currentManagedArtifacts.keySet());
+ Set/*<File>*/ files = scanner.scan(true);
+ if (files != null)
+ {
+ process(files);
+ }
+ }
}
/**
@@ -143,165 +158,35 @@
+ TMPDIR + " = " + tmpDir + ", "
+ FILTER + " = " + filter + "}", null);
- initializeCurrentManagedBundles();
-
- scanner.initialize(currentManagedArtifacts.keySet());
+ if (!noInitialDelay)
+ {
+ initializeCurrentManagedBundles();
+ scanner.initialize(currentManagedArtifacts.keySet());
+ }
while (!interrupted())
{
try
{
- Set/*<File>*/ files = scanner.scan();
+ Set/*<File>*/ files = scanner.scan(false);
// Check that there is a result. If not, this means that the directory can not be listed,
// so it's presumably not a valid directory (it may have been deleted by someone).
// In such case, just sleep
if (files == null)
{
- Thread.sleep(poll);
+ synchronized (this)
+ {
+ wait(poll);
+ }
continue;
}
- List/*<ArtifactListener>*/ listeners = FileInstall.getListeners();
- List/*<Artifact>*/ deleted = new ArrayList/*<Artifact>*/();
- List/*<Artifact>*/ modified = new ArrayList/*<Artifact>*/();
- List/*<Artifact>*/ created = new ArrayList/*<Artifact>*/();
+ process(files);
- // Try to process again files that could not be processed
- files.addAll(processingFailures);
- processingFailures.clear();
-
- for (Iterator it = files.iterator(); it.hasNext();)
+ synchronized (this)
{
- File file = (File) it.next();
- boolean exists = file.exists();
- Artifact artifact = (Artifact) currentManagedArtifacts.get(file);
- // File has been deleted
- if (!exists && artifact != null)
- {
- deleteJaredDirectory(artifact);
- deleteTransformedFile(artifact);
- deleted.add(artifact);
- }
- else
- {
- File jar = file;
- // Jar up the directory if needed
- if (file.isDirectory())
- {
- prepareDir(tmpDir);
- try
- {
- jar = new File(tmpDir, file.getName() + ".jar");
- Util.jarDir(file, jar);
-
- }
- catch (IOException e)
- {
- log("Unable to create jar for: " + file.getAbsolutePath(), e);
- continue;
- }
- }
- // File has been modified
- if (exists && artifact != null)
- {
- // Check the last modified date against
- // the artifact last modified date if available. This will loose
- // the possibility of the jar being replaced by an older one
- // or the content changed without the date being modified, but
- // else, we'd have to reinstall all the deployed bundles on restart.
- if (artifact.getLastModified() > Util.getLastModified(file))
- {
- continue;
- }
- // If there's no listener, this is because this artifact has been installed before
- // fileinstall has been restarted. In this case, try to find a listener.
- if (artifact.getListener() == null)
- {
- ArtifactListener listener = findListener(jar, listeners);
- // If no listener can handle this artifact, we need to defer the
- // processing for this artifact until one is found
- if (listener == null)
- {
- processingFailures.add(file);
- continue;
- }
- artifact.setListener(listener);
- }
- // If the listener can not handle this file anymore,
- // uninstall the artifact and try as if is was new
- if (!listeners.contains(artifact.getListener()) || !artifact.getListener().canHandle(jar))
- {
- deleted.add(artifact);
- artifact = null;
- }
- // The listener is still ok
- else
- {
- deleteTransformedFile(artifact);
- artifact.setJaredDirectory(jar);
- if (transformArtifact(artifact))
- {
- modified.add(artifact);
- }
- else
- {
- deleteJaredDirectory(artifact);
- deleted.add(artifact);
- }
- continue;
- }
- }
- // File has been added
- if (exists && artifact == null)
- {
- // Find the listener
- ArtifactListener listener = findListener(jar, listeners);
- // If no listener can handle this artifact, we need to defer the
- // processing for this artifact until one is found
- if (listener == null)
- {
- processingFailures.add(file);
- continue;
- }
- // Create the artifact
- artifact = new Artifact();
- artifact.setPath(file);
- artifact.setJaredDirectory(jar);
- artifact.setListener(listener);
- if (transformArtifact(artifact))
- {
- created.add(artifact);
- }
- else
- {
- deleteJaredDirectory(artifact);
- }
- }
- }
+ wait(poll);
}
- // Handle deleted artifacts
- // We do the operations in the following order:
- // uninstall, update, install, refresh & start.
- Collection uninstalledBundles = uninstall(deleted);
- Collection updatedBundles = update(modified);
- Collection installedBundles = install(created);
- if (uninstalledBundles.size() > 0 || updatedBundles.size() > 0)
- {
- // Refresh if any bundle got uninstalled or updated.
- // This can lead to restart of recently updated bundles, but
- // don't worry about that at this point of time.
- refresh();
- }
-
- if (startBundles)
- {
- // Try to start all the bundles that are not persistently stopped
- startAllBundles();
- // Try to start newly installed bundles
- start(installedBundles);
- }
-
- Thread.sleep(poll);
}
catch (InterruptedException e)
{
@@ -314,6 +199,148 @@
}
}
+ private void process(Set files) {
+ List/*<ArtifactListener>*/ listeners = FileInstall.getListeners();
+ List/*<Artifact>*/ deleted = new ArrayList/*<Artifact>*/();
+ List/*<Artifact>*/ modified = new ArrayList/*<Artifact>*/();
+ List/*<Artifact>*/ created = new ArrayList/*<Artifact>*/();
+
+ // Try to process again files that could not be processed
+ files.addAll(processingFailures);
+ processingFailures.clear();
+
+ for (Iterator it = files.iterator(); it.hasNext();)
+ {
+ File file = (File) it.next();
+ boolean exists = file.exists();
+ Artifact artifact = (Artifact) currentManagedArtifacts.get(file);
+ // File has been deleted
+ if (!exists && artifact != null)
+ {
+ deleteJaredDirectory(artifact);
+ deleteTransformedFile(artifact);
+ deleted.add(artifact);
+ }
+ else
+ {
+ File jar = file;
+ // Jar up the directory if needed
+ if (file.isDirectory())
+ {
+ prepareDir(tmpDir);
+ try
+ {
+ jar = new File(tmpDir, file.getName() + ".jar");
+ Util.jarDir(file, jar);
+
+ }
+ catch (IOException e)
+ {
+ log("Unable to create jar for: " + file.getAbsolutePath(), e);
+ continue;
+ }
+ }
+ // File has been modified
+ if (exists && artifact != null)
+ {
+ // Check the last modified date against
+ // the artifact last modified date if available. This will loose
+ // the possibility of the jar being replaced by an older one
+ // or the content changed without the date being modified, but
+ // else, we'd have to reinstall all the deployed bundles on restart.
+ if (artifact.getLastModified() > Util.getLastModified(file))
+ {
+ continue;
+ }
+ // If there's no listener, this is because this artifact has been installed before
+ // fileinstall has been restarted. In this case, try to find a listener.
+ if (artifact.getListener() == null)
+ {
+ ArtifactListener listener = findListener(jar, listeners);
+ // If no listener can handle this artifact, we need to defer the
+ // processing for this artifact until one is found
+ if (listener == null)
+ {
+ processingFailures.add(file);
+ continue;
+ }
+ artifact.setListener(listener);
+ }
+ // If the listener can not handle this file anymore,
+ // uninstall the artifact and try as if is was new
+ if (!listeners.contains(artifact.getListener()) || !artifact.getListener().canHandle(jar))
+ {
+ deleted.add(artifact);
+ artifact = null;
+ }
+ // The listener is still ok
+ else
+ {
+ deleteTransformedFile(artifact);
+ artifact.setJaredDirectory(jar);
+ if (transformArtifact(artifact))
+ {
+ modified.add(artifact);
+ }
+ else
+ {
+ deleteJaredDirectory(artifact);
+ deleted.add(artifact);
+ }
+ continue;
+ }
+ }
+ // File has been added
+ if (exists && artifact == null)
+ {
+ // Find the listener
+ ArtifactListener listener = findListener(jar, listeners);
+ // If no listener can handle this artifact, we need to defer the
+ // processing for this artifact until one is found
+ if (listener == null)
+ {
+ processingFailures.add(file);
+ continue;
+ }
+ // Create the artifact
+ artifact = new Artifact();
+ artifact.setPath(file);
+ artifact.setJaredDirectory(jar);
+ artifact.setListener(listener);
+ if (transformArtifact(artifact))
+ {
+ created.add(artifact);
+ }
+ else
+ {
+ deleteJaredDirectory(artifact);
+ }
+ }
+ }
+ }
+ // Handle deleted artifacts
+ // We do the operations in the following order:
+ // uninstall, update, install, refresh & start.
+ Collection uninstalledBundles = uninstall(deleted);
+ Collection updatedBundles = update(modified);
+ Collection installedBundles = install(created);
+ if (uninstalledBundles.size() > 0 || updatedBundles.size() > 0)
+ {
+ // Refresh if any bundle got uninstalled or updated.
+ // This can lead to restart of recently updated bundles, but
+ // don't worry about that at this point of time.
+ refresh();
+ }
+
+ if (startBundles)
+ {
+ // Try to start all the bundles that are not persistently stopped
+ startAllBundles();
+ // Try to start newly installed bundles
+ start(installedBundles);
+ }
+ }
+
ArtifactListener findListener(File artifact, List/* <ArtifactListener> */ listeners)
{
for (Iterator itL = listeners.iterator(); itL.hasNext();)
diff --git a/fileinstall/src/main/java/org/apache/felix/fileinstall/internal/FileInstall.java b/fileinstall/src/main/java/org/apache/felix/fileinstall/internal/FileInstall.java
index b9667f6..84ba378 100644
--- a/fileinstall/src/main/java/org/apache/felix/fileinstall/internal/FileInstall.java
+++ b/fileinstall/src/main/java/org/apache/felix/fileinstall/internal/FileInstall.java
@@ -115,6 +115,7 @@
set(ht, DirectoryWatcher.FILTER);
set(ht, DirectoryWatcher.TMPDIR);
set(ht, DirectoryWatcher.START_NEW_BUNDLES);
+ set(ht, DirectoryWatcher.NO_INITIAL_DELAY);
updated("initial", ht);
}
@@ -135,12 +136,17 @@
public void stop(BundleContext context) throws Exception
{
- for (Iterator w = watchers.values().iterator(); w.hasNext();)
+ List /*<DirectoryWatcher>*/ toClose = new ArrayList /*<DirectoryWatcher>*/();
+ synchronized (watchers)
+ {
+ toClose.addAll(watchers.values());
+ watchers.clear();
+ }
+ for (Iterator w = toClose.iterator(); w.hasNext();)
{
try
{
DirectoryWatcher dir = (DirectoryWatcher) w.next();
- w.remove();
dir.close();
}
catch (Exception e)
@@ -155,7 +161,11 @@
public void deleted(String pid)
{
- DirectoryWatcher watcher = (DirectoryWatcher) watchers.remove(pid);
+ DirectoryWatcher watcher;
+ synchronized (watchers)
+ {
+ watcher = (DirectoryWatcher) watchers.remove(pid);
+ }
if (watcher != null)
{
watcher.close();
@@ -184,6 +194,7 @@
{
listeners.add(listener);
}
+ notifyWatchers();
}
private void removeListener(ArtifactListener listener)
@@ -192,6 +203,24 @@
{
listeners.remove(listener);
}
+ notifyWatchers();
+ }
+
+ private void notifyWatchers()
+ {
+ List /*<DirectoryWatcher>*/ toNotify = new ArrayList /*<DirectoryWatcher>*/();
+ synchronized (watchers)
+ {
+ toNotify.addAll(watchers.values());
+ }
+ for (Iterator w = toNotify.iterator(); w.hasNext();)
+ {
+ DirectoryWatcher dir = (DirectoryWatcher) w.next();
+ synchronized (dir)
+ {
+ dir.notifyAll();
+ }
+ }
}
static List getListeners()
diff --git a/fileinstall/src/main/java/org/apache/felix/fileinstall/internal/Scanner.java b/fileinstall/src/main/java/org/apache/felix/fileinstall/internal/Scanner.java
index 44e93cf..0697414 100644
--- a/fileinstall/src/main/java/org/apache/felix/fileinstall/internal/Scanner.java
+++ b/fileinstall/src/main/java/org/apache/felix/fileinstall/internal/Scanner.java
@@ -95,9 +95,10 @@
* Upon restart, such checksums are not known so that all files will
* be reported as modified.
*
+ * @param reportImmediately report all files immediately without waiting for the checksum to be stable
* @return a list of changes on the files included in the directory
*/
- public Set/*<File>*/ scan()
+ public Set/*<File>*/ scan(boolean reportImmediately)
{
File[] list = directory.listFiles(filter);
if (list == null)
@@ -114,7 +115,7 @@
long newChecksum = checksum(file);
lastChecksums.put(file, Long.valueOf(newChecksum));
// Only handle file when it does not change anymore and it has changed since last reported
- if (newChecksum == lastChecksum && newChecksum != storedChecksum)
+ if ((newChecksum == lastChecksum || reportImmediately) && newChecksum != storedChecksum)
{
storedChecksums.put(file, Long.valueOf(newChecksum));
files.add(file);