[maven-release-plugin]  copy for tag org.apache.sling.installer.provider.file-1.1.0

git-svn-id: https://svn.apache.org/repos/asf/sling/tags/org.apache.sling.installer.provider.file-1.1.0@1674255 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/file/pom.xml b/file/pom.xml
deleted file mode 100644
index 4c3d6b9..0000000
--- a/file/pom.xml
+++ /dev/null
@@ -1,109 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-    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.
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
-
-    <modelVersion>4.0.0</modelVersion>
-    <parent>
-        <groupId>org.apache.sling</groupId>
-        <artifactId>sling</artifactId>
-        <version>22</version>
-        <relativePath>../../../parent/pom.xml</relativePath>
-    </parent>
-
-    <artifactId>org.apache.sling.installer.provider.file</artifactId>
-    <version>1.1.0</version>
-    <packaging>bundle</packaging>
-
-    <name>Apache Sling File Installer</name>
-    <description> 
-        Installs OSGi bundles and configurations from the file system.
-    </description>
-
-    <scm>
-        <connection>scm:svn:http://svn.apache.org/repos/asf/sling/tags/org.apache.sling.installer.provider.file-1.1.0</connection>
-        <developerConnection> scm:svn:https://svn.apache.org/repos/asf/sling/tags/org.apache.sling.installer.provider.file-1.1.0</developerConnection>
-        <url>http://svn.apache.org/viewvc/sling/tags/org.apache.sling.installer.provider.file-1.1.0</url>
-    </scm>
-
-    <build>
-        <plugins>
-
-            <plugin>
-                <groupId>org.apache.felix</groupId>
-                <artifactId>maven-bundle-plugin</artifactId>
-                <extensions>true</extensions>
-                <configuration>
-                    <instructions>
-                        <Bundle-Activator>
-                            org.apache.sling.installer.provider.file.impl.Activator
-                        </Bundle-Activator>
-                        <!-- 
-                             We need at least 3.1.2 as this allows reading comments from a config
-                         -->
-                        <Import-Package>
-                            org.apache.sling.installer.api;version="[3.1.2,4)",
-                            *
-                        </Import-Package>
-                        <Private-Package>
-                            org.apache.sling.installer.provider.file.impl.*
-                        </Private-Package>
-                        <Embed-Dependency>
-                            org.apache.felix.configadmin;inline="org/apache/felix/cm/file/ConfigurationHandler.*"
-                        </Embed-Dependency>
-                    </instructions>
-                </configuration>
-            </plugin>
-        </plugins>
-    </build>
-
-    <dependencies>
-        <dependency>
-            <groupId>org.osgi</groupId>
-            <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>
-        <dependency>
-            <groupId>org.apache.sling</groupId>
-            <artifactId>org.apache.sling.installer.core</artifactId>
-            <version>3.5.4</version>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.sling</groupId>
-            <artifactId>org.apache.sling.settings</artifactId>
-            <version>1.1.0</version>
-            <scope>provided</scope>
-        </dependency>
-      <!-- We use a class from the config admin implementation to read config files -->
-        <dependency>
-            <groupId>org.apache.felix</groupId>
-            <artifactId>org.apache.felix.configadmin</artifactId>
-            <version>1.2.8</version>
-            <scope>provided</scope>
-        </dependency>
-    </dependencies>
-</project>
diff --git a/file/src/main/java/org/apache/sling/installer/provider/file/impl/Activator.java b/file/src/main/java/org/apache/sling/installer/provider/file/impl/Activator.java
deleted file mode 100644
index 2b06592..0000000
--- a/file/src/main/java/org/apache/sling/installer/provider/file/impl/Activator.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * 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.installer.provider.file.impl;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.StringTokenizer;
-
-import org.osgi.framework.BundleActivator;
-import org.osgi.framework.BundleContext;
-
-/**
- * The <code>Activator</code>
- */
-public class Activator implements BundleActivator {
-
-    public static final String KEY_DIR = "sling.fileinstall.dir";
-    public static final String KEY_DELAY = "sling.fileinstall.interval";
-    public static final String KEY_WRITEBACK = "sling.fileinstall.writeback";
-
-    /** The services listener will activate the installer. */
-    private ServicesListener servicesListener;
-
-    /**
-     * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)
-     */
-    public void start(final BundleContext context) {
-        // read initial scan configurations
-        final List<ScanConfiguration> configs = new ArrayList<ScanConfiguration>();
-        final Object dir = getProp(context, KEY_DIR);
-        if ( dir != null ) {
-            Long delay = null;
-            final Object interval = getProp(context, KEY_DELAY);
-            if ( interval != null ) {
-                if ( interval instanceof Number ) {
-                    delay = ((Number)interval).longValue();
-                } else {
-                    delay = Long.valueOf(interval.toString());
-                }
-            }
-            final StringTokenizer st = new StringTokenizer(dir.toString(), ",");
-            while ( st.hasMoreTokens() ) {
-                final ScanConfiguration sc = new ScanConfiguration();
-                sc.directory = st.nextToken();
-                sc.scanInterval = delay;
-
-                configs.add(sc);
-            }
-        }
-        this.servicesListener = new ServicesListener(context, configs);
-    }
-
-    /**
-     * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
-     */
-    public void stop(final BundleContext context) {
-        this.servicesListener.deactivate();
-        this.servicesListener = null;
-    }
-
-    public static Object getProp(final BundleContext bundleContext, final String key) {
-        Object o = bundleContext.getProperty(key);
-        if (o == null) {
-            o = System.getProperty(key);
-            if ( o == null ) {
-                o = System.getProperty(key.toUpperCase().replace('.', '_'));
-            }
-        }
-        return o;
-    }
-}
diff --git a/file/src/main/java/org/apache/sling/installer/provider/file/impl/FileChangesListener.java b/file/src/main/java/org/apache/sling/installer/provider/file/impl/FileChangesListener.java
deleted file mode 100644
index 2fd34d5..0000000
--- a/file/src/main/java/org/apache/sling/installer/provider/file/impl/FileChangesListener.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * 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.installer.provider.file.impl;
-
-import java.io.File;
-import java.util.List;
-
-public interface FileChangesListener {
-
-    void initialSet(List<File> files);
-
-    void updated(List<File> added, List<File> changed, List<File> removed);
-
-    String getScheme();
-}
diff --git a/file/src/main/java/org/apache/sling/installer/provider/file/impl/FileInstaller.java b/file/src/main/java/org/apache/sling/installer/provider/file/impl/FileInstaller.java
deleted file mode 100644
index a646f61..0000000
--- a/file/src/main/java/org/apache/sling/installer/provider/file/impl/FileInstaller.java
+++ /dev/null
@@ -1,234 +0,0 @@
-/*
- * 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.installer.provider.file.impl;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.math.BigInteger;
-import java.security.MessageDigest;
-import java.util.ArrayList;
-import java.util.Dictionary;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.felix.cm.file.ConfigurationHandler;
-import org.apache.sling.installer.api.InstallableResource;
-import org.apache.sling.installer.api.OsgiInstaller;
-import org.apache.sling.installer.api.UpdateHandler;
-import org.apache.sling.installer.api.UpdateResult;
-import org.apache.sling.settings.SlingSettingsService;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * The <code>FileInstaller</code> manages the file installers and
- * handles updates.
- *
- */
-public class FileInstaller
-    implements UpdateHandler {
-
-    /** The scheme we use to register our resources. */
-    public static final String SCHEME_PREFIX = "fileinstall";
-
-    /** Logger. */
-    private final Logger logger = LoggerFactory.getLogger(this.getClass());
-
-    /** All active scan configurations. */
-    private final List<ScanConfiguration> scanConfigurations = new ArrayList<ScanConfiguration>();
-
-    /** All monitors. */
-    private final List<FileMonitor> monitors = new ArrayList<FileMonitor>();
-
-    private final boolean writeBack;
-
-    public FileInstaller(final List<ScanConfiguration> configs, final boolean writeBack) {
-        this.writeBack = writeBack;
-        if ( configs != null ) {
-            scanConfigurations.addAll(configs);
-        }
-    }
-
-    public boolean hasConfigurations() {
-        return !this.scanConfigurations.isEmpty();
-    }
-
-    public void start(final OsgiInstaller installer, final SlingSettingsService settings) {
-        for(final ScanConfiguration config : this.scanConfigurations) {
-            String key = config.directory;
-            if ( key.startsWith(settings.getSlingHomePath() + File.separator) ) {
-                key = "${sling.home}" + key.substring(settings.getSlingHomePath().length());
-            }
-            logger.debug("Starting monitor for {}", config.directory);
-            this.monitors.add(new FileMonitor(new File(config.directory),
-                    config.scanInterval, new Installer(installer, settings, config.directory, hash(key))));
-        }
-    }
-
-    public void stop() {
-        for(final FileMonitor monitor : this.monitors) {
-            monitor.stop();
-        }
-        this.monitors.clear();
-
-    }
-
-    public String[] getSchemes() {
-        final String[] schemes = new String[this.monitors.size()];
-        int index = 0;
-
-        for(final FileMonitor m : this.monitors) {
-            schemes[index] = m.getListener().getScheme();
-            index++;
-        }
-
-        return schemes;
-    }
-
-    /**
-     * @see org.apache.sling.installer.api.UpdateHandler#handleRemoval(java.lang.String, java.lang.String, java.lang.String)
-     */
-    public UpdateResult handleRemoval(final String resourceType,
-            final String id,
-            final String url) {
-        if ( !this.writeBack ) {
-            return null;
-        }
-        final int pos = url.indexOf(':');
-        final String path = url.substring(pos + 1);
-        // remove
-        logger.debug("Removal of {}", path);
-        final File file = new File(path);
-        if ( file.exists() ) {
-            file.delete();
-        }
-        return new UpdateResult(url);
-    }
-
-    /**
-     * @see org.apache.sling.installer.api.UpdateHandler#handleUpdate(java.lang.String, java.lang.String, java.lang.String, java.util.Dictionary, Map)
-     */
-    public UpdateResult handleUpdate(final String resourceType,
-            final String id,
-            final String url,
-            final Dictionary<String, Object> dict,
-            final Map<String, Object> attributes) {
-        return this.handleUpdate(resourceType, id, url, null, dict, attributes);
-    }
-
-    /**
-     * @see org.apache.sling.installer.api.UpdateHandler#handleUpdate(java.lang.String, java.lang.String, java.lang.String, java.io.InputStream, Map)
-     */
-    public UpdateResult handleUpdate(final String resourceType,
-            final String id,
-            final String url,
-            final InputStream is,
-            final Map<String, Object> attributes) {
-        return this.handleUpdate(resourceType, id, url, is, null, attributes);
-    }
-
-    /**
-     * Internal implementation of update handling
-     */
-    private UpdateResult handleUpdate(final String resourceType,
-            final String id,
-            final String url,
-            final InputStream is,
-            final Dictionary<String, Object> dict,
-            final Map<String, Object> attributes) {
-        if ( !this.writeBack ) {
-            return null;
-        }
-
-        // we only handle add/update of configs for now
-        if ( !resourceType.equals(InstallableResource.TYPE_CONFIG) ) {
-            return null;
-        }
-
-        try {
-            final String path;
-            final String prefix;
-            if ( url != null ) {
-                // update
-                final int pos = url.indexOf(':');
-                final String oldPath = url.substring(pos + 1);
-                prefix = url.substring(0, pos);
-                // ensure extension 'config'
-                if ( !oldPath.endsWith(".config") ) {
-                    final File file = new File(oldPath);
-                    if ( file.exists() ) {
-                        file.delete();
-                    }
-                    final int lastDot = oldPath.lastIndexOf('.');
-                    final int lastSlash = oldPath.lastIndexOf('/');
-                    if ( lastDot <= lastSlash ) {
-                        path = oldPath + ".config";
-                    } else {
-                        path = oldPath.substring(0, lastDot) + ".config";
-                    }
-                } else {
-                    path = oldPath;
-                }
-                logger.debug("Update of {} at {}", resourceType, path);
-            } else {
-                // add
-                final FileMonitor first = this.monitors.get(0);
-                path = first.getRoot().getAbsolutePath() + '/' + id + ".config";
-                prefix = first.getListener().getScheme();
-                logger.debug("Add of {} at {}", resourceType, path);
-            }
-
-            final File file = new File(path);
-            file.getParentFile().mkdirs();
-            final FileOutputStream fos = new FileOutputStream(file);
-            try {
-                fos.write("# Configuration created by Apache Sling File Installer\n".getBytes("UTF-8"));
-                ConfigurationHandler.write(fos, dict);
-            } finally {
-                try {
-                    fos.close();
-                } catch (final IOException ignore) {}
-            }
-
-            final UpdateResult result = new UpdateResult(prefix + ':' + path);
-            result.setResourceIsMoved(true);
-            return result;
-        } catch (final IOException e) {
-            logger.error("Unable to add/update resource " + resourceType + ':' + id, e);
-            return null;
-        }
-    }
-
-    /**
-     * Hash the string
-     */
-    private static String hash(final String value) {
-        try {
-            final MessageDigest d = MessageDigest.getInstance("MD5");
-            d.update(value.getBytes("UTF-8"));
-            final BigInteger bigInt = new BigInteger(1, d.digest());
-            return new String(bigInt.toString(16));
-        } catch (final Exception ignore) {
-            // if anything goes wrong we just return the value
-            return value;
-        }
-    }
-}
diff --git a/file/src/main/java/org/apache/sling/installer/provider/file/impl/FileMonitor.java b/file/src/main/java/org/apache/sling/installer/provider/file/impl/FileMonitor.java
deleted file mode 100644
index 085d07e..0000000
--- a/file/src/main/java/org/apache/sling/installer/provider/file/impl/FileMonitor.java
+++ /dev/null
@@ -1,287 +0,0 @@
-/*
- * 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.installer.provider.file.impl;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Timer;
-import java.util.TimerTask;
-
-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 FileChangesListener listener;
-
-    /**
-     * Creates a new instance of this class.
-     * @param interval The interval between executions of the task, in milliseconds.
-     */
-    public FileMonitor(final File rootDir, final Long interval, final FileChangesListener listener) {
-        this.listener = listener;
-        this.root = new Monitorable(rootDir);
-        createStatus(this.root);
-        final List<File> files = new ArrayList<File>();
-        collect(this.root.file, files);
-        this.listener.initialSet(files);
-        logger.debug("Starting file monitor for {} with an interval of {}ms", this.root.file, interval);
-        timer.schedule(this, 0, (interval != null ? interval : 5000));
-    }
-
-    public File getRoot() {
-        return this.root.file;
-    }
-
-    public FileChangesListener getListener() {
-        return this.listener;
-    }
-
-    private void collect(final File file, final List<File> files) {
-        if ( file.exists() ) {
-            if ( file.isDirectory() ) {
-                final File[] children = file.listFiles();
-                if ( children != null ) {
-                    for(final File child : children ) {
-                        collect(child, files);
-                    }
-                }
-            } else {
-                files.add(file);
-            }
-        }
-    }
-
-    private void collectDeleted(final Monitorable m, final List<File> files) {
-        if ( m.status instanceof DirStatus ) {
-            for(final Monitorable child : ((DirStatus)m.status).children ) {
-                collectDeleted(child, files);
-            }
-        } else {
-            files.add(m.file);
-        }
-    }
-
-    private final static class Collector {
-        public final List<File> added = new ArrayList<File>();
-        public final List<File> removed = new ArrayList<File>();
-        public final List<File> changed = new ArrayList<File>();
-    }
-
-    /**
-     * 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 {
-                final Collector c = new Collector();
-                this.check(this.root, c);
-                this.listener.updated(c.added, c.changed, c.removed);
-            } 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 Collector collector) {
-        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);
-                final List<File> files = new ArrayList<File>();
-                collect(monitorable.file, files);
-                for(final File file : files ) {
-                    collector.added.add(file);
-                }
-            }
-        } else {
-            // check if the file has been removed
-            if ( !monitorable.file.exists() ) {
-                // removed file and update status
-                final List<File> files = new ArrayList<File>();
-                collectDeleted(monitorable, files);
-                for(final File file : files ) {
-                    collector.removed.add(file);
-                }
-                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
-                    if ( monitorable.file.isFile() ) {
-                        collector.changed.add(monitorable.file);
-                    }
-                    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], collector);
-                    }
-                    // if the dir changed we have to update
-                    if ( changed ) {
-                        // and now update
-                        final File[] files = monitorable.file.listFiles();
-                        if (files != null) {
-                            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(files[i]);
-                                    children[i].status = NonExistingStatus.SINGLETON;
-                                    check(children[i], collector);
-                                }
-                            }
-                            ds.children = children;
-                        } else {
-                            ds.children = new Monitorable[0];
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    /**
-     * 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);
-        }
-    }
-
-    /** The monitorable to hold the resource path, the file and the status. */
-    private static final class Monitorable {
-        public final File   file;
-        public Object status;
-
-        public Monitorable(final File file) {
-            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) {
-            super(dir);
-            final File[] files = dir.listFiles();
-            if (files != null) {
-                this.children = new Monitorable[files.length];
-                for (int i = 0; i < files.length; i++) {
-                    this.children[i] = new Monitorable(files[i]);
-                    FileMonitor.createStatus(this.children[i]);
-                }
-            } else {
-                this.children = new Monitorable[0];
-            }
-        }
-    }
-
-    /** 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/file/src/main/java/org/apache/sling/installer/provider/file/impl/Installer.java b/file/src/main/java/org/apache/sling/installer/provider/file/impl/Installer.java
deleted file mode 100644
index 1b05e78..0000000
--- a/file/src/main/java/org/apache/sling/installer/provider/file/impl/Installer.java
+++ /dev/null
@@ -1,196 +0,0 @@
-/*
- * 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.installer.provider.file.impl;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.Dictionary;
-import java.util.Hashtable;
-import java.util.List;
-import java.util.Set;
-
-import org.apache.sling.installer.api.InstallableResource;
-import org.apache.sling.installer.api.OsgiInstaller;
-import org.apache.sling.settings.SlingSettingsService;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * The <code>Installer</code> is the service calling the
- * OSGi installer
- *
- */
-public class Installer
-    implements FileChangesListener {
-
-    /** Logger. */
-    private final Logger logger = LoggerFactory.getLogger(this.getClass());
-
-    /** The OSGi installer service. */
-    private final OsgiInstaller installer;
-
-    /** The settings service. */
-    private final Set<String> activeRunModes;
-
-    /** The scheme to use. */
-    private final String scheme;
-
-    /** Prefix. */
-    private final String prefix;
-
-    public Installer(final OsgiInstaller installer,
-            final SlingSettingsService settings,
-            final String root,
-            final String id) {
-        this.scheme = FileInstaller.SCHEME_PREFIX + id;
-        this.installer = installer;
-        this.activeRunModes = settings.getRunModes();
-        this.prefix = new File(root).getAbsolutePath() + File.separator;
-    }
-
-    /**
-     * @see org.apache.sling.installer.provider.file.impl.FileChangesListener#getScheme()
-     */
-    public String getScheme() {
-        return this.scheme;
-    }
-
-    /**
-     * @see org.apache.sling.installer.provider.file.impl.FileChangesListener#initialSet(java.util.List)
-     */
-    public void initialSet(final List<File> files) {
-        logger.debug("Initial set for {}", this.scheme);
-        final List<InstallableResource> resources = new ArrayList<InstallableResource>();
-        for(final File f : files) {
-            logger.debug("Initial file {}", f);
-            final InstallableResource resource = this.createResource(f);
-            if ( resource != null ) {
-                resources.add(resource);
-            }
-        }
-        this.installer.registerResources(this.scheme, resources.toArray(new InstallableResource[resources.size()]));
-    }
-
-    /**
-     * @see org.apache.sling.installer.provider.file.impl.FileChangesListener#updated(java.util.List, java.util.List, java.util.List)
-     */
-    public void updated(List<File> added, List<File> changed, List<File> removed) {
-        final List<InstallableResource> updated;
-        if ( (added != null && added.size() > 0) || (changed != null && changed.size() > 0) ) {
-            updated = new ArrayList<InstallableResource>();
-            if ( added != null ) {
-                for(final File f : added) {
-                    logger.debug("Added file {}", f);
-                    final InstallableResource resource = this.createResource(f);
-                    if ( resource != null ) {
-                        updated.add(resource);
-                    }
-                }
-            }
-            if ( changed != null ) {
-                for(final File f : changed) {
-                    logger.debug("Changed file {}", f);
-                    final InstallableResource resource = this.createResource(f);
-                    if ( resource != null ) {
-                        updated.add(resource);
-                    }
-                }
-            }
-        } else {
-            updated = null;
-        }
-        final String[] removedUrls;
-        if ( removed != null && removed.size() > 0 ) {
-            removedUrls = new String[removed.size()];
-            int index = 0;
-            for(final File f : removed) {
-                removedUrls[index] = f.getAbsolutePath();
-                logger.debug("Removed file {}", removedUrls[index]);
-                index++;
-            }
-        } else {
-            removedUrls = null;
-        }
-        if ( updated != null || removedUrls != null ) {
-            this.installer.updateResources(this.scheme,
-                    updated == null ? null : updated.toArray(new InstallableResource[updated.size()]), removedUrls);
-        }
-    }
-
-    private InstallableResource createResource(final File file) {
-        try {
-            // check for run modes
-            final String name = file.getAbsolutePath().substring(this.prefix.length()).replace(File.separatorChar, '/');
-            boolean isActive = true;
-            Integer prio = null;
-            final int pos = name.indexOf('/');
-            if ( pos != -1 && name.startsWith("install.") ) {
-                final String runModes = name.substring(8, pos);
-                final int activeModes = this.isActive(runModes);
-                if ( activeModes > 0 ) {
-                    prio = InstallableResource.DEFAULT_PRIORITY + activeModes;
-                } else {
-                    isActive = false;
-                }
-            }
-            if ( isActive ) {
-                final InputStream is = new FileInputStream(file);
-                final String digest = String.valueOf(file.lastModified());
-                // if this is a bundle check for start level directory!
-                final Dictionary<String, Object> dict = new Hashtable<String, Object>();
-                if ( file.getName().endsWith(".jar") || file.getName().endsWith(".war") ) {
-                    final String parentName = file.getParentFile().getName();
-                    try {
-                        final int startLevel = Integer.valueOf(parentName);
-                        if ( startLevel > 0 ) {
-                            dict.put(InstallableResource.BUNDLE_START_LEVEL, startLevel);
-                        }
-                    } catch (NumberFormatException nfe) {
-                        // ignore this
-                    }
-                }
-                dict.put(InstallableResource.RESOURCE_URI_HINT, file.toURI().toString());
-                return new InstallableResource(file.getAbsolutePath(), is, dict, digest,
-                    null, prio);
-            } else {
-                logger.info("Ignoring inactive resource at {}", file);
-            }
-
-        } catch (IOException io) {
-            logger.error("Unable to read file " + file, io);
-        }
-        return null;
-    }
-
-    private int isActive(final String runModesString) {
-        final String[] runModes = runModesString.split("\\.");
-        boolean active = true;
-        for(final String mode : runModes) {
-            if ( !activeRunModes.contains(mode) ) {
-                active = false;
-                break;
-            }
-        }
-
-        return active ? runModes.length : 0;
-    }
-}
diff --git a/file/src/main/java/org/apache/sling/installer/provider/file/impl/ScanConfiguration.java b/file/src/main/java/org/apache/sling/installer/provider/file/impl/ScanConfiguration.java
deleted file mode 100644
index 0e82304..0000000
--- a/file/src/main/java/org/apache/sling/installer/provider/file/impl/ScanConfiguration.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * 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.installer.provider.file.impl;
-
-/**
- * A scan configuration for the file install.
- */
-public class ScanConfiguration {
-
-    public String directory;
-
-    public Long   scanInterval;
-}
diff --git a/file/src/main/java/org/apache/sling/installer/provider/file/impl/ServicesListener.java b/file/src/main/java/org/apache/sling/installer/provider/file/impl/ServicesListener.java
deleted file mode 100644
index 90d016a..0000000
--- a/file/src/main/java/org/apache/sling/installer/provider/file/impl/ServicesListener.java
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
- * 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.installer.provider.file.impl;
-
-import java.util.Dictionary;
-import java.util.Hashtable;
-import java.util.List;
-
-import org.apache.sling.installer.api.OsgiInstaller;
-import org.apache.sling.installer.api.UpdateHandler;
-import org.apache.sling.settings.SlingSettingsService;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.Constants;
-import org.osgi.framework.InvalidSyntaxException;
-import org.osgi.framework.ServiceEvent;
-import org.osgi.framework.ServiceListener;
-import org.osgi.framework.ServiceReference;
-import org.osgi.framework.ServiceRegistration;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * The <code>ServicesListener</code> listens for the required services
- * and starts/stops the scanners based on the availability of the
- * services.
- */
-public class ServicesListener {
-
-    /** The logger. */
-    private final Logger logger = LoggerFactory.getLogger(this.getClass());
-
-    /** The name of the installer service. */
-    private static final String INSTALLER_SERVICE_NAME = OsgiInstaller.class.getName();
-
-    /** The name of the settings service. */
-    private static final String SETTINGS_SERVICE_NAME = SlingSettingsService.class.getName();
-
-    /** The bundle context. */
-    private final BundleContext bundleContext;
-
-    /** The listener for the installer. */
-    private final Listener installerListener;
-
-    /** The listener for the settings service. */
-    private final Listener settingsListener;
-
-    /** The file installer. */
-    private final FileInstaller installer;
-
-    /** Service registration. */
-    private ServiceRegistration registration;
-
-    private boolean running = false;
-
-    public ServicesListener(final BundleContext bundleContext,
-            final List<ScanConfiguration> configs) {
-        this.bundleContext = bundleContext;
-        boolean writeBack = true;
-        final Object writeBackObj = Activator.getProp(this.bundleContext, Activator.KEY_WRITEBACK);
-        if ( writeBackObj != null && "false".equalsIgnoreCase(writeBackObj.toString())) {
-            writeBack = false;
-        }
-        this.installer = new FileInstaller(configs, writeBack);
-        this.installerListener = new Listener(INSTALLER_SERVICE_NAME);
-        this.settingsListener = new Listener(SETTINGS_SERVICE_NAME);
-        this.installerListener.start();
-        this.settingsListener.start();
-    }
-
-    public synchronized void notifyChange() {
-        final boolean shouldRun = this.installer.hasConfigurations();
-        if ( (shouldRun && !running) || (!shouldRun && running) ) {
-            final OsgiInstaller installer = (OsgiInstaller)this.installerListener.getService();
-            final SlingSettingsService settings = (SlingSettingsService)this.settingsListener.getService();
-            if ( installer != null && settings != null && !running ) {
-                logger.debug("Starting scanner");
-                this.startScanner(installer, settings);
-            } else if ( running && (installer == null || settings == null) ) {
-                logger.debug("Stopping scanner");
-                this.stopScanner();
-            }
-        }
-    }
-
-    /**
-     * Deactivate this listener.
-     */
-    public void deactivate() {
-        this.installerListener.deactivate();
-        this.stopScanner();
-    }
-
-    /** Vendor of all registered services. */
-    public static final String VENDOR = "The Apache Software Foundation";
-
-    private void startScanner(final OsgiInstaller installer, final SlingSettingsService settings) {
-        if ( !running ) {
-            this.installer.start(installer, settings);
-            final Dictionary<String, Object> props = new Hashtable<String, Object>();
-            props.put(Constants.SERVICE_DESCRIPTION, "Apache Sling File Installer Controller Service");
-            props.put(Constants.SERVICE_VENDOR, VENDOR);
-            props.put(UpdateHandler.PROPERTY_SCHEMES, this.installer.getSchemes());
-
-            this.registration = this.bundleContext.registerService(UpdateHandler.class.getName(),
-                    this.installer, props);
-            running = true;
-        }
-    }
-
-    private void stopScanner() {
-        if ( running ) {
-            if ( this.registration != null ) {
-                this.registration.unregister();
-                this.registration = null;
-            }
-            this.installer.stop();
-            running = false;
-        }
-    }
-
-    protected final class Listener implements ServiceListener {
-
-        private final String serviceName;
-
-        private ServiceReference reference;
-        private Object service;
-
-        public Listener(final String serviceName) {
-            this.serviceName = serviceName;
-        }
-
-        public void start() {
-            this.retainService();
-            try {
-                bundleContext.addServiceListener(this, "("
-                        + Constants.OBJECTCLASS + "=" + serviceName + ")");
-            } catch (final InvalidSyntaxException ise) {
-                // this should really never happen
-                throw new RuntimeException("Unexpected exception occured.", ise);
-            }
-        }
-
-        public void deactivate() {
-            bundleContext.removeServiceListener(this);
-        }
-
-        public synchronized Object getService() {
-            return this.service;
-        }
-        private synchronized void retainService() {
-            if ( this.reference == null ) {
-                this.reference = bundleContext.getServiceReference(this.serviceName);
-                if ( this.reference != null ) {
-                    this.service = bundleContext.getService(this.reference);
-                    if ( this.service == null ) {
-                        this.reference = null;
-                    } else {
-                        notifyChange();
-                    }
-                }
-            }
-        }
-
-        private synchronized void releaseService() {
-            if ( this.reference != null ) {
-                this.service = null;
-                bundleContext.ungetService(this.reference);
-                this.reference = null;
-                notifyChange();
-            }
-        }
-
-        /**
-         * @see org.osgi.framework.ServiceListener#serviceChanged(org.osgi.framework.ServiceEvent)
-         */
-        public void serviceChanged(ServiceEvent event) {
-            if (event.getType() == ServiceEvent.REGISTERED && this.service == null ) {
-                this.retainService();
-            } else if ( event.getType() == ServiceEvent.UNREGISTERING && this.service != null ) {
-                this.releaseService();
-            }
-        }
-    }
-}
diff --git a/src/main/java/org/apache/sling/installer/provider/file/impl/FileInstaller.java b/src/main/java/org/apache/sling/installer/provider/file/impl/FileInstaller.java
index b0dce00..a646f61 100644
--- a/src/main/java/org/apache/sling/installer/provider/file/impl/FileInstaller.java
+++ b/src/main/java/org/apache/sling/installer/provider/file/impl/FileInstaller.java
@@ -73,9 +73,13 @@
 
     public void start(final OsgiInstaller installer, final SlingSettingsService settings) {
         for(final ScanConfiguration config : this.scanConfigurations) {
+            String key = config.directory;
+            if ( key.startsWith(settings.getSlingHomePath() + File.separator) ) {
+                key = "${sling.home}" + key.substring(settings.getSlingHomePath().length());
+            }
             logger.debug("Starting monitor for {}", config.directory);
             this.monitors.add(new FileMonitor(new File(config.directory),
-                    config.scanInterval, new Installer(installer, settings, config.directory, hash(config.directory))));
+                    config.scanInterval, new Installer(installer, settings, config.directory, hash(key))));
         }
     }
 
@@ -216,13 +220,13 @@
     /**
      * Hash the string
      */
-    private static String hash(String value) {
+    private static String hash(final String value) {
         try {
             final MessageDigest d = MessageDigest.getInstance("MD5");
             d.update(value.getBytes("UTF-8"));
             final BigInteger bigInt = new BigInteger(1, d.digest());
             return new String(bigInt.toString(16));
-        } catch (Exception ignore) {
+        } catch (final Exception ignore) {
             // if anything goes wrong we just return the value
             return value;
         }