You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by ro...@apache.org on 2017/11/07 09:35:42 UTC
[sling-org-apache-sling-fsresource] 22/25: SLING-1387 : File system
provider should send resource events
This is an automated email from the ASF dual-hosted git repository.
rombert pushed a commit to annotated tag org.apache.sling.fsresource-1.0.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-fsresource.git
commit 93cda71b4356d387c52bb9a1947117b76cf551e3
Author: Carsten Ziegeler <cz...@apache.org>
AuthorDate: Fri Feb 19 10:37:26 2010 +0000
SLING-1387 : File system provider should send resource events
git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/bundles/extensions/fsresource@911777 13f79535-47bb-0310-9956-ffa450edef68
---
NOTICE | 2 +-
pom.xml | 4 +
.../sling/fsprovider/internal/FileMonitor.java | 256 +++++++++++++++++++++
.../sling/fsprovider/internal/FsResource.java | 4 +-
.../fsprovider/internal/FsResourceProvider.java | 43 +++-
src/main/resources/META-INF/NOTICE | 2 +-
6 files changed, 306 insertions(+), 5 deletions(-)
diff --git a/NOTICE b/NOTICE
index 7a727bf..9d9af52 100644
--- a/NOTICE
+++ b/NOTICE
@@ -1,5 +1,5 @@
Apache Sling File System Resource Provider
-Copyright 2008-2009 The Apache Software Foundation
+Copyright 2008-2010 The Apache Software Foundation
Apache Sling is based on source code originally developed
by Day Software (http://www.day.com/).
diff --git a/pom.xml b/pom.xml
index ed57ad1..89aaae9 100644
--- a/pom.xml
+++ b/pom.xml
@@ -89,6 +89,10 @@
<artifactId>org.osgi.core</artifactId>
</dependency>
<dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.compendium</artifactId>
+ </dependency>
+ <dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
diff --git a/src/main/java/org/apache/sling/fsprovider/internal/FileMonitor.java b/src/main/java/org/apache/sling/fsprovider/internal/FileMonitor.java
new file mode 100644
index 0000000..5e03ea9
--- /dev/null
+++ b/src/main/java/org/apache/sling/fsprovider/internal/FileMonitor.java
@@ -0,0 +1,256 @@
+/*
+ * 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.sling.fsprovider.internal;
+
+import java.io.File;
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.Timer;
+import java.util.TimerTask;
+
+import org.apache.sling.api.SlingConstants;
+import org.osgi.service.event.EventAdmin;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This class is a monitor for the file system
+ * that periodically checks for changes.
+ */
+public class FileMonitor extends TimerTask {
+
+ /** The logger. */
+ private final Logger logger = LoggerFactory.getLogger(this.getClass());
+
+ private final Timer timer = new Timer();
+ private boolean stop = false;
+ private boolean stopped = true;
+
+ private final Monitorable root;
+
+ private final FsResourceProvider provider;
+
+ /**
+ * Creates a new instance of this class.
+ * @param provider The resource provider.
+ * @param interval The interval between executions of the task, in milliseconds.
+ */
+ public FileMonitor(final FsResourceProvider provider, final long interval) {
+ this.provider = provider;
+ this.root = new Monitorable(this.provider.getProviderRoot(), this.provider.getRootFile());
+ createStatus(this.root);
+ logger.debug("Starting file monitor for {} with an interval of {}ms", this.root.file, interval);
+ timer.schedule(this, 0, interval);
+ }
+
+ /**
+ * Stop periodically executing this task. If the task is currently executing it
+ * will never be run again after the current execution, otherwise it will simply
+ * never run (again).
+ */
+ void stop() {
+ synchronized (timer) {
+ if (!stop) {
+ stop = true;
+ cancel();
+ timer.cancel();
+ }
+
+ boolean interrupted = false;
+ while (!stopped) {
+ try {
+ timer.wait();
+ }
+ catch (InterruptedException e) {
+ interrupted = true;
+ }
+ }
+ if (interrupted) {
+ Thread.currentThread().interrupt();
+ }
+ }
+ logger.debug("Stopped file monitor for {}", this.root.file);
+ }
+
+ /**
+ * @see java.util.TimerTask#run()
+ */
+ public void run() {
+ synchronized (timer) {
+ stopped = false;
+ if (stop) {
+ stopped = true;
+ timer.notifyAll();
+ return;
+ }
+ }
+ synchronized ( this ) {
+ try {
+ // if we don't have an event admin, we just skip the check
+ final EventAdmin localEA = this.provider.getEventAdmin();
+ if ( localEA != null ) {
+ this.check(this.root, localEA);
+ }
+ } catch (Exception e) {
+ // ignore this
+ }
+ }
+ synchronized (timer) {
+ stopped = true;
+ timer.notifyAll();
+ }
+ }
+
+ /**
+ * Check the monitorable
+ * @param monitorable The monitorable to check
+ * @param localEA The event admin
+ */
+ private void check(final Monitorable monitorable, final EventAdmin localEA) {
+ logger.debug("Checking {}", monitorable.file);
+ // if the file is non existing, check if it has been readded
+ if ( monitorable.status instanceof NonExistingStatus ) {
+ if ( monitorable.file.exists() ) {
+ // new file and reset status
+ createStatus(monitorable);
+ sendEvents(monitorable,
+ SlingConstants.TOPIC_RESOURCE_ADDED,
+ localEA);
+ }
+ } else {
+ // check if the file has been removed
+ if ( !monitorable.file.exists() ) {
+ // removed file and update status
+ sendEvents(monitorable,
+ SlingConstants.TOPIC_RESOURCE_REMOVED,
+ localEA);
+ monitorable.status = NonExistingStatus.SINGLETON;
+ } else {
+ // check for changes
+ final FileStatus fs = (FileStatus)monitorable.status;
+ boolean changed = false;
+ if ( fs.lastModified < monitorable.file.lastModified() ) {
+ fs.lastModified = monitorable.file.lastModified();
+ // changed
+ sendEvents(monitorable,
+ SlingConstants.TOPIC_RESOURCE_CHANGED,
+ localEA);
+ changed = true;
+ }
+ if ( fs instanceof DirStatus ) {
+ // directory
+ final DirStatus ds = (DirStatus)fs;
+ for(int i=0; i<ds.children.length; i++) {
+ check(ds.children[i], localEA);
+ }
+ // if the dir changed we have to update
+ if ( changed ) {
+ // and now update
+ final File[] files = monitorable.file.listFiles();
+ final Monitorable[] children = new Monitorable[files.length];
+ for(int i=0; i<files.length; i++) {
+ // search in old list
+ for(int m=0;m<ds.children.length;m++) {
+ if ( ds.children[m].file.equals(files[i]) ) {
+ children[i] = ds.children[m];
+ break;
+ }
+ }
+ if ( children[i] == null ) {
+ children[i] = new Monitorable(monitorable.path + '/' + files[i].getName(), files[i]);
+ children[i].status = NonExistingStatus.SINGLETON;
+ check(children[i], localEA);
+ }
+ }
+ ds.children = children;
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Send the event async via the event admin.
+ */
+ private void sendEvents(final Monitorable monitorable, final String topic, final EventAdmin localEA) {
+ if ( logger.isDebugEnabled() ) {
+ logger.debug("Detected change for resource {} : {}", monitorable.path, topic);
+ }
+
+ final Dictionary<String, String> properties = new Hashtable<String, String>();
+ properties.put(SlingConstants.PROPERTY_PATH, monitorable.path);
+ final String type = monitorable.status instanceof FileStatus ?
+ FsResource.RESOURCE_TYPE_FILE : FsResource.RESOURCE_TYPE_FOLDER;
+ properties.put(SlingConstants.PROPERTY_RESOURCE_TYPE, type);
+ localEA.postEvent(new org.osgi.service.event.Event(topic, properties));
+ }
+
+ /**
+ * Create a status object for the monitorable
+ */
+ private static void createStatus(final Monitorable monitorable) {
+ if ( !monitorable.file.exists() ) {
+ monitorable.status = NonExistingStatus.SINGLETON;
+ } else if ( monitorable.file.isFile() ) {
+ monitorable.status = new FileStatus(monitorable.file);
+ } else {
+ monitorable.status = new DirStatus(monitorable.file, monitorable.path);
+ }
+ }
+
+ /** The monitorable to hold the resource path, the file and the status. */
+ private static final class Monitorable {
+ public final String path;
+ public final File file;
+ public Object status;
+
+ public Monitorable(final String path, final File file) {
+ this.path = path;
+ this.file = file;
+ }
+ }
+
+ /** Status for files. */
+ private static class FileStatus {
+ public long lastModified;
+ public FileStatus(final File file) {
+ this.lastModified = file.lastModified();
+ }
+ }
+
+ /** Status for directories. */
+ private static final class DirStatus extends FileStatus {
+ public Monitorable[] children;
+
+ public DirStatus(final File dir, final String path) {
+ super(dir);
+ final File[] files = dir.listFiles();
+ this.children = new Monitorable[files.length];
+ for(int i=0; i<files.length; i++) {
+ this.children[i] = new Monitorable(path + '/' + files[i].getName(), files[i]);
+ FileMonitor.createStatus(this.children[i]);
+ }
+ }
+ }
+
+ /** Status for non existing files. */
+ private static final class NonExistingStatus {
+ public static NonExistingStatus SINGLETON = new NonExistingStatus();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/org/apache/sling/fsprovider/internal/FsResource.java b/src/main/java/org/apache/sling/fsprovider/internal/FsResource.java
index 372d499..7ecd8bc 100644
--- a/src/main/java/org/apache/sling/fsprovider/internal/FsResource.java
+++ b/src/main/java/org/apache/sling/fsprovider/internal/FsResource.java
@@ -42,13 +42,13 @@ public class FsResource extends SlingAdaptable implements Resource {
* The resource type for file system files mapped into the resource tree by
* the {@link FsResourceProvider} (value is "nt:file").
*/
- private static final String RESOURCE_TYPE_FILE = "nt:file";
+ static final String RESOURCE_TYPE_FILE = "nt:file";
/**
* The resource type for file system folders mapped into the resource tree
* by the {@link FsResourceProvider} (value is "nt:folder").
*/
- private static final String RESOURCE_TYPE_FOLDER = "nt:folder";
+ static final String RESOURCE_TYPE_FOLDER = "nt:folder";
// default log, assigned on demand
private Logger log;
diff --git a/src/main/java/org/apache/sling/fsprovider/internal/FsResourceProvider.java b/src/main/java/org/apache/sling/fsprovider/internal/FsResourceProvider.java
index 1cc0e18..dd7b740 100644
--- a/src/main/java/org/apache/sling/fsprovider/internal/FsResourceProvider.java
+++ b/src/main/java/org/apache/sling/fsprovider/internal/FsResourceProvider.java
@@ -32,6 +32,7 @@ import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceProvider;
import org.apache.sling.api.resource.ResourceResolver;
import org.osgi.framework.BundleContext;
+import org.osgi.service.event.EventAdmin;
/**
* The <code>FsResourceProvider</code> is a resource provider which maps
@@ -48,12 +49,13 @@ import org.osgi.framework.BundleContext;
* label="%resource.resolver.name"
* description="%resource.resolver.description"
* configurationFactory="true"
- * @scr.service
+ * @scr.service interface="ResourceProvider"
* @scr.property name="service.description" value="Sling Filesystem Resource
* Provider"
* @scr.property name="service.vendor" value="The Apache Software Foundation"
* @scr.property nameRef="ResourceProvider.ROOTS"
* @scr.property nameRef="PROP_PROVIDER_FILE"
+ * @scr.property nameRef="PROP_PROVIDER_CHECKINTERVAL" valueRef="DEFAULT_CHECKINTERVAL"
*/
public class FsResourceProvider implements ResourceProvider {
@@ -64,6 +66,14 @@ public class FsResourceProvider implements ResourceProvider {
*/
public static final String PROP_PROVIDER_FILE = "provider.file";
+ /**
+ * The name of the configuration property providing the check interval
+ * for file changes (value is "provider.checkinterval").
+ */
+ public static final String PROP_PROVIDER_CHECKINTERVAL = "provider.checkinterval";
+
+ public static long DEFAULT_CHECKINTERVAL = 1000;
+
// The location in the resource tree where the resources are mapped
private String providerRoot;
@@ -73,6 +83,12 @@ public class FsResourceProvider implements ResourceProvider {
// The "root" file or folder in the file system
private File providerFile;
+ /** The monitor to detect file changes. */
+ private FileMonitor monitor;
+
+ /** @scr.reference cardinality="0..1" policy="dynamic" */
+ private EventAdmin eventAdmin;
+
/**
* Same as {@link #getResource(ResourceResolver, String)}, i.e. the
* <code>request</code> parameter is ignored.
@@ -199,14 +215,39 @@ public class FsResourceProvider implements ResourceProvider {
this.providerRoot = providerRoot;
this.providerRootPrefix = providerRoot.concat("/");
this.providerFile = getProviderFile(providerFileName, bundleContext);
+ // start background monitor if check interval is higher than 100
+ long checkInterval = DEFAULT_CHECKINTERVAL;
+ final Object interval = props.get(PROP_PROVIDER_CHECKINTERVAL);
+ if ( interval != null && interval instanceof Long ) {
+ checkInterval = (Long)interval;
+ }
+ if ( checkInterval > 100 ) {
+ this.monitor = new FileMonitor(this, checkInterval);
+ }
}
protected void deactivate() {
+ if ( this.monitor != null ) {
+ this.monitor.stop();
+ this.monitor = null;
+ }
this.providerRoot = null;
this.providerRootPrefix = null;
this.providerFile = null;
}
+ EventAdmin getEventAdmin() {
+ return this.eventAdmin;
+ }
+
+ File getRootFile() {
+ return this.providerFile;
+ }
+
+ String getProviderRoot() {
+ return this.providerRoot;
+ }
+
// ---------- internal
private File getProviderFile(String providerFileName,
diff --git a/src/main/resources/META-INF/NOTICE b/src/main/resources/META-INF/NOTICE
index 7a727bf..9d9af52 100644
--- a/src/main/resources/META-INF/NOTICE
+++ b/src/main/resources/META-INF/NOTICE
@@ -1,5 +1,5 @@
Apache Sling File System Resource Provider
-Copyright 2008-2009 The Apache Software Foundation
+Copyright 2008-2010 The Apache Software Foundation
Apache Sling is based on source code originally developed
by Day Software (http://www.day.com/).
--
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.