SLING-8495 - Make FSClassLoader its cache location root directory configurable
diff --git a/src/main/java/org/apache/sling/commons/fsclassloader/impl/CacheLocationUtils.java b/src/main/java/org/apache/sling/commons/fsclassloader/impl/CacheLocationUtils.java
new file mode 100644
index 0000000..1318522
--- /dev/null
+++ b/src/main/java/org/apache/sling/commons/fsclassloader/impl/CacheLocationUtils.java
@@ -0,0 +1,42 @@
+/*
+ * 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.commons.fsclassloader.impl;
+
+import java.io.File;
+
+import org.apache.commons.lang3.StringUtils;
+import org.osgi.framework.BundleContext;
+
+/**
+ * Utils to acquire file system cache root directory based on configuration
+ */
+public class CacheLocationUtils {
+
+	private CacheLocationUtils() {
+    }
+    
+    public static File getRootDir(final BundleContext context, final FSClassLoaderComponentConfig config) {
+        String cacheLocation = config.fsclassloader_fileSystemCompiledScriptsCacheLocation();
+        if (StringUtils.isBlank(cacheLocation))
+            return new File(context.getDataFile(""), "classes");
+        else
+            return new File(cacheLocation);
+    }
+
+}
diff --git a/src/main/java/org/apache/sling/commons/fsclassloader/impl/FSClassLoaderComponentConfig.java b/src/main/java/org/apache/sling/commons/fsclassloader/impl/FSClassLoaderComponentConfig.java
new file mode 100644
index 0000000..dfee0a1
--- /dev/null
+++ b/src/main/java/org/apache/sling/commons/fsclassloader/impl/FSClassLoaderComponentConfig.java
@@ -0,0 +1,43 @@
+/*
+ * 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.commons.fsclassloader.impl;
+
+import org.osgi.service.metatype.annotations.AttributeDefinition;
+import org.osgi.service.metatype.annotations.ObjectClassDefinition;
+
+/**
+ * {@code FSClassLoaderComponentConfig} Describes the declarative services description for the FileSystem Class Loader component.
+ */
+@ObjectClassDefinition(
+        name = "FileSystem Class Loader",
+        description = "Uses the file system to store and read class files from."
+)
+@interface FSClassLoaderComponentConfig {
+ 
+    /**
+     * Location of the filesystem compiled scripts cache
+     */
+	@AttributeDefinition(
+            name = "Location of the filesystem compiled scripts cache",
+            description = "Controls where the filesystem compiled scripts cache is stored. When the value "
+                    + "is set to null (default) the cache is stored on the bundle persistent "
+                    + "storage area."
+            )
+    String fsclassloader_fileSystemCompiledScriptsCacheLocation();
+}
diff --git a/src/main/java/org/apache/sling/commons/fsclassloader/impl/FSClassLoaderMBeanImpl.java b/src/main/java/org/apache/sling/commons/fsclassloader/impl/FSClassLoaderMBeanImpl.java
index d9afe3c..2db387d 100644
--- a/src/main/java/org/apache/sling/commons/fsclassloader/impl/FSClassLoaderMBeanImpl.java
+++ b/src/main/java/org/apache/sling/commons/fsclassloader/impl/FSClassLoaderMBeanImpl.java
@@ -30,7 +30,6 @@
 import java.util.Map;
 
 import org.apache.sling.commons.fsclassloader.FSClassLoaderMBean;
