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:19:02 UTC
[sling-org-apache-sling-bundleresource-impl] 11/25: SLING-641 Make
the internal map of the cache be access-ordered (instead of insert-ordered)
and wrap the maps in synchronized maps to prevent multi-threading issues
plus JavaDoc and preparation for management support
This is an automated email from the ASF dual-hosted git repository.
rombert pushed a commit to annotated tag org.apache.sling.bundleresource.impl-2.0.4-incubator
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-bundleresource-impl.git
commit 854122cbdcc583436df1e9271a0b565e8d16623b
Author: Felix Meschberger <fm...@apache.org>
AuthorDate: Thu Sep 4 06:33:42 2008 +0000
SLING-641 Make the internal map of the cache be access-ordered (instead of
insert-ordered) and wrap the maps in synchronized maps to prevent
multi-threading issues plus JavaDoc and preparation for management support
git-svn-id: https://svn.apache.org/repos/asf/incubator/sling/trunk/extensions/bundleresource@691883 13f79535-47bb-0310-9956-ffa450edef68
---
.../bundleresource/impl/BundleResourceCache.java | 196 ++++++++++++++++++---
.../impl/BundleResourceProvider.java | 38 ++--
2 files changed, 201 insertions(+), 33 deletions(-)
diff --git a/src/main/java/org/apache/sling/bundleresource/impl/BundleResourceCache.java b/src/main/java/org/apache/sling/bundleresource/impl/BundleResourceCache.java
index 32d74fb..55b5aa5 100644
--- a/src/main/java/org/apache/sling/bundleresource/impl/BundleResourceCache.java
+++ b/src/main/java/org/apache/sling/bundleresource/impl/BundleResourceCache.java
@@ -26,59 +26,146 @@ import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
+import java.util.Map;
import java.util.Map.Entry;
import org.osgi.framework.Bundle;
-public class BundleResourceCache {
+/**
+ * The <code>BundleResourceCache</code> implements a simple caching for
+ * resources provided from a bundle. Each {@link BundleResourceProvider}
+ * instance uses an instance of this class to access the bundle resources (or
+ * bundle entries) through the cache.
+ * <p>
+ * The cache on the one hand caches single entries as URLs. The other part of
+ * the cache is for the child entries of a given bundle entry path. This caches
+ * lists of strings (entry path).
+ * <p>
+ * Currently the cache limits are fixed at {@value #CACHE_SIZE} for the entries
+ * cache and at {@value #LIST_CACHE_SIZE} for the child entries cache.
+ */
+class BundleResourceCache {
+
+ /**
+ * The maximum size of the single entry cache (value is 50).
+ */
+ private static final int CACHE_SIZE = 50;
+
+ /**
+ * The maximum size of the child entry cache (value is 20).
+ */
+ private static final int LIST_CACHE_SIZE = 20;
+ /**
+ * Sentinel for the single entry cache representing a missing entry to
+ * prevent looking for non-existing bundle entries multiple times (value is
+ * "file:///not_found").
+ */
private static final URL NOT_FOUND_URL;
+ /**
+ * Sentinel for the child entry cache representing a missing child list for
+ * a given path to prevent looking for non-existing bundle entries multiple
+ * times (value is an empty list).
+ */
private static final List<String> NOT_FOUND_CHILDREN = Collections.<String> emptyList();
- private final BundleResourceMap<String, URL> cache;
+ /**
+ * Single entry cache. This is a synchronized map with a size limit.
+ */
+ private final Map<String, URL> cache;
- private final BundleResourceMap<String, List<String>> listCache;
+ /**
+ * The child entry cache. This is a synchronized map with a size limit.
+ */
+ private final Map<String, List<String>> listCache;
+ /**
+ * The Bundle providing the resource entries.
+ */
private final Bundle bundle;
+ // static initializer setting the NOT_FOUND_URL. Because the
+ // constructor may throw an exception we use a static initializer
+ // which fails the class initialization in the unlikely case
+ // of the URL constructor failing.
static {
try {
- NOT_FOUND_URL = new URL("file:///not_found");
+ NOT_FOUND_URL = new URL("file:/not_found");
} catch (MalformedURLException mue) {
throw new ExceptionInInitializerError(mue);
}
}
+ /**
+ * Creates a new instance of this class providing access to the entries in
+ * the given <code>bundle</code>.
+ *
+ * @param bundle
+ */
BundleResourceCache(Bundle bundle) {
this.bundle = bundle;
- this.cache = new BundleResourceMap<String, URL>(50);
- this.listCache = new BundleResourceMap<String, List<String>>(20);
+
+ // create the limited maps wrapping in synchronized maps
+ this.cache = Collections.synchronizedMap(new BundleResourceMap<String, URL>(
+ CACHE_SIZE));
+ this.listCache = Collections.synchronizedMap(new BundleResourceMap<String, List<String>>(
+ LIST_CACHE_SIZE));
}
+ /**
+ * Returns the <code>Bundle</code> to which this instance provides access.
+ */
Bundle getBundle() {
return bundle;
}
-
+
+ /**
+ * Returns the entry in the underlying bundle at the given path. This path
+ * is assumed to be an absolute path. If relative it is resolved relative to
+ * the bundle root.
+ * <p>
+ * This method is backed by the <code>Bundle.getEntry(String)</code>
+ * method.
+ *
+ * @param path The path to the bundle entry to return
+ * @return The URL to access the bundle entry or <code>null</code> if the
+ * bundle does not contain the request entry.
+ */
URL getEntry(String path) {
URL url = cache.get(path);
if (url == null) {
url = bundle.getEntry(path);
-
+
if (url == null) {
url = NOT_FOUND_URL;
}
-
+
cache.put(path, url);
}
return (url == NOT_FOUND_URL) ? null : url;
}
+ /**
+ * Returns a list of bundle entry paths considered children of the given
+ * <code>parentPath</code>. This parent path is assumed to be an absolute
+ * path. If relative it is resolved relative to the bundle root.
+ * <p>
+ * This method is backed by the <code>Bundle.getEntryPaths(String)</code>
+ * method but returns an <code>Iterator<String></code> instead of an
+ * <code>Enumeration</code> of strings.
+ *
+ * @param parentPath The path to the parent entry whose child entries are to
+ * be returned.
+ * @return An <code>Iterator<String></code> providing the paths of
+ * entries considered direct children of the <code>parentPath</code>
+ * or <code>null</code> if the parent entry does not exist.
+ */
Iterator<String> getEntryPaths(String path) {
List<String> list = listCache.get(path);
if (list == null) {
-
+
@SuppressWarnings("unchecked")
Enumeration<String> entries = bundle.getEntryPaths(path);
if (entries != null && entries.hasMoreElements()) {
@@ -87,34 +174,101 @@ public class BundleResourceCache {
list.add(entries.nextElement());
}
}
-
+
if (list == null) {
list = NOT_FOUND_CHILDREN;
}
-
+
listCache.put(path, list);
}
-
+
return (list == NOT_FOUND_CHILDREN) ? null : list.iterator();
}
-
- private static class BundleResourceMap<K, V> extends LinkedHashMap<String, V> {
+
+ // ---------- Management API
+
+ /**
+ * Returns the current number of entries stored in the entry cache. This
+ * number includes "negative" entries, which are requested entries not found
+ * in the bundle.
+ */
+ int getEntryCacheSize() {
+ return cache.size();
+ }
+
+ /**
+ * Returns the maximum number of entries to be stored in the cache. This
+ * number is currently fixed at {@link #CACHE_SIZE}
+ */
+ int getEntryCacheMaxSize() {
+ return CACHE_SIZE;
+ }
+
+ /**
+ * Returns the current number of list entries stored in the list cache. This
+ * number includes "negative" list entries, which are requested list entries
+ * not found in the bundle.
+ */
+ int getListCacheSize() {
+ return listCache.size();
+ }
+
+ /**
+ * Returns the maximum number of list entries to be stored in the cache.
+ * This number is currently fixed at {@link #LIST_CACHE_SIZE}
+ */
+ int getListCacheMaxSize() {
+ return LIST_CACHE_SIZE;
+ }
+
+ // ---------- inner class
+
+ /**
+ * The <code>BundleResourceMap</code> class extends the
+ * <code>LinkedHashMap</code> class overwriting the
+ * {@link #removeEldestEntry(Entry)} method to implement the size limit,
+ * which is set in the constructor.
+ */
+ private static class BundleResourceMap<K, V> extends
+ LinkedHashMap<String, V> {
/**
- * The default size of a bundle resource cache.
+ * The default size of a bundle resource cache (value is 20).
+ */
+ private static final int DEFAULT_LIMIT = 20;
+
+ /**
+ * The limit configured for this map.
*/
- public static final int DEFAULT_LIMIT = 100;
-
private final int limit;
-
+
+ /**
+ * Creates a new instance of this size limited map.
+ *
+ * @param limit The maximum number of entries in this map. If this value
+ * is less than or equal to zero, the default size of
+ * {@link #DEFAULT_LIMIT} is used.
+ */
BundleResourceMap(int limit) {
+ // deliberately chosen initial size and load factor, but
+ // we need the access-order to implement the LRU mechanism
+ super(8, 0.75f, true);
+
+ // normalize size to a possitive number
if (limit <= 0) {
limit = DEFAULT_LIMIT;
}
-
+
this.limit = limit;
}
-
+
+ /**
+ * Returns the maximum number of entries to be stored in this map.
+ */
+ int getLimit() {
+ return limit;
+ }
+
/**
* Returns <code>true</code> if the current number of elements in the
* map exceeds the configured limit.
diff --git a/src/main/java/org/apache/sling/bundleresource/impl/BundleResourceProvider.java b/src/main/java/org/apache/sling/bundleresource/impl/BundleResourceProvider.java
index c9e71ff..0c2230c 100644
--- a/src/main/java/org/apache/sling/bundleresource/impl/BundleResourceProvider.java
+++ b/src/main/java/org/apache/sling/bundleresource/impl/BundleResourceProvider.java
@@ -48,7 +48,7 @@ public class BundleResourceProvider implements ResourceProvider {
private final MappedPath[] roots;
private ServiceRegistration serviceRegistration;
-
+
/**
* Creates Bundle resource provider accessing entries in the given Bundle an
* supporting resources below root paths given by the rootList which is a
@@ -70,38 +70,51 @@ public class BundleResourceProvider implements ResourceProvider {
void registerService(BundleContext context) {
Dictionary<String, Object> props = new Hashtable<String, Object>();
- props.put(Constants.SERVICE_DESCRIPTION, "Provider of Bundle based Resources");
+ props.put(Constants.SERVICE_DESCRIPTION,
+ "Provider of Bundle based Resources");
props.put(Constants.SERVICE_VENDOR, "The Apache Software Foundation");
props.put(ROOTS, getRoots());
-
+
serviceRegistration = context.registerService(SERVICE_NAME, this, props);
}
-
+
void unregisterService() {
if (serviceRegistration != null) {
serviceRegistration.unregister();
}
}
+
+ //---------- Web Console plugin support
+
+ BundleResourceCache getBundleResourceCache() {
+ return bundle;
+ }
+
+ MappedPath[] getMappedPaths() {
+ return roots;
+ }
+
+ //---------- internal
/** Returns the root paths */
private String[] getRoots() {
String[] rootPaths = new String[roots.length];
- for (int i=0; i < roots.length; i++) {
+ for (int i = 0; i < roots.length; i++) {
rootPaths[i] = roots[i].getResourceRoot();
}
return rootPaths;
}
-
+
private MappedPath getMappedPath(String resourcePath) {
- for (MappedPath mappedPath: roots) {
+ for (MappedPath mappedPath : roots) {
if (mappedPath.isChild(resourcePath)) {
return mappedPath;
}
}
-
+
return null;
}
-
+
public Resource getResource(ResourceResolver resourceResolver,
HttpServletRequest request, String path) {
return getResource(resourceResolver, path);
@@ -115,9 +128,10 @@ public class BundleResourceProvider implements ResourceProvider {
public Resource getResource(ResourceResolver resourceResolver, String path) {
MappedPath mappedPath = getMappedPath(path);
if (mappedPath != null) {
- return BundleResource.getResource(resourceResolver, bundle, mappedPath, path);
+ return BundleResource.getResource(resourceResolver, bundle,
+ mappedPath, path);
}
-
+
return null;
}
@@ -140,6 +154,6 @@ public class BundleResourceProvider implements ResourceProvider {
// the parent resource cannot have children in this provider,
// though this is basically not expected, we still have to
// be prepared for such a situation
- return Collections.<Resource>emptyList().iterator();
+ return Collections.<Resource> emptyList().iterator();
}
}
--
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.