SLING-4490 : Refactor JCR installer

git-svn-id: https://svn.apache.org/repos/asf/sling/trunk@1665574 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/src/main/java/org/apache/sling/installer/provider/jcr/impl/InstallerConfig.java b/src/main/java/org/apache/sling/installer/provider/jcr/impl/InstallerConfig.java
new file mode 100644
index 0000000..13491a1
--- /dev/null
+++ b/src/main/java/org/apache/sling/installer/provider/jcr/impl/InstallerConfig.java
@@ -0,0 +1,153 @@
+/*
+ * 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.jcr.impl;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Dictionary;
+
+import org.apache.sling.commons.osgi.PropertiesUtil;
+import org.apache.sling.installer.provider.jcr.impl.JcrInstaller.NodeConverter;
+import org.apache.sling.settings.SlingSettingsService;
+import org.osgi.framework.Constants;
+import org.osgi.service.component.ComponentContext;
+import org.slf4j.Logger;
+
+public class InstallerConfig {
+
+    /** Write back enabled? */
+    private final boolean writeBack;
+
+    /** Our NodeConverters*/
+    private final Collection <NodeConverter> converters = new ArrayList<NodeConverter>();
+
+    private final int maxWatchedFolderDepth;
+
+    /** Filter for folder names */
+    private final FolderNameFilter folderNameFilter;
+
+    /** The root folders that we watch */
+    private final String [] roots;
+
+    /** The path for new configurations. */
+    private final String newConfigPath;
+
+    /** The path for pauseInstallation property */
+    private final String pauseScanNodePath;
+
+    public InstallerConfig(
+            final Logger logger,
+            final ComponentContext ctx,
+            final Dictionary<?, ?> cfg,
+            final SlingSettingsService settings) {
+        this.writeBack = PropertiesUtil.toBoolean(getPropertyValue(logger, ctx, cfg, JcrInstaller.PROP_ENABLE_WRITEBACK), JcrInstaller.DEFAULT_ENABLE_WRITEBACK);
+
+        // Setup converters
+        converters.add(new FileNodeConverter());
+        converters.add(new ConfigNodeConverter());
+
+        // Configurable max depth, system property (via bundle context) overrides default value
+        final Object obj = getPropertyValue(logger, ctx, cfg, JcrInstaller.PROP_INSTALL_FOLDER_MAX_DEPTH);
+        if (obj != null) {
+            // depending on where it's coming from, obj might be a string or integer
+            maxWatchedFolderDepth = Integer.valueOf(String.valueOf(obj)).intValue();
+            logger.debug("Using configured ({}) folder name max depth '{}'", JcrInstaller.PROP_INSTALL_FOLDER_MAX_DEPTH, maxWatchedFolderDepth);
+        } else {
+            maxWatchedFolderDepth = JcrInstaller.DEFAULT_FOLDER_MAX_DEPTH;
+            logger.debug("Using default folder max depth {}, not provided by {}", maxWatchedFolderDepth, JcrInstaller.PROP_INSTALL_FOLDER_MAX_DEPTH);
+        }
+
+        // Configurable folder regexp, system property overrides default value
+        String folderNameRegexp = (String)getPropertyValue(logger, ctx, cfg, JcrInstaller.FOLDER_NAME_REGEXP_PROPERTY);
+        if(folderNameRegexp != null) {
+            folderNameRegexp = folderNameRegexp.trim();
+            logger.debug("Using configured ({}) folder name regexp '{}'", JcrInstaller.FOLDER_NAME_REGEXP_PROPERTY, folderNameRegexp);
+        } else {
+            folderNameRegexp = JcrInstaller.DEFAULT_FOLDER_NAME_REGEXP;
+            logger.debug("Using default folder name regexp '{}', not provided by {}", folderNameRegexp, JcrInstaller.FOLDER_NAME_REGEXP_PROPERTY);
+        }
+
+        // Setup folder filtering and watching
+        this.folderNameFilter = new FolderNameFilter(PropertiesUtil.toStringArray(getPropertyValue(logger, ctx, cfg, JcrInstaller.PROP_SEARCH_PATH), JcrInstaller.DEFAULT_SEARCH_PATH),
+                folderNameRegexp, settings.getRunModes());
+        this.roots = folderNameFilter.getRootPaths();
+
+        // setup default path for new configurations
+        String newCfgPath = PropertiesUtil.toString(getPropertyValue(logger, ctx, cfg, JcrInstaller.PROP_NEW_CONFIG_PATH), JcrInstaller.DEFAULT_NEW_CONFIG_PATH);
+        final boolean postSlash = newCfgPath.endsWith("/");
+        if ( !postSlash ) {
+            newCfgPath = newCfgPath.concat("/");
+        }
+        final boolean preSlash = newCfgPath.startsWith("/");
+        if ( !preSlash ) {
+            newCfgPath = this.folderNameFilter.getRootPaths()[0] + '/' + newCfgPath;
+        }
+        this.newConfigPath = newCfgPath;
+
+        this.pauseScanNodePath = PropertiesUtil.toString(getPropertyValue(logger, ctx, cfg, JcrInstaller.PROP_SCAN_PROP_PATH), JcrInstaller.PAUSE_SCAN_NODE_PATH);
+    }
+
+    /** Get a property value from the old config, component context or bundle context */
+    private Object getPropertyValue(final Logger logger, final ComponentContext ctx, final Dictionary<?, ?> oldConfig, final String name) {
+        Object result = null;
+        if ( oldConfig != null ) {
+            result = oldConfig.get(name);
+            if ( result != null ) {
+                logger.warn("Using configuration value from obsolete configuration with PID {} for property {}." +
+                            " Please merge this configuration into the configuration with the PID {}.",
+                            new Object[] {JcrInstaller.OLD_PID, name, ctx.getProperties().get(Constants.SERVICE_PID)});
+            }
+        }
+        if ( result == null ) {
+            result = ctx.getBundleContext().getProperty(name);
+            if (result == null) {
+                result = ctx.getProperties().get(name);
+            }
+        }
+        return result;
+    }
+
+    public String[] getRoots() {
+        return this.roots;
+    }
+
+    public FolderNameFilter getFolderNameFilter() {
+        return this.folderNameFilter;
+    }
+
+    public Collection <NodeConverter> getConverters() {
+        return this.converters;
+    }
+
+    public int getMaxWatchedFolderDepth() {
+        return maxWatchedFolderDepth;
+    }
+
+    public String getPauseScanNodePath() {
+        return pauseScanNodePath;
+    }
+
+    public boolean isWriteBack() {
+        return this.writeBack;
+    }
+
+    public String getNewConfigPath() {
+        return this.newConfigPath;
+    }
+}
diff --git a/src/main/java/org/apache/sling/installer/provider/jcr/impl/JcrInstaller.java b/src/main/java/org/apache/sling/installer/provider/jcr/impl/JcrInstaller.java
index 6b62d0e..e28db6c 100644
--- a/src/main/java/org/apache/sling/installer/provider/jcr/impl/JcrInstaller.java
+++ b/src/main/java/org/apache/sling/installer/provider/jcr/impl/JcrInstaller.java
@@ -24,12 +24,12 @@
 import java.io.InputStream;
 import java.util.ArrayList;
 import java.util.Calendar;