-import org.osgi.framework.BundleContext;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -38,13 +37,13 @@
  * Implementation of the FSClassLoaderMBean interface
  */
 public class FSClassLoaderMBeanImpl implements FSClassLoaderMBean {
-	private final BundleContext context;
+	private final File root;
 	private final FSClassLoaderProvider fsClassLoaderProvider;
 	private static final Logger log = LoggerFactory.getLogger(FSClassLoaderMBeanImpl.class);
 
-	public FSClassLoaderMBeanImpl(final FSClassLoaderProvider fsClassLoaderProvider, final BundleContext context) {
+	public FSClassLoaderMBeanImpl(final FSClassLoaderProvider fsClassLoaderProvider, final File root) {
 		this.fsClassLoaderProvider = fsClassLoaderProvider;
-		this.context = context;
+		this.root = root;
 	}
 
 	/*
@@ -76,7 +75,6 @@
 		Collection<String> scripts = new HashSet<String>();
 		try {
 			Map<String, ScriptFiles> s = new LinkedHashMap<String, ScriptFiles>();
-			File root = new File(context.getDataFile(""), "classes");
 			if (root != null) {
 				FSClassLoaderWebConsole.readFiles(root, root, s);
 			}
@@ -106,7 +104,7 @@
 	 */
 	@Override
 	public String getFSClassLoaderRoot() {
-		return new File(context.getDataFile(""), "classes").getAbsolutePath();
+		return root.getAbsolutePath();
 	}
 
 }
diff --git a/src/main/java/org/apache/sling/commons/fsclassloader/impl/FSClassLoaderProvider.java b/src/main/java/org/apache/sling/commons/fsclassloader/impl/FSClassLoaderProvider.java
index 5151ee2..83e2270 100644
--- a/src/main/java/org/apache/sling/commons/fsclassloader/impl/FSClassLoaderProvider.java
+++ b/src/main/java/org/apache/sling/commons/fsclassloader/impl/FSClassLoaderProvider.java
@@ -53,6 +53,7 @@
 import org.osgi.service.component.annotations.Deactivate;
 import org.osgi.service.component.annotations.Reference;
 import org.osgi.service.component.annotations.ServiceScope;
+import org.osgi.service.metatype.annotations.Designate;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -62,11 +63,15 @@
  *
  */
 @Component(service = ClassLoaderWriter.class, scope = ServiceScope.BUNDLE,
+    configurationPid = FSClassLoaderProvider.SHARED_CONFIGURATION_PID,
     property = {
             Constants.SERVICE_RANKING + ":Integer=100"
     })
+@Designate(ocd = FSClassLoaderComponentConfig.class)
 public class FSClassLoaderProvider implements ClassLoaderWriter {
 
+	public static final String SHARED_CONFIGURATION_PID = "org.apache.sling.commons.fsclassloader.impl.FSClassLoaderProvider";
+
 	private static final String LISTENER_FILTER = "(" + Constants.OBJECTCLASS + "="
 			+ ClassLoaderWriterListener.class.getName() + ")";
 
@@ -102,10 +107,10 @@
 	 * @throws MalformedObjectNameException
 	 */
 	@Activate
-	protected void activate(final ComponentContext componentContext)
+	protected void activate(final ComponentContext componentContext, final FSClassLoaderComponentConfig config)
 			throws MalformedURLException, InvalidSyntaxException, MalformedObjectNameException {
 		// get the file root
-		this.root = new File(componentContext.getBundleContext().getDataFile(""), "classes");
+		this.root = CacheLocationUtils.getRootDir(componentContext.getBundleContext(), config);
 		this.root.mkdirs();
 		this.rootURL = this.root.toURI().toURL();
 		this.callerBundle = componentContext.getUsingBundle();
@@ -147,7 +152,7 @@
 		mbeanProps.put(Constants.SERVICE_VENDOR, "The Apache Software Foundation");
 		mbeanProps.put("jmx.objectname", new ObjectName("org.apache.sling.classloader", jmxProps));
 		mbeanRegistration = componentContext.getBundleContext().registerService(FSClassLoaderMBean.class.getName(),
-				new FSClassLoaderMBeanImpl(this, componentContext.getBundleContext()), mbeanProps);
+				new FSClassLoaderMBeanImpl(this, this.root), mbeanProps);
 	}
 
 	/**
diff --git a/src/main/java/org/apache/sling/commons/fsclassloader/impl/FSClassLoaderWebConsole.java b/src/main/java/org/apache/sling/commons/fsclassloader/impl/FSClassLoaderWebConsole.java
index 6f56b21..ba34035 100644
--- a/src/main/java/org/apache/sling/commons/fsclassloader/impl/FSClassLoaderWebConsole.java
+++ b/src/main/java/org/apache/sling/commons/fsclassloader/impl/FSClassLoaderWebConsole.java
@@ -50,6 +50,7 @@
  * and Class files.
  */
 @Component(service = Servlet.class,
+    configurationPid = FSClassLoaderProvider.SHARED_CONFIGURATION_PID,
     property = {
          "service.description=Web Console for the FileSystem Class Loader",
 		 "service.vendor=The Apache Software Foundation",
@@ -93,9 +94,9 @@
 	 * @throws MalformedURLException
 	 */
 	@Activate
-	protected void activate(final ComponentContext componentContext) throws MalformedURLException {
+	protected void activate(final ComponentContext componentContext, final FSClassLoaderComponentConfig config) throws MalformedURLException {
 		// get the file root
-		root = new File(componentContext.getBundleContext().getDataFile(""), "classes");
+		this.root = CacheLocationUtils.getRootDir(componentContext.getBundleContext(), config);
 	}
 
 	/*