You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by fm...@apache.org on 2014/10/23 09:50:37 UTC
svn commit: r1633762 - in /sling/whiteboard/fmeschbe/fsr: ./
src/main/java/org/apache/sling/fsprovider/internal/
src/main/resources/OSGI-INF/
Author: fmeschbe
Date: Thu Oct 23 07:50:37 2014
New Revision: 1633762
URL: http://svn.apache.org/r1633762
Log:
Fancy Filesystem ResourceProvider Prototype
Added:
sling/whiteboard/fmeschbe/fsr/
- copied from r1562756, sling/trunk/bundles/extensions/fsresource/
Removed:
sling/whiteboard/fmeschbe/fsr/src/main/java/org/apache/sling/fsprovider/internal/FileMonitor.java
sling/whiteboard/fmeschbe/fsr/src/main/resources/OSGI-INF/
Modified:
sling/whiteboard/fmeschbe/fsr/pom.xml
sling/whiteboard/fmeschbe/fsr/src/main/java/org/apache/sling/fsprovider/internal/FsResource.java
sling/whiteboard/fmeschbe/fsr/src/main/java/org/apache/sling/fsprovider/internal/FsResourceProvider.java
Modified: sling/whiteboard/fmeschbe/fsr/pom.xml
URL: http://svn.apache.org/viewvc/sling/whiteboard/fmeschbe/fsr/pom.xml?rev=1633762&r1=1562756&r2=1633762&view=diff
==============================================================================
--- sling/whiteboard/fmeschbe/fsr/pom.xml (original)
+++ sling/whiteboard/fmeschbe/fsr/pom.xml Thu Oct 23 07:50:37 2014
@@ -23,24 +23,26 @@
<groupId>org.apache.sling</groupId>
<artifactId>sling</artifactId>
<version>18</version>
- <relativePath>../../../parent/pom.xml</relativePath>
+ <relativePath></relativePath>
</parent>
- <artifactId>org.apache.sling.fsresource</artifactId>
+ <artifactId>org.apache.sling.fsr</artifactId>
<packaging>bundle</packaging>
- <version>1.1.3-SNAPSHOT</version>
+ <version>0.0.1-SNAPSHOT</version>
- <name>Apache Sling Filesystem Resource Provider</name>
+ <name>Apache Sling Filesystem Resource Provider++</name>
<description>
Provides a ResourceProvider implementation supporting filesystem
- based resources.
+ based resources with support for metadata
</description>
+ <!--
<scm>
- <connection>scm:svn:http://svn.apache.org/repos/asf/sling/trunk/bundles/extensions/fsresource</connection>
- <developerConnection>scm:svn:https://svn.apache.org/repos/asf/sling/trunk/bundles/extensions/fsresource</developerConnection>
- <url>http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/fsresource</url>
+ <connection>scm:svn:http://svn.apache.org/repos/asf/sling/</connection>
+ <developerConnection>scm:svn:https://svn.apache.org/repos/asf/sling/trunk/ --- TO FIX --- /fsr</developerConnection>
+ <url>http://svn.apache.org/viewvc/sling/trunk/ --- TO FIX --- /fsr</url>
</scm>
+ -->
<build>
<plugins>
@@ -70,9 +72,13 @@
<extensions>true</extensions>
<configuration>
<instructions>
- <Private-Package>
- org.apache.sling.fsprovider.internal
- </Private-Package>
+ <Import-Package>
+ !org.apache.tools.*,
+ *
+ </Import-Package>
+ <Embed-Dependency>
+ je
+ </Embed-Dependency>
</instructions>
</configuration>
</plugin>
@@ -83,10 +89,20 @@
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
</dependency>
+<dependency>
+ <groupId>com.sleepycat</groupId>
+ <artifactId>je</artifactId>
+ <version>5.0.73</version>
+</dependency>
<dependency>
<groupId>org.apache.sling</groupId>
<artifactId>org.apache.sling.api</artifactId>
- <version>2.3.0</version>
+ <version>2.8.0</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.sling</groupId>
+ <artifactId>org.apache.sling.serviceusermapper</artifactId>
+ <version>1.0.0</version>
</dependency>
<dependency>
<groupId>org.apache.sling</groupId>
@@ -94,6 +110,16 @@
<version>2.0.4</version>
</dependency>
<dependency>
+ <groupId>org.apache.sling</groupId>
+ <artifactId>org.apache.sling.commons.osgi</artifactId>
+ <version>2.2.0</version>
+ </dependency>
+ <dependency>
+ <groupId>commons-io</groupId>
+ <artifactId>commons-io</artifactId>
+ <version>1.4</version>
+ </dependency>
+ <dependency>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.core</artifactId>
</dependency>
Modified: sling/whiteboard/fmeschbe/fsr/src/main/java/org/apache/sling/fsprovider/internal/FsResource.java
URL: http://svn.apache.org/viewvc/sling/whiteboard/fmeschbe/fsr/src/main/java/org/apache/sling/fsprovider/internal/FsResource.java?rev=1633762&r1=1562756&r2=1633762&view=diff
==============================================================================
--- sling/whiteboard/fmeschbe/fsr/src/main/java/org/apache/sling/fsprovider/internal/FsResource.java (original)
+++ sling/whiteboard/fmeschbe/fsr/src/main/java/org/apache/sling/fsprovider/internal/FsResource.java Thu Oct 23 07:50:37 2014
@@ -22,20 +22,17 @@ import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
-import java.net.MalformedURLException;
-import java.net.URL;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;
-
import org.apache.sling.adapter.annotations.Adaptable;
import org.apache.sling.adapter.annotations.Adapter;
import org.apache.sling.api.resource.AbstractResource;
+import org.apache.sling.api.resource.ModifiableValueMap;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceMetadata;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ValueMap;
-import org.apache.sling.api.wrappers.ValueMapDecorator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -44,7 +41,7 @@ import org.slf4j.LoggerFactory;
* a Sling Resource.
*/
@Adaptable(adaptableClass=Resource.class, adapters={
- @Adapter({File.class, URL.class}),
+ @Adapter({ValueMap.class, ModifiableValueMap.class, Map.class}),
@Adapter(condition="If the resource is an FsResource and is a readable file.", value=InputStream.class)
})
public class FsResource extends AbstractResource {
@@ -67,11 +64,17 @@ public class FsResource extends Abstract
// the owning resource resolver
private final ResourceResolver resolver;
+ // the owning ResourceProvider
+ private final FsResourceProvider provider;
+
// the path of this resource in the resource tree
private final String resourcePath;
// the file wrapped by this instance
- private final File file;
+ private final File metaFile;
+
+ // the file wrapped by this instance
+ private final File dataFile;
// the resource type, assigned on demand
private String resourceType;
@@ -79,17 +82,34 @@ public class FsResource extends Abstract
// the resource metadata, assigned on demand
private ResourceMetadata metaData;
+ private FsModifiableValueMap properties;
+
+ private boolean modified = false;
+
+ private boolean removed = false;
+
/**
* Creates an instance of this Filesystem resource.
*
* @param resolver The owning resource resolver
+ * @param provider The FsResourceProvider creating this instance
* @param resourcePath The resource path in the resource tree
- * @param file The wrapped file
+ * @param metaFile The file providing the metadata (ValueMap properties) for
+ * this resource
+ * @param dataFile The file providing the contents of this resource or
+ * {@code null} if this resource only has properties
*/
- FsResource(ResourceResolver resolver, String resourcePath, File file) {
+ FsResource(ResourceResolver resolver, FsResourceProvider provider, String resourcePath, File metaFile, File dataFile, Map<String, Object> properties) {
this.resolver = resolver;
+ this.provider = provider;
this.resourcePath = resourcePath;
- this.file = file;
+ this.metaFile = metaFile;
+ this.dataFile = dataFile;
+
+ // initial properties (overwrite), causes this resource to be modified
+ if (properties != null && !properties.isEmpty()) {
+ this.getProperties().putAll(properties);
+ }
}
/**
@@ -107,11 +127,14 @@ public class FsResource extends Abstract
public ResourceMetadata getResourceMetadata() {
if (metaData == null) {
metaData = new ResourceMetadata();
- metaData.setContentLength(file.length());
- metaData.setModificationTime(file.lastModified());
- metaData.setResolutionPath(resourcePath);
- if ( this.file.isDirectory() ) {
- metaData.put(ResourceMetadata.INTERNAL_CONTINUE_RESOLVING, Boolean.TRUE);
+
+ if (this.dataFile != null) {
+ metaData.setContentLength(dataFile.length());
+ metaData.setModificationTime(dataFile.lastModified());
+ metaData.setResolutionPath(resourcePath);
+ if (this.dataFile.isDirectory()) {
+ metaData.put(ResourceMetadata.INTERNAL_CONTINUE_RESOLVING, Boolean.TRUE);
+ }
}
}
return metaData;
@@ -139,9 +162,8 @@ public class FsResource extends Abstract
*/
public String getResourceType() {
if (resourceType == null) {
- resourceType = file.isFile()
- ? RESOURCE_TYPE_FILE
- : RESOURCE_TYPE_FOLDER;
+ // TODO: PropertiesUtil
+ resourceType = (String) this.getProperties().get("sling:resourceType");
}
return resourceType;
@@ -155,59 +177,143 @@ public class FsResource extends Abstract
@Override
@SuppressWarnings("unchecked")
public <AdapterType> AdapterType adaptTo(Class<AdapterType> type) {
- if (type == File.class) {
+ if (type == InputStream.class) {
- return (AdapterType) file;
-
- } else if (type == InputStream.class) {
-
- if (!file.isDirectory() && file.canRead()) {
+ if (this.dataFile != null && !this.dataFile.isDirectory() && this.dataFile.canRead()) {
try {
- return (AdapterType) new FileInputStream(file);
+ return (AdapterType) new FileInputStream(this.dataFile);
} catch (IOException ioe) {
getLog().info(
- "adaptTo: Cannot open a stream on the file " + file,
+ "adaptTo: Cannot open a stream on the file " + this.dataFile,
ioe);
}
} else {
- getLog().debug("adaptTo: File {} is not a readable file", file);
+ getLog().debug("adaptTo: File {} is not a readable file", this.dataFile);
}
- } else if (type == URL.class) {
+ } else if (type == ValueMap.class || type == ModifiableValueMap.class || type == Map.class) {
+
+ return (AdapterType) this.getProperties();
+
+ }
+
+ return super.adaptTo(type);
+ }
+
+ // ---------- Object
+
+ @Override
+ public int hashCode() {
+ return (this.modified ? 17 : 0) + (this.removed ? 33 : 0) + this.getPath().hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ } else if (!(obj instanceof FsResource)) {
+ return false;
+ }
+
+ FsResource other = (FsResource) obj;
+ return this.getPath().equals(other.getPath()) && this.modified == other.modified
+ && this.removed == other.removed;
+ }
+ @Override
+ public String toString() {
+ return getClass().getSimpleName() + getResourceMetadata();
+ }
+
+ // modifiable support
+
+ private ModifiableValueMap getProperties() {
+ if (this.properties == null || this.properties.isEmpty()) {
+
+ Map<String, Object> props = null;
try {
- return (AdapterType) file.toURI().toURL();
- } catch (MalformedURLException mue) {
- getLog().info(
- "adaptTo: Cannot convert the file path " + file
- + " to an URL", mue);
+ props = FsUtil.readProperties(this.metaFile);
+ } catch (IOException e) {
+ // TODO: handle !!
}
- } else if (type == ValueMap.class) {
-
- // this resource simulates nt:file/nt:folder behavior by returning it as resource type
- // we should simulate the corresponding JCR properties in a value map as well
- if (file.exists() && file.canRead()) {
- Map<String,Object> props = new HashMap<String, Object>();
- props.put("jcr:primaryType", getResourceType());
+ if (props == null) {
+ props = new HashMap<String, Object>();
props.put("jcr:createdBy", "system");
Calendar lastModifed = Calendar.getInstance();
- lastModifed.setTimeInMillis(file.lastModified());
+ if (this.dataFile != null) {
+ lastModifed.setTimeInMillis(this.dataFile.lastModified());
+ }
props.put("jcr:created", lastModifed);
- return (AdapterType) new ValueMapDecorator(props);
}
+ // ensure primary and resource type !
+ if (!props.containsKey("jcr:primaryType")) {
+ props.put("jcr:primaryType", (this.dataFile == null) ? "nt:unstructured" : (this.dataFile.isFile()
+ ? RESOURCE_TYPE_FILE
+ : RESOURCE_TYPE_FOLDER));
+ }
+ if (!props.containsKey("sling:resourceType")) {
+ props.put("sling:resourceType", props.get("jcr:primaryType"));
+ }
+
+ this.properties = new FsModifiableValueMap(this, props);
}
+ return this.properties;
+ }
- return super.adaptTo(type);
+ void commit() throws IOException {
+ if (this.removed) {
+ this.metaFile.delete();
+ if (this.dataFile != null) {
+ // TODO: Check whether this is an empty directory first !
+ this.dataFile.delete();
+ }
+ } else if (this.modified && this.properties != null) {
+ FsUtil.writeProperties(this.metaFile, this.properties);
+ }
}
+ void revert() {
+ this.modified = false;
+ this.removed = false;
+ if (this.properties != null) {
+ this.properties.clear();
+ this.getProperties();
+ }
+ }
+
+
// ---------- internal
+ void unlockResourceMetadata() {
+ if (this.metaData != null) {
+ ResourceMetadata newMetaData = new ResourceMetadata();
+ newMetaData.putAll(this.metaData);
+ this.metaData = newMetaData;
+ }
+ }
+
+ File getDataFile() {
+ return this.dataFile;
+ }
+
+ void remove() {
+ this.removed = true;
+ this.provider.modified(this);
+ }
+
+ void modified() {
+ if (!this.modified && !this.removed) {
+ this.modified = true;
+ this.provider.modified(this);
+ }
+ }
+
private Logger getLog() {
if (log == null) {
log = LoggerFactory.getLogger(getClass());
Modified: sling/whiteboard/fmeschbe/fsr/src/main/java/org/apache/sling/fsprovider/internal/FsResourceProvider.java
URL: http://svn.apache.org/viewvc/sling/whiteboard/fmeschbe/fsr/src/main/java/org/apache/sling/fsprovider/internal/FsResourceProvider.java?rev=1633762&r1=1562756&r2=1633762&view=diff
==============================================================================
--- sling/whiteboard/fmeschbe/fsr/src/main/java/org/apache/sling/fsprovider/internal/FsResourceProvider.java (original)
+++ sling/whiteboard/fmeschbe/fsr/src/main/java/org/apache/sling/fsprovider/internal/FsResourceProvider.java Thu Oct 23 07:50:37 2014
@@ -19,26 +19,29 @@
package org.apache.sling.fsprovider.internal;
import java.io.File;
+import java.io.FileFilter;
+import java.io.IOException;
+import java.util.Collection;
import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.NoSuchElementException;
+import java.util.Set;
import javax.servlet.http.HttpServletRequest;
-import org.apache.felix.scr.annotations.Component;
-import org.apache.felix.scr.annotations.ConfigurationPolicy;
-import org.apache.felix.scr.annotations.Properties;
-import org.apache.felix.scr.annotations.Property;
-import org.apache.felix.scr.annotations.Reference;
-import org.apache.felix.scr.annotations.ReferenceCardinality;
-import org.apache.felix.scr.annotations.ReferencePolicy;
-import org.apache.felix.scr.annotations.Service;
+import org.apache.sling.adapter.SlingAdaptable;
+import org.apache.sling.api.resource.AttributableResourceProvider;
+import org.apache.sling.api.resource.ModifyingResourceProvider;
+import org.apache.sling.api.resource.PersistenceException;
+import org.apache.sling.api.resource.RefreshableResourceProvider;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceProvider;
import org.apache.sling.api.resource.ResourceResolver;
-import org.osgi.framework.BundleContext;
-import org.osgi.service.event.EventAdmin;
+import org.apache.sling.api.resource.ResourceResolverFactory;
+import org.apache.sling.fsprovider.User;
/**
* The <code>FsResourceProvider</code> is a resource provider which maps
@@ -51,53 +54,20 @@ import org.osgi.service.event.EventAdmin
* and the file system path from where files and folders are mapped into the
* resource ({@link #PROP_PROVIDER_FILE}).
*/
-@Component(
- name="org.apache.sling.fsprovider.internal.FsResourceProvider",
- label="%resource.resolver.name",
- description="%resource.resolver.description",
- configurationFactory=true,
- policy=ConfigurationPolicy.REQUIRE,
- metatype=true
- )
-@Service(ResourceProvider.class)
-@Properties({
- @Property(name="service.description", value="Sling Filesystem Resource Provider"),
- @Property(name="service.vendor", value="The Apache Software Foundation"),
- @Property(name=ResourceProvider.ROOTS)
-})
-public class FsResourceProvider implements ResourceProvider {
+public class FsResourceProvider extends SlingAdaptable implements ResourceProvider, ModifyingResourceProvider, AttributableResourceProvider, RefreshableResourceProvider {
- /**
- * The name of the configuration property providing file system path of
- * files and folders mapped into the resource tree (value is
- * "provider.file").
- */
- @Property
- public static final String PROP_PROVIDER_FILE = "provider.file";
-
- /**
- * The name of the configuration property providing the check interval
- * for file changes (value is "provider.checkinterval").
- */
- @Property(longValue=FsResourceProvider.DEFAULT_CHECKINTERVAL)
- public static final String PROP_PROVIDER_CHECKINTERVAL = "provider.checkinterval";
+ private final FsrResourceProviderFactory factory;
- public static final long DEFAULT_CHECKINTERVAL = 1000;
+ private final User user;
- // The location in the resource tree where the resources are mapped
- private String providerRoot;
+ private final Set<FsResource> modifiedResources = new HashSet<FsResource>();
- // providerRoot + "/" to be used for prefix matching of paths
- private String providerRootPrefix;
+ private final Map<String, FsResource> cache = new HashMap<String, FsResource>();
- // The "root" file or folder in the file system
- private File providerFile;
-
- /** The monitor to detect file changes. */
- private FileMonitor monitor;
-
- @Reference(cardinality=ReferenceCardinality.OPTIONAL_UNARY, policy=ReferencePolicy.DYNAMIC)
- private EventAdmin eventAdmin;
+ FsResourceProvider(final FsrResourceProviderFactory factory, final User user) {
+ this.factory = factory;
+ this.user = user;
+ }
/**
* Same as {@link #getResource(ResourceResolver, String)}, i.e. the
@@ -105,8 +75,7 @@ public class FsResourceProvider implemen
*
* @see #getResource(ResourceResolver, String)
*/
- public Resource getResource(ResourceResolver resourceResolver,
- HttpServletRequest request, String path) {
+ public Resource getResource(ResourceResolver resourceResolver, HttpServletRequest request, String path) {
return getResource(resourceResolver, path);
}
@@ -120,34 +89,37 @@ public class FsResourceProvider implemen
* method returns <code>null</code>.
*/
public Resource getResource(ResourceResolver resourceResolver, String path) {
- return getResource(resourceResolver, path, getFile(path));
+ return getResource(resourceResolver, path, this.factory.getFile(path));
}
/**
* Returns an iterator of resources.
*/
public Iterator<Resource> listChildren(Resource parent) {
- File parentFile = parent.adaptTo(File.class);
- // not a FsResource, try to create one from the resource
- if (parentFile == null) {
+ File parentDataFile;
+ if (parent instanceof FsResource) {
+
+ parentDataFile = ((FsResource) parent).getDataFile();
+
+ } else {
+
// if the parent path is at or below the provider root, get
// the respective file
- parentFile = getFile(parent.getPath());
+ File parentMetaFile = this.factory.getFile(parent.getPath());
// if the parent path is actually the parent of the provider
// root, return a single element iterator just containing the
// provider file, unless the provider file is a directory and
// a repository item with the same path actually exists
- if (parentFile == null) {
+ if (parentMetaFile == null) {
String parentPath = parent.getPath().concat("/");
- if (providerRoot.startsWith(parentPath)) {
- String relPath = providerRoot.substring(parentPath.length());
+ if (this.factory.getProviderRoot().startsWith(parentPath)) {
+ String relPath = this.factory.getProviderRoot().substring(parentPath.length());
if (relPath.indexOf('/') < 0) {
- Resource res = getResource(
- parent.getResourceResolver(), providerRoot,
- providerFile);
+ Resource res = getResource(parent.getResourceResolver(), this.factory.getProviderRoot(),
+ this.factory.getRootFile());
if (res != null) {
return Collections.singletonList(res).iterator();
}
@@ -157,9 +129,15 @@ public class FsResourceProvider implemen
// no children here
return null;
}
+
+ parentDataFile = getDataFile(parentMetaFile);
}
- final File[] children = parentFile.listFiles();
+ final File[] children = parentDataFile.listFiles(new FileFilter() {
+ public boolean accept(File file) {
+ return file.getName().endsWith(".meta");
+ }
+ });
if (children != null && children.length > 0) {
final ResourceResolver resolver = parent.getResourceResolver();
@@ -190,7 +168,8 @@ public class FsResourceProvider implemen
private Resource seek() {
while (index < children.length) {
File file = children[index++];
- String path = parentPath + "/" + file.getName();
+ String path = parentPath + "/"
+ + file.getName().substring(0, file.getName().length() - ".meta".length());
Resource result = getResource(resolver, path, file);
if (result != null) {
return result;
@@ -207,115 +186,97 @@ public class FsResourceProvider implemen
return null;
}
- // ---------- SCR Integration
+ // ---------- ModifyingResourceProvider
- protected void activate(BundleContext bundleContext, Map<?, ?> props) {
- String providerRoot = (String) props.get(ROOTS);
- if (providerRoot == null || providerRoot.length() == 0) {
- throw new IllegalArgumentException(ROOTS + " property must be set");
+ public Resource create(final ResourceResolver resolver, final String path, final Map<String, Object> properties) {
+ File metaFile = this.factory.getFile(path);
+ // manage some properties
+ Map<String, Object> props = new HashMap<String, Object>();
+ if (properties != null) {
+ props.putAll(properties);
}
+ props.put("jcr:created", System.currentTimeMillis());
+ props.put("jcr:createdBy", resolver.getUserID());
- String providerFileName = (String) props.get(PROP_PROVIDER_FILE);
- if (providerFileName == null || providerFileName.length() == 0) {
- throw new IllegalArgumentException(PROP_PROVIDER_FILE
- + " property must be set");
- }
+ return createResource(resolver, path, metaFile, props);
+ }
- this.providerRoot = providerRoot;
- this.providerRootPrefix = providerRoot.concat("/");
- this.providerFile = getProviderFile(providerFileName, bundleContext);
- // start background monitor if check interval is higher than 100
- long checkInterval = DEFAULT_CHECKINTERVAL;
- final Object interval = props.get(PROP_PROVIDER_CHECKINTERVAL);
- if ( interval != null && interval instanceof Long ) {
- checkInterval = (Long)interval;
- }
- if ( checkInterval > 100 ) {
- this.monitor = new FileMonitor(this, checkInterval);
+ public void delete(ResourceResolver resolver, String path) {
+ Resource res = this.getResource(resolver, path);
+ if (res instanceof FsResource) {
+ ((FsResource) res).remove();
}
}
- protected void deactivate() {
- if ( this.monitor != null ) {
- this.monitor.stop();
- this.monitor = null;
+ public void revert(ResourceResolver resolver) {
+ for (FsResource fsResource : modifiedResources) {
+ fsResource.revert();
}
- this.providerRoot = null;
- this.providerRootPrefix = null;
- this.providerFile = null;
+ modifiedResources.clear();
}
- EventAdmin getEventAdmin() {
- return this.eventAdmin;
+ public void commit(ResourceResolver resolver) throws PersistenceException {
+ for (FsResource fsResource : modifiedResources) {
+ try {
+ fsResource.commit();
+ } catch (IOException e) {
+ throw new PersistenceException(e.getMessage(), e);
+ }
+ }
+ modifiedResources.clear();
}
- File getRootFile() {
- return this.providerFile;
+ public boolean hasChanges(ResourceResolver resolver) {
+ return !this.modifiedResources.isEmpty();
}
- String getProviderRoot() {
- return this.providerRoot;
- }
+ // ---------- AttributableResourceProvider
- // ---------- internal
+ public Collection<String> getAttributeNames(ResourceResolver resolver) {
+ return Collections.singleton(ResourceResolverFactory.USER);
+ }
- private File getProviderFile(String providerFileName,
- BundleContext bundleContext) {
+ public Object getAttribute(ResourceResolver resolver, String name) {
+ return (ResourceResolverFactory.USER == name) ? this.user.getId() : null;
+ }
- // the file object from the plain name
- File providerFile = new File(providerFileName);
+ // ---------- RefreshableResourceProvider
- // resolve relative file name against sling.home or current
- // working directory
- if (!providerFile.isAbsolute()) {
- String home = bundleContext.getProperty("sling.home");
- if (home != null && home.length() > 0) {
- providerFile = new File(home, providerFileName);
+ public void refresh() {
+ // drop all unmodified resources from the cache
+ for (Iterator<FsResource> fsri = this.cache.values().iterator(); fsri.hasNext(); ) {
+ if (!this.modifiedResources.contains(fsri.next())) {
+ fsri.remove();
}
}
+ }
- // resolve the path
- providerFile = providerFile.getAbsoluteFile();
+ // ---------- SlingAdaptable
- // if the provider file does not exist, create an empty new folder
- if (!providerFile.exists() && !providerFile.mkdirs()) {
- throw new IllegalArgumentException(
- "Cannot create provider file root " + providerFile);
+ @SuppressWarnings("unchecked")
+ @Override
+ public <AdapterType> AdapterType adaptTo(Class<AdapterType> type) {
+ if (type == User.class) {
+ return (AdapterType) this.user;
}
- return providerFile;
+ return super.adaptTo(type);
}
- /**
- * Returns a file corresponding to the given absolute resource tree path. If
- * the path equals the configured provider root, the provider root file is
- * returned. If the path starts with the configured provider root, a file is
- * returned relative to the provider root file whose relative path is the
- * remains of the resource tree path without the provider root path.
- * Otherwise <code>null</code> is returned.
- */
- private File getFile(String path) {
- if (path.equals(providerRoot)) {
- return providerFile;
- }
-
- if (path.startsWith(providerRootPrefix)) {
- String relPath = path.substring(providerRootPrefix.length());
- return new File(providerFile, relPath);
- }
+ // ---------- internal
- return null;
+ void modified(FsResource resource) {
+ this.modifiedResources.add(resource);
}
- private Resource getResource(ResourceResolver resourceResolver,
- String resourcePath, File file) {
+ private Resource getResource(ResourceResolver resourceResolver, String resourcePath, File metaFile) {
- if (file != null) {
+ if (metaFile != null) {
// if the file exists, but is not a directory or no repository entry
// exists, return it as a resource
- if (file.exists()) {
- return new FsResource(resourceResolver, resourcePath, file);
+ if (metaFile.exists()) {
+ return createResource(resourceResolver, resourcePath, metaFile, null);
}
}
@@ -323,4 +284,35 @@ public class FsResourceProvider implemen
// not applicable or not an existing file path
return null;
}
+
+ private Resource createResource(ResourceResolver resourceResolver, String resourcePath, File metaFile, Map<String, Object> properties) {
+ FsResource res = this.cache.get(resourcePath);
+ if (res == null) {
+ File dataFile = getDataFile(metaFile);
+ res = new FsResource(resourceResolver, this, resourcePath, metaFile, dataFile, properties);
+ this.cache.put(resourcePath, res);
+ } else {
+ // TODO: short-term fix to prevent exceptions since metadata
+ // is locked after it went through the ResourceResolver. Better
+ // would probably be to have a facade with ResourceMetadata
+ // and a backend with the rest
+ res.unlockResourceMetadata();
+ }
+ return res;
+ }
+
+ private File getDataFile(final File metaFile) {
+ String name = metaFile.getName();
+ if (name.endsWith(".meta")) {
+ name = name.substring(0, name.length()-".meta".length());
+ }
+
+ File dirFile = new File(metaFile.getParentFile(), name);
+ if (dirFile.isDirectory()) {
+ return dirFile;
+ }
+
+ return new File(metaFile.getParentFile(), name + ".data");
+ }
+
}