-import java.util.Collection;
 import java.util.Dictionary;
 import java.util.Hashtable;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
 
 import javax.jcr.Node;
 import javax.jcr.NodeIterator;
@@ -46,7 +46,6 @@
 import org.apache.felix.scr.annotations.PropertyUnbounded;
 import org.apache.felix.scr.annotations.Reference;
 import org.apache.felix.scr.annotations.Service;
-import org.apache.sling.commons.osgi.PropertiesUtil;
 import org.apache.sling.installer.api.InstallableResource;
 import org.apache.sling.installer.api.OsgiInstaller;
 import org.apache.sling.installer.api.UpdateHandler;
@@ -82,7 +81,7 @@
 	public static final String URL_SCHEME = "jcrinstall";
 
 	/** PID before refactoring. */
-	private static final String OLD_PID = "org.apache.sling.jcr.install.impl.JcrInstaller";
+	public static final String OLD_PID = "org.apache.sling.jcr.install.impl.JcrInstaller";
 
 	private final Logger logger = LoggerFactory.getLogger(getClass());
 
@@ -148,20 +147,12 @@
     public static final String PROP_SEARCH_PATH = "sling.jcrinstall.search.path";
     public static final String [] DEFAULT_SEARCH_PATH = { "/libs:100", "/apps:200" };
 
-    private volatile int maxWatchedFolderDepth;
-
-    /** Filter for folder names */
-    private volatile FolderNameFilter folderNameFilter;
-
     /** List of watched folders */
     private volatile List<WatchedFolder> watchedFolders;
 
     /** Session shared by all WatchedFolder */
     private volatile Session session;
 
-    /** The root folders that we watch */
-    private volatile String [] roots;
-
     /** The component context. */
     private volatile ComponentContext componentContext;
 
@@ -171,28 +162,19 @@
     /** Configuration from managed service (old pid) */
     private volatile Dictionary<?, ?> oldConfiguration;
 
-    private static final String DEFAULT_NEW_CONFIG_PATH = "sling/install";
+    public static final String DEFAULT_NEW_CONFIG_PATH = "sling/install";
     @Property(value=DEFAULT_NEW_CONFIG_PATH)
-    private static final String PROP_NEW_CONFIG_PATH = "sling.jcrinstall.new.config.path";
-
-    /** The path for new configurations. */
-    private volatile String newConfigPath;
+    public static final String PROP_NEW_CONFIG_PATH = "sling.jcrinstall.new.config.path";
 
     public static final String PAUSE_SCAN_NODE_PATH = "/system/sling/installer/jcr/pauseInstallation";
     @Property(value= PAUSE_SCAN_NODE_PATH)
-    private static final String PROP_SCAN_PROP_PATH = "sling.jcrinstall.signal.path";
-
-    /** The path for pauseInstallation property */
-    private volatile String pauseScanNodePath;
+    public static final String PROP_SCAN_PROP_PATH = "sling.jcrinstall.signal.path";
 
     private volatile boolean pauseMessageLogged = false;
 
-    private static final boolean DEFAULT_ENABLE_WRITEBACK = true;
+    public static final boolean DEFAULT_ENABLE_WRITEBACK = true;
     @Property(boolValue=DEFAULT_ENABLE_WRITEBACK)
-    private static final String PROP_ENABLE_WRITEBACK = "sling.jcrinstall.enable.writeback";
-
-    /** Write back enabled? */
-    private volatile boolean writeBack;
+    public static final String PROP_ENABLE_WRITEBACK = "sling.jcrinstall.enable.writeback";
 
     private volatile EventListener moveEventListener;
 
@@ -202,9 +184,6 @@
     	throws RepositoryException;
     }
 
-    /** Our NodeConverters*/
-    private final Collection <NodeConverter> converters = new ArrayList<NodeConverter>();
-
     /** Detect newly created folders that we must watch */
     private final List<RootFolderListener> listeners = new LinkedList<RootFolderListener>();
 
@@ -212,16 +191,20 @@
     private final RescanTimer updateFoldersListTimer = new RescanTimer();
 
     /** Thread that can be cleanly stopped with a flag */
-    static volatile int bgThreadCounter;
+    private final static AtomicInteger bgThreadCounter = new AtomicInteger();
     class StoppableThread extends Thread {
 
+
         /** Used for synchronizing. */
         final Object lock = new Object();
         volatile boolean active = true;
 
-        StoppableThread() {
+        private final InstallerConfig cfg;
+
+        StoppableThread(final InstallerConfig cfg) {
+            this.cfg = cfg;
             synchronized (JcrInstaller.class) {
-                setName("JcrInstaller." + (++bgThreadCounter));
+                setName("JcrInstaller." + String.valueOf(bgThreadCounter.incrementAndGet()));
             }
             setDaemon(true);
         }
@@ -235,8 +218,8 @@
                         // open session
                         session = repository.loginAdministrative(repository.getDefaultWorkspace());
 
-                        for (String path : roots) {
-                            listeners.add(new RootFolderListener(session, folderNameFilter, path, updateFoldersListTimer));
+                        for (String path : cfg.getRoots()) {
+                            listeners.add(new RootFolderListener(session, cfg.getFolderNameFilter(), path, updateFoldersListTimer));
                             logger.debug("Configured root folder: {}", path);
                         }
 
@@ -258,8 +241,8 @@
                                 try {
                                     while (events.hasNext()) {
                                         final Event e = events.nextEvent();
-                                        JcrInstaller.this.checkChanges(e.getIdentifier());
-                                        JcrInstaller.this.checkChanges(e.getPath());
+                                        JcrInstaller.this.checkChanges(cfg, e.getIdentifier());
+                                        JcrInstaller.this.checkChanges(cfg, e.getPath());
                                     }
                                 } catch (final RepositoryException re) {
                                     logger.warn("RepositoryException in onEvent", re);
@@ -280,8 +263,8 @@
 
                         // Find paths to watch and create WatchedFolders to manage them
                         watchedFolders = new LinkedList<WatchedFolder>();
-                        for(String root : roots) {
-                            findPathsToWatch(root, watchedFolders);
+                        for(String root : cfg.getRoots()) {
+                            findPathsToWatch(cfg, root, watchedFolders);
                         }
 
                         // Scan watchedFolders and register resources with installer
@@ -324,11 +307,15 @@
             }
 
             while (active) {
-                runOneCycle();
+                runOneCycle(cfg);
             }
             logger.info("Background thread {} done", Thread.currentThread().getName());
             counters[RUN_LOOP_COUNTER] = -1;
         }
+
+        public InstallerConfig getConfiguration() {
+            return this.cfg;
+        }
     };
     private volatile StoppableThread backgroundThread;
 
@@ -347,52 +334,9 @@
 
     private void start() {
         logger.info("Activating Apache Sling JCR Installer");
-        this.writeBack = PropertiesUtil.toBoolean(getPropertyValue(PROP_ENABLE_WRITEBACK), DEFAULT_ENABLE_WRITEBACK);
+        final InstallerConfig cfg = new InstallerConfig(logger, componentContext, oldConfiguration, settings);
 
-    	// Setup converters
-    	converters.add(new FileNodeConverter());
-    	converters.add(new ConfigNodeConverter());
-
-    	// Configurable max depth, system property (via bundle context) overrides default value
-    	final Object obj = getPropertyValue(PROP_INSTALL_FOLDER_MAX_DEPTH);
-    	if (obj != null) {
-    		// depending on where it's coming from, obj might be a string or integer
-    		maxWatchedFolderDepth = Integer.valueOf(String.valueOf(obj)).intValue();
-            logger.debug("Using configured ({}) folder name max depth '{}'", PROP_INSTALL_FOLDER_MAX_DEPTH, maxWatchedFolderDepth);
-    	} else {
-            maxWatchedFolderDepth = DEFAULT_FOLDER_MAX_DEPTH;
-            logger.debug("Using default folder max depth {}, not provided by {}", maxWatchedFolderDepth, PROP_INSTALL_FOLDER_MAX_DEPTH);
-    	}
-
-    	// Configurable folder regexp, system property overrides default value
-    	String folderNameRegexp = (String)getPropertyValue(FOLDER_NAME_REGEXP_PROPERTY);
-    	if(folderNameRegexp != null) {
-    		folderNameRegexp = folderNameRegexp.trim();
-            logger.debug("Using configured ({}) folder name regexp '{}'", FOLDER_NAME_REGEXP_PROPERTY, folderNameRegexp);
-    	} else {
-    	    folderNameRegexp = DEFAULT_FOLDER_NAME_REGEXP;
-            logger.debug("Using default folder name regexp '{}', not provided by {}", folderNameRegexp, FOLDER_NAME_REGEXP_PROPERTY);
-    	}
-
-    	// Setup folder filtering and watching
-        folderNameFilter = new FolderNameFilter(PropertiesUtil.toStringArray(getPropertyValue(PROP_SEARCH_PATH), DEFAULT_SEARCH_PATH),
-                folderNameRegexp, settings.getRunModes());
-        roots = folderNameFilter.getRootPaths();
-
-        // setup default path for new configurations
-        this.newConfigPath = PropertiesUtil.toString(getPropertyValue(PROP_NEW_CONFIG_PATH), DEFAULT_NEW_CONFIG_PATH);
-        final boolean postSlash = newConfigPath.endsWith("/");
-        if ( !postSlash ) {
-            this.newConfigPath = newConfigPath.concat("/");
-        }
-        final boolean preSlash = newConfigPath.startsWith("/");
-        if ( !preSlash ) {
-            this.newConfigPath = this.folderNameFilter.getRootPaths()[0] + '/' + this.newConfigPath;
-        }
-
-        this.pauseScanNodePath = PropertiesUtil.toString(getPropertyValue(PROP_SCAN_PROP_PATH), PAUSE_SCAN_NODE_PATH);
-
-        backgroundThread = new StoppableThread();
+        backgroundThread = new StoppableThread(cfg);
         backgroundThread.start();
     }
 
@@ -440,9 +384,7 @@
         }
         listeners.clear();
 
-        folderNameFilter = null;
         watchedFolders = null;
-        converters.clear();
     }
 
 
@@ -468,30 +410,9 @@
         }
     }
 
-    /** Get a property value from the old config, component context or bundle context */
-    protected Object getPropertyValue(final String name) {
-        final Dictionary<?, ?> oldConfig = this.oldConfiguration;
-        Object result = null;
-        if ( oldConfig != null ) {
-            result = oldConfig.get(name);
-            if ( result != null ) {
-                logger.warn("Using configuration value from obsolete configuration with PID {} for property {}." +
-                            " Please merge this configuration into the configuration with the PID {}.",
-                            new Object[] {OLD_PID, name, this.componentContext.getProperties().get(Constants.SERVICE_PID)});
-            }
-        }
-        if ( result == null ) {
-            result = this.componentContext.getBundleContext().getProperty(name);
-            if (result == null) {
-                result = this.componentContext.getProperties().get(name);
-            }
-        }
-        return result;
-    }
-
     /** Find the paths to watch under rootPath, according to our folderNameFilter,
      * 	and add them to result */
-    private void findPathsToWatch(final String rootPath, final List<WatchedFolder> result) throws RepositoryException {
+    private void findPathsToWatch(final InstallerConfig cfg, final String rootPath, final List<WatchedFolder> result) throws RepositoryException {
         Session s = null;
 
         try {
@@ -501,7 +422,7 @@
             } else {
                 logger.debug("Bundles root node {} found, looking for bundle folders inside it", rootPath);
                 final Node n = (Node)s.getItem(rootPath);
-                findPathsUnderNode(n, result);
+                findPathsUnderNode(cfg, n, result);
             }
         } finally {
             if (s != null) {
@@ -514,20 +435,20 @@
      * Add n to result if it is a folder that we must watch, and recurse into its children
      * to do the same.
      */
-    void findPathsUnderNode(final Node n, final List<WatchedFolder> result) throws RepositoryException {
+    void findPathsUnderNode(final InstallerConfig cfg, final Node n, final List<WatchedFolder> result) throws RepositoryException {
         final String path = n.getPath();
-        final int priority = folderNameFilter.getPriority(path);
+        final int priority = cfg.getFolderNameFilter().getPriority(path);
         if (priority > 0) {
-            result.add(new WatchedFolder(session, path, priority, converters));
+            result.add(new WatchedFolder(session, path, priority, cfg.getConverters()));
         }
         final int depth = path.split("/").length;
-        if(depth > maxWatchedFolderDepth) {
-            logger.debug("Not recursing into {} due to maxWatchedFolderDepth={}", path, maxWatchedFolderDepth);
+        if(depth > cfg.getMaxWatchedFolderDepth()) {
+            logger.debug("Not recursing into {} due to maxWatchedFolderDepth={}", path, cfg.getMaxWatchedFolderDepth());
             return;
         }
         final NodeIterator it = n.getNodes();
         while (it.hasNext()) {
-            findPathsUnderNode(it.nextNode(), result);
+            findPathsUnderNode(cfg, it.nextNode(), result);
         }
     }
 
@@ -553,14 +474,14 @@
      *  @return a list of InstallableResource that must be unregistered,
      *  	for folders that have been removed
      */
-    private List<String> updateFoldersList() throws Exception {
+    private List<String> updateFoldersList(final InstallerConfig cfg) throws Exception {
         logger.debug("Updating folder list.");
 
         final List<String> result = new LinkedList<String>();
 
         final List<WatchedFolder> newFolders = new ArrayList<WatchedFolder>();
-	    for(String root : roots) {
-	        findPathsToWatch(root, newFolders);
+	    for(String root : cfg.getRoots()) {
+	        findPathsToWatch(cfg, root, newFolders);
 	    }
 	    for(WatchedFolder wf : newFolders) {
 	        addWatchedFolder(wf);
@@ -588,8 +509,8 @@
     /**
      * Check for changes in any of the root folders
      */
-    private void checkChanges(final String path) {
-        for(String root : roots) {
+    private void checkChanges(final InstallerConfig cfg, final String path) {
+        for(String root : cfg.getRoots()) {
             if (path.startsWith(root)) {
                 logger.info("Got event for root {}, scheduling scanning of new folders", root);
                 updateFoldersListTimer.scheduleScan();
@@ -597,28 +518,41 @@
         }
     }
 
+    InstallerConfig getConfiguration() {
+        InstallerConfig cfg = null;
+        final StoppableThread st = this.backgroundThread;
+        if ( st != null ) {
+            cfg = st.getConfiguration();
+        }
+        return cfg;
+    }
+
     /**
      * @see javax.jcr.observation.EventListener#onEvent(javax.jcr.observation.EventIterator)
      */
     public void onEvent(final EventIterator it) {
         // Got a DELETE or ADD on root - schedule folders rescan if one
         // of our root folders is impacted
-        try {
-            while(it.hasNext()) {
-                final Event e = it.nextEvent();
-                logger.debug("Got event {}", e);
+        // get configuration
+        final InstallerConfig cfg = this.getConfiguration();
+        if ( cfg != null ) {
+            try {
+                while(it.hasNext()) {
+                    final Event e = it.nextEvent();
+                    logger.debug("Got event {}", e);
 
-                this.checkChanges(e.getPath());
+                    this.checkChanges(cfg, e.getPath());
+                }
+            } catch(RepositoryException re) {
+                logger.warn("RepositoryException in onEvent", re);
             }
-        } catch(RepositoryException re) {
-            logger.warn("RepositoryException in onEvent", re);
         }
     }
 
     /**
      * Run periodic scans of our watched folders, and watch for folders creations/deletions.
      */
-    public void runOneCycle() {
+    public void runOneCycle(final InstallerConfig cfg) {
         logger.debug("Running watch cycle.");
 
         try {
@@ -627,11 +561,11 @@
             if (anyWatchFolderNeedsScan()) {
                 session.refresh(false);
                 didRefresh = true;
-                if (scanningIsPaused()) {
+                if (scanningIsPaused(cfg)) {
                     if (!pauseMessageLogged) {
                         //Avoid flooding the logs every 500 msec so log at info level once
                         logger.info("Detected signal for pausing the JCR Provider i.e. child nodes found under path {}. " +
-                                "JCR Provider scanning would not be performed", pauseScanNodePath);
+                                "JCR Provider scanning would not be performed", cfg.getPauseScanNodePath());
                         pauseMessageLogged = true;
                     }
                     return;
@@ -677,7 +611,7 @@
                 }
                 updateFoldersListTimer.reset();
                 counters[UPDATE_FOLDERS_LIST_COUNTER]++;
-                final List<String> toRemove = updateFoldersList();
+                final List<String> toRemove = updateFoldersList(cfg);
                 if ( toRemove.size() > 0 ) {
                     logger.info("Removing resource from OSGi installer (folder deleted): {}", toRemove);
                     installer.updateResources(URL_SCHEME, null,
@@ -700,9 +634,9 @@
         counters[RUN_LOOP_COUNTER]++;
     }
 
-    boolean scanningIsPaused() throws RepositoryException {
-        if (session.nodeExists(pauseScanNodePath)) {
-            Node node = session.getNode(pauseScanNodePath);
+    boolean scanningIsPaused(final InstallerConfig cfg) throws RepositoryException {
+        if (session.nodeExists(cfg.getPauseScanNodePath())) {
+            Node node = session.getNode(cfg.getPauseScanNodePath());
             boolean result = node.hasNodes();
             if (result && logger.isDebugEnabled()) {
                 List<String> nodeNames = new ArrayList<String>();
@@ -710,7 +644,7 @@
                 while (childItr.hasNext()) {
                     nodeNames.add(childItr.nextNode().getName());
                 }
-                logger.debug("Found child nodes {} at path {}. Scanning would be paused", nodeNames, pauseScanNodePath);
+                logger.debug("Found child nodes {} at path {}. Scanning would be paused", nodeNames, cfg.getPauseScanNodePath());
             }
             return result;
         }
@@ -736,7 +670,9 @@
     public UpdateResult handleRemoval(final String resourceType,
             final String id,
             final String url) {
-        if ( !this.writeBack ) {
+        // get configuration
+        final InstallerConfig cfg = this.getConfiguration();
+        if ( cfg == null || !cfg.isWriteBack() ) {
             return null;
         }
         final int pos = url.indexOf(':');
@@ -749,7 +685,7 @@
             return null;
         }
         // 1. Is this a system configuration then don't delete
-        final String[] rootPaths = this.folderNameFilter.getRootPaths();
+        final String[] rootPaths = cfg.getFolderNameFilter().getRootPaths();
         final String systemConfigRootPath = rootPaths[rootPaths.length - 1];
         if ( path.startsWith(systemConfigRootPath) ) {
             logger.debug("Not removing system artifact from repository at {}", path);
@@ -760,7 +696,7 @@
         int lastSlash = path.lastIndexOf('/');
         while (!found && lastSlash > 1) {
             final String prefix = path.substring(0, lastSlash);
-            if ( this.folderNameFilter.getPriority(prefix) != -1 ) {
+            if ( cfg.getFolderNameFilter().getPriority(prefix) != -1 ) {
                 found = true;
             } else {
                 lastSlash = prefix.lastIndexOf('/');
@@ -813,10 +749,10 @@
         return this.handleUpdate(resourceType, id, url, is, null, attributes);
     }
 
-    private String getPathWithHighestPrio(final String oldPath) {
+    private String getPathWithHighestPrio(final InstallerConfig cfg, final String oldPath) {
         final String path;
         // check root path, we use the path with highest prio
-        final String rootPath = this.folderNameFilter.getRootPaths()[0] + '/';
+        final String rootPath = cfg.getFolderNameFilter().getRootPaths()[0] + '/';
         if ( !oldPath.startsWith(rootPath) ) {
             final int slashPos = oldPath.indexOf('/', 1);
             path = rootPath + oldPath.substring(slashPos + 1);
@@ -835,7 +771,9 @@
             final InputStream is,
             final Dictionary<String, Object> dict,
             final Map<String, Object> attributes) {
-        if ( !this.writeBack ) {
+        // get configuration
+        final InstallerConfig cfg = this.getConfiguration();
+        if ( cfg == null || !cfg.isWriteBack() ) {
             return null;
         }
 
@@ -858,7 +796,7 @@
                 // calculate the new node path
                 final String nodePath;
                 if ( url.startsWith(URL_SCHEME + ':') ) {
-                    nodePath = getPathWithHighestPrio(oldPath);
+                    nodePath = getPathWithHighestPrio(cfg, oldPath);
                 } else {
                     final int lastSlash = url.lastIndexOf('/');
                     final int lastPos = url.lastIndexOf('.');
@@ -868,7 +806,7 @@
                     } else {
                         name = url.substring(lastSlash + 1, lastPos);
                     }
-                    nodePath = getPathWithHighestPrio(this.newConfigPath + name + ".config");
+                    nodePath = getPathWithHighestPrio(cfg, cfg.getNewConfigPath() + name + ".config");
                 }
                 // ensure extension 'config'
                 if ( !nodePath.endsWith(".config") ) {
@@ -890,7 +828,7 @@
                 } else {
                     name = id;
                 }
-                path = this.newConfigPath + name + ".config";
+                path = cfg.getNewConfigPath() + name + ".config";
                 logger.debug("Add of {} at {}", resourceType, path);
             }
 
@@ -915,7 +853,7 @@
             // priority
             final int lastSlash = path.lastIndexOf('/');
             final String parentPath = path.substring(0, lastSlash);
-            result.setPriority(this.folderNameFilter.getPriority(parentPath));
+            result.setPriority(cfg.getFolderNameFilter().getPriority(parentPath));
             result.setResourceIsMoved(resourceIsMoved);
             return result;
         } catch (final RepositoryException re) {
diff --git a/src/test/java/org/apache/sling/installer/provider/jcr/impl/ScanningLoopTest.java b/src/test/java/org/apache/sling/installer/provider/jcr/impl/ScanningLoopTest.java
index 3211ab8..2cef10c 100644
--- a/src/test/java/org/apache/sling/installer/provider/jcr/impl/ScanningLoopTest.java
+++ b/src/test/java/org/apache/sling/installer/provider/jcr/impl/ScanningLoopTest.java
@@ -88,11 +88,11 @@
     }
 
     public void testDefaultScanPauseFalse() throws Exception{
-        assertFalse(installer.scanningIsPaused());
+        assertFalse(installer.scanningIsPaused(installer.getConfiguration()));
     }
 
     public void testPauseScan() throws Exception{
-        assertFalse(installer.scanningIsPaused());
+        assertFalse(installer.scanningIsPaused(installer.getConfiguration()));
 
         Node n = contentHelper.createFolder(JcrInstaller.PAUSE_SCAN_NODE_PATH);
         Node testNode = n.addNode("foo.example.pause");
@@ -100,7 +100,7 @@
 
         eventHelper.waitForEvents(TIMEOUT);
 
-        assertTrue(installer.scanningIsPaused());
+        assertTrue(installer.scanningIsPaused(installer.getConfiguration()));
         final long sf = installer.getCounters()[JcrInstaller.SCAN_FOLDERS_COUNTER];
         final long uc = installer.getCounters()[JcrInstaller.UPDATE_FOLDERS_LIST_COUNTER];