You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by ss...@apache.org on 2017/02/24 20:45:26 UTC
svn commit: r1784324 - in /sling/trunk/bundles/extensions/fsresource/src:
main/java/org/apache/sling/fsprovider/internal/
main/java/org/apache/sling/fsprovider/internal/mapper/
main/java/org/apache/sling/fsprovider/internal/mapper/jcr/
main/java/org/ap...
Author: sseifert
Date: Fri Feb 24 20:45:26 2017
New Revision: 1784324
URL: http://svn.apache.org/viewvc?rev=1784324&view=rev
Log:
SLING-6440 further improvements for content file/json support:
- enhance jcr api layer
- make sure jcr primary type is always defined
- send events for all nodes in content files
- introduce simple LRU memory cache for parsed content files
Added:
sling/trunk/bundles/extensions/fsresource/src/main/java/org/apache/sling/fsprovider/internal/mapper/jcr/FsNodeType.java (with props)
sling/trunk/bundles/extensions/fsresource/src/main/java/org/apache/sling/fsprovider/internal/mapper/jcr/FsPropertyDefinition.java (with props)
sling/trunk/bundles/extensions/fsresource/src/main/java/org/apache/sling/fsprovider/internal/parser/ContentFileCache.java (with props)
sling/trunk/bundles/extensions/fsresource/src/main/java/org/apache/sling/fsprovider/internal/parser/ContentFileTypes.java (with props)
sling/trunk/bundles/extensions/fsresource/src/test/java/org/apache/sling/fsprovider/internal/parser/ContentFileCacheTest.java (with props)
sling/trunk/bundles/extensions/fsresource/src/test/resources/fs-test/folder2/content/file2content.txt (with props)
Modified:
sling/trunk/bundles/extensions/fsresource/src/main/java/org/apache/sling/fsprovider/internal/FileMonitor.java
sling/trunk/bundles/extensions/fsresource/src/main/java/org/apache/sling/fsprovider/internal/FsResourceProvider.java
sling/trunk/bundles/extensions/fsresource/src/main/java/org/apache/sling/fsprovider/internal/mapper/ContentFile.java
sling/trunk/bundles/extensions/fsresource/src/main/java/org/apache/sling/fsprovider/internal/mapper/ContentFileResource.java
sling/trunk/bundles/extensions/fsresource/src/main/java/org/apache/sling/fsprovider/internal/mapper/ContentFileResourceMapper.java
sling/trunk/bundles/extensions/fsresource/src/main/java/org/apache/sling/fsprovider/internal/mapper/ValueMapUtil.java
sling/trunk/bundles/extensions/fsresource/src/main/java/org/apache/sling/fsprovider/internal/mapper/jcr/FsNode.java
sling/trunk/bundles/extensions/fsresource/src/main/java/org/apache/sling/fsprovider/internal/mapper/jcr/FsProperty.java
sling/trunk/bundles/extensions/fsresource/src/main/java/org/apache/sling/fsprovider/internal/parser/ContentFileParser.java
sling/trunk/bundles/extensions/fsresource/src/test/java/org/apache/sling/fsprovider/internal/FileMonitorTest.java
sling/trunk/bundles/extensions/fsresource/src/test/java/org/apache/sling/fsprovider/internal/FilesFolderTest.java
sling/trunk/bundles/extensions/fsresource/src/test/java/org/apache/sling/fsprovider/internal/JsonContentTest.java
sling/trunk/bundles/extensions/fsresource/src/test/java/org/apache/sling/fsprovider/internal/mapper/ContentFileTest.java
sling/trunk/bundles/extensions/fsresource/src/test/resources/fs-test/folder2/content.json
Modified: sling/trunk/bundles/extensions/fsresource/src/main/java/org/apache/sling/fsprovider/internal/FileMonitor.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/fsresource/src/main/java/org/apache/sling/fsprovider/internal/FileMonitor.java?rev=1784324&r1=1784323&r2=1784324&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/fsresource/src/main/java/org/apache/sling/fsprovider/internal/FileMonitor.java (original)
+++ sling/trunk/bundles/extensions/fsresource/src/main/java/org/apache/sling/fsprovider/internal/FileMonitor.java Fri Feb 24 20:45:26 2017
@@ -19,13 +19,19 @@
package org.apache.sling.fsprovider.internal;
import java.io.File;
-import java.util.Collections;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
import org.apache.commons.lang3.StringUtils;
import org.apache.sling.api.resource.observation.ResourceChange;
import org.apache.sling.api.resource.observation.ResourceChange.ChangeType;
+import org.apache.sling.fsprovider.internal.mapper.ContentFile;
+import org.apache.sling.fsprovider.internal.parser.ContentFileCache;
import org.apache.sling.spi.resource.provider.ObservationReporter;
import org.apache.sling.spi.resource.provider.ObserverConfiguration;
import org.slf4j.Logger;
@@ -37,8 +43,7 @@ import org.slf4j.LoggerFactory;
*/
public final class FileMonitor extends TimerTask {
- /** The logger. */
- private final Logger logger = LoggerFactory.getLogger(this.getClass());
+ private final Logger log = LoggerFactory.getLogger(this.getClass());
private final Timer timer = new Timer();
private boolean stop = false;
@@ -49,18 +54,21 @@ public final class FileMonitor extends T
private final FsResourceProvider provider;
private final ContentFileExtensions contentFileExtensions;
+ private final ContentFileCache contentFileCache;
/**
* Creates a new instance of this class.
* @param provider The resource provider.
* @param interval The interval between executions of the task, in milliseconds.
*/
- public FileMonitor(final FsResourceProvider provider, final long interval, final ContentFileExtensions contentFileExtensions) {
+ public FileMonitor(final FsResourceProvider provider, final long interval,
+ final ContentFileExtensions contentFileExtensions, final ContentFileCache contentFileCache) {
this.provider = provider;
this.contentFileExtensions = contentFileExtensions;
+ this.contentFileCache = contentFileCache;
this.root = new Monitorable(this.provider.getProviderRoot(), this.provider.getRootFile(), null);
- createStatus(this.root, contentFileExtensions);
- logger.debug("Starting file monitor for {} with an interval of {}ms", this.root.file, interval);
+ createStatus(this.root, contentFileExtensions, contentFileCache);
+ log.debug("Starting file monitor for {} with an interval of {}ms", this.root.file, interval);
timer.schedule(this, 0, interval);
}
@@ -90,7 +98,7 @@ public final class FileMonitor extends T
Thread.currentThread().interrupt();
}
}
- logger.debug("Stopped file monitor for {}", this.root.file);
+ log.debug("Stopped file monitor for {}", this.root.file);
}
/**
@@ -129,24 +137,21 @@ public final class FileMonitor extends T
* @param reporter The ObservationReporter
*/
private void check(final Monitorable monitorable, final ObservationReporter reporter) {
- logger.debug("Checking {}", monitorable.file);
+ log.trace("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, contentFileExtensions);
- sendEvents(monitorable,
- ChangeType.ADDED,
- reporter);
+ createStatus(monitorable, contentFileExtensions, contentFileCache);
+ sendEvents(monitorable, ChangeType.ADDED, reporter);
}
} else {
// check if the file has been removed
if ( !monitorable.file.exists() ) {
// removed file and update status
- sendEvents(monitorable,
- ChangeType.REMOVED,
- reporter);
+ sendEvents(monitorable, ChangeType.REMOVED, reporter);
monitorable.status = NonExistingStatus.SINGLETON;
+ contentFileCache.remove(monitorable.path);
} else {
// check for changes
final FileStatus fs = (FileStatus)monitorable.status;
@@ -154,10 +159,9 @@ public final class FileMonitor extends T
if ( fs.lastModified < monitorable.file.lastModified() ) {
fs.lastModified = monitorable.file.lastModified();
// changed
- sendEvents(monitorable,
- ChangeType.CHANGED,
- reporter);
+ sendEvents(monitorable, ChangeType.CHANGED, reporter);
changed = true;
+ contentFileCache.remove(monitorable.path);
}
if ( fs instanceof DirStatus ) {
// directory
@@ -200,28 +204,86 @@ public final class FileMonitor extends T
* Send the event async via the event admin.
*/
private void sendEvents(final Monitorable monitorable, final ChangeType changeType, final ObservationReporter reporter) {
- if ( logger.isDebugEnabled() ) {
- logger.debug("Detected change for resource {} : {}", monitorable.path, changeType);
+ if (log.isDebugEnabled()) {
+ log.debug("Detected change for resource {} : {}", monitorable.path, changeType);
}
- for(final ObserverConfiguration config : reporter.getObserverConfigurations()) {
+ for (final ObserverConfiguration config : reporter.getObserverConfigurations()) {
if ( config.matches(monitorable.path) ) {
- final ResourceChange change = new ResourceChange(changeType, monitorable.path, false, null, null, null);
- reporter.reportChanges(Collections.singleton(change), false);
+ List<ResourceChange> changes = collectResourceChanges(monitorable, changeType);
+ if (log.isTraceEnabled()) {
+ for (ResourceChange change : changes) {
+ log.debug("Send change for resource {}: {} to {}", change.getPath(), change.getType(), config);
+ }
+ }
+ reporter.reportChanges(changes, false);
+ }
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private List<ResourceChange> collectResourceChanges(final Monitorable monitorable, final ChangeType changeType) {
+ List<ResourceChange> changes = new ArrayList<>();
+ if (monitorable.status instanceof ContentFileStatus) {
+ ContentFile contentFile = ((ContentFileStatus)monitorable.status).contentFile;
+ if (changeType == ChangeType.CHANGED) {
+ Map<String,Object> content = (Map<String,Object>)contentFile.getContent();
+ // we cannot easily report the diff of resource changes between two content files
+ // so we simulate a removal of the toplevel node and then add all nodes contained in the current content file again.
+ changes.add(buildContentResourceChange(ChangeType.REMOVED, content, monitorable.path));
+ addContentResourceChanges(changes, ChangeType.ADDED, content, monitorable.path);
+ }
+ else {
+ addContentResourceChanges(changes, changeType, (Map<String,Object>)contentFile.getContent(), monitorable.path);
+ }
+ }
+ else {
+ changes.add(new ResourceChange(changeType, monitorable.path, false, null, null, null));
+ }
+ return changes;
+ }
+ @SuppressWarnings("unchecked")
+ private void addContentResourceChanges(final List<ResourceChange> changes, final ChangeType changeType,
+ final Map<String,Object> content, final String path) {
+ changes.add(buildContentResourceChange(changeType, content, path));
+ if (content != null) {
+ for (Map.Entry<String,Object> entry : content.entrySet()) {
+ if (entry.getValue() instanceof Map) {
+ String childPath = path + "/" + entry.getKey();
+ addContentResourceChanges(changes, changeType, (Map<String,Object>)entry.getValue(), childPath);
+ }
}
}
}
+ private ResourceChange buildContentResourceChange(final ChangeType changeType, final Map<String,Object> content, final String path) {
+ Set<String> addedPropertyNames = null;
+ if (content != null && changeType == ChangeType.ADDED) {
+ addedPropertyNames = new HashSet<>();
+ for (Map.Entry<String,Object> entry : content.entrySet()) {
+ if (!(entry.getValue() instanceof Map)) {
+ addedPropertyNames.add(entry.getKey());
+ }
+ }
+ }
+ return new ResourceChange(changeType, path, false, addedPropertyNames, null, null);
+ }
/**
* Create a status object for the monitorable
*/
- private static void createStatus(final Monitorable monitorable, ContentFileExtensions contentFileExtensions) {
+ private static void createStatus(final Monitorable monitorable, ContentFileExtensions contentFileExtensions, ContentFileCache contentFileCache) {
if ( !monitorable.file.exists() ) {
monitorable.status = NonExistingStatus.SINGLETON;
} else if ( monitorable.file.isFile() ) {
- monitorable.status = new FileStatus(monitorable.file);
+ if (contentFileExtensions.matchesSuffix(monitorable.file)) {
+ monitorable.status = new ContentFileStatus(monitorable.file,
+ new ContentFile(monitorable.file, monitorable.path, null, contentFileCache));
+ }
+ else {
+ monitorable.status = new FileStatus(monitorable.file);
+ }
} else {
- monitorable.status = new DirStatus(monitorable.file, monitorable.path, contentFileExtensions);
+ monitorable.status = new DirStatus(monitorable.file, monitorable.path, contentFileExtensions, contentFileCache);
}
}
@@ -248,12 +310,22 @@ public final class FileMonitor extends T
this.lastModified = file.lastModified();
}
}
-
+
+ /** Status for content files */
+ private static class ContentFileStatus extends FileStatus {
+ public final ContentFile contentFile;
+ public ContentFileStatus(final File file, final ContentFile contentFile) {
+ super(file);
+ this.contentFile = contentFile;
+ }
+ }
+
/** Status for directories. */
private static final class DirStatus extends FileStatus {
public Monitorable[] children;
- public DirStatus(final File dir, final String path, final ContentFileExtensions contentFileExtensions) {
+ public DirStatus(final File dir, final String path,
+ final ContentFileExtensions contentFileExtensions, final ContentFileCache contentFileCache) {
super(dir);
final File[] files = dir.listFiles();
if (files != null) {
@@ -261,7 +333,7 @@ public final class FileMonitor extends T
for (int i = 0; i < files.length; i++) {
this.children[i] = new Monitorable(path + '/' + files[i].getName(), files[i],
contentFileExtensions.getSuffix(files[i]));
- FileMonitor.createStatus(this.children[i], contentFileExtensions);
+ FileMonitor.createStatus(this.children[i], contentFileExtensions, contentFileCache);
}
} else {
this.children = new Monitorable[0];
Modified: sling/trunk/bundles/extensions/fsresource/src/main/java/org/apache/sling/fsprovider/internal/FsResourceProvider.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/fsresource/src/main/java/org/apache/sling/fsprovider/internal/FsResourceProvider.java?rev=1784324&r1=1784323&r2=1784324&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/fsresource/src/main/java/org/apache/sling/fsprovider/internal/FsResourceProvider.java (original)
+++ sling/trunk/bundles/extensions/fsresource/src/main/java/org/apache/sling/fsprovider/internal/FsResourceProvider.java Fri Feb 24 20:45:26 2017
@@ -31,7 +31,8 @@ import org.apache.sling.api.resource.Res
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.fsprovider.internal.mapper.ContentFileResourceMapper;
import org.apache.sling.fsprovider.internal.mapper.FileResourceMapper;
-import org.apache.sling.fsprovider.internal.parser.ContentFileParser;
+import org.apache.sling.fsprovider.internal.parser.ContentFileCache;
+import org.apache.sling.fsprovider.internal.parser.ContentFileTypes;
import org.apache.sling.spi.resource.provider.ObservationReporter;
import org.apache.sling.spi.resource.provider.ProviderContext;
import org.apache.sling.spi.resource.provider.ResolveContext;
@@ -108,7 +109,11 @@ public final class FsResourceProvider ex
@AttributeDefinition(name = "Mount JSON",
description = "Mount .json files as content in the resource hierarchy.")
boolean provider_json_content();
-
+
+ @AttributeDefinition(name = "Cache Size",
+ description = "Max. number of content files cached in memory.")
+ int provider_cache_size() default 1000;
+
/**
* Internal Name hint for web console.
*/
@@ -130,6 +135,9 @@ public final class FsResourceProvider ex
// if true resources from filesystem are only "overlayed" to JCR resources, serving JCR as fallback within the same path
private boolean overlayParentResourceProvider;
+
+ // cache for parsed content files
+ private ContentFileCache contentFileCache;
/**
* Returns a resource wrapping a file system file or folder for the given
@@ -243,17 +251,20 @@ public final class FsResourceProvider ex
List<String> contentFileSuffixes = new ArrayList<>();
if (config.provider_json_content()) {
- contentFileSuffixes.add(ContentFileParser.JSON_SUFFIX);
+ contentFileSuffixes.add(ContentFileTypes.JSON_SUFFIX);
this.overlayParentResourceProvider = false;
}
ContentFileExtensions contentFileExtensions = new ContentFileExtensions(contentFileSuffixes);
+ this.contentFileCache = new ContentFileCache(config.provider_cache_size());
this.fileMapper = new FileResourceMapper(this.providerRoot, this.providerFile, contentFileExtensions);
- this.contentFileMapper = new ContentFileResourceMapper(this.providerRoot, this.providerFile, contentFileExtensions);
+ this.contentFileMapper = new ContentFileResourceMapper(this.providerRoot, this.providerFile,
+ contentFileExtensions, this.contentFileCache);
// start background monitor if check interval is higher than 100
if ( config.provider_checkinterval() > 100 ) {
- this.monitor = new FileMonitor(this, config.provider_checkinterval(), contentFileExtensions);
+ this.monitor = new FileMonitor(this, config.provider_checkinterval(),
+ contentFileExtensions, this.contentFileCache);
}
}
@@ -268,6 +279,10 @@ public final class FsResourceProvider ex
this.overlayParentResourceProvider = false;
this.fileMapper = null;
this.contentFileMapper = null;
+ if (this.contentFileCache != null) {
+ this.contentFileCache.clear();
+ this.contentFileCache = null;
+ }
}
File getRootFile() {
Modified: sling/trunk/bundles/extensions/fsresource/src/main/java/org/apache/sling/fsprovider/internal/mapper/ContentFile.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/fsresource/src/main/java/org/apache/sling/fsprovider/internal/mapper/ContentFile.java?rev=1784324&r1=1784323&r2=1784324&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/fsresource/src/main/java/org/apache/sling/fsprovider/internal/mapper/ContentFile.java (original)
+++ sling/trunk/bundles/extensions/fsresource/src/main/java/org/apache/sling/fsprovider/internal/mapper/ContentFile.java Fri Feb 24 20:45:26 2017
@@ -22,7 +22,7 @@ import java.io.File;
import java.util.Map;
import org.apache.sling.api.resource.ValueMap;
-import org.apache.sling.fsprovider.internal.parser.ContentFileParser;
+import org.apache.sling.fsprovider.internal.parser.ContentFileCache;
/**
* Reference to a file that contains a content fragment (e.g. JSON, JCR XML).
@@ -30,28 +30,35 @@ import org.apache.sling.fsprovider.inter
public final class ContentFile {
private final File file;
+ private final String path;
private final String subPath;
+ private final ContentFileCache contentFileCache;
private boolean contentInitialized;
private Object content;
private ValueMap valueMap;
/**
* @param file File with content fragment
+ * @param path Root path of the content file
* @param subPath Relative path addressing content fragment inside file
+ * @param contentFileCache Content file cache
*/
- public ContentFile(File file, String subPath) {
+ public ContentFile(File file, String path, String subPath, ContentFileCache contentFileCache) {
this.file = file;
+ this.path = path;
this.subPath = subPath;
+ this.contentFileCache = contentFileCache;
}
/**
* @param file File with content fragment
+ * @param path Root path of the content file
* @param subPath Relative path addressing content fragment inside file
+ * @param contentFileCache Content file cache
* @param content Content
*/
- public ContentFile(File file, String subPath, Object content) {
- this.file = file;
- this.subPath = subPath;
+ public ContentFile(File file, String path, String subPath, ContentFileCache contentFileCache, Object content) {
+ this(file, path, subPath, contentFileCache);
this.contentInitialized = true;
this.content = content;
}
@@ -62,6 +69,13 @@ public final class ContentFile {
public File getFile() {
return file;
}
+
+ /**
+ * @return Root path of content file
+ */
+ public String getPath() {
+ return path;
+ }
/**
* @return Relative path addressing content fragment inside file
@@ -76,7 +90,7 @@ public final class ContentFile {
*/
public Object getContent() {
if (!contentInitialized) {
- Map<String,Object> rootContent = ContentFileParser.parse(file);
+ Map<String,Object> rootContent = contentFileCache.get(path, file);
content = getDeepContent(rootContent, subPath);
contentInitialized = true;
}
Modified: sling/trunk/bundles/extensions/fsresource/src/main/java/org/apache/sling/fsprovider/internal/mapper/ContentFileResource.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/fsresource/src/main/java/org/apache/sling/fsprovider/internal/mapper/ContentFileResource.java?rev=1784324&r1=1784323&r2=1784324&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/fsresource/src/main/java/org/apache/sling/fsprovider/internal/mapper/ContentFileResource.java (original)
+++ sling/trunk/bundles/extensions/fsresource/src/main/java/org/apache/sling/fsprovider/internal/mapper/ContentFileResource.java Fri Feb 24 20:45:26 2017
@@ -54,10 +54,11 @@ public final class ContentFileResource e
* @param resourcePath The resource path in the resource tree
* @param contentFile Content file with sub path
*/
- ContentFileResource(ResourceResolver resolver, String resourcePath, ContentFile contentFile) {
+ ContentFileResource(ResourceResolver resolver, ContentFile contentFile) {
this.resolver = resolver;
- this.resourcePath = resourcePath;
this.contentFile = contentFile;
+ this.resourcePath = contentFile.getPath()
+ + (contentFile.getSubPath() != null ? "/" + contentFile.getSubPath() : "");
}
public String getPath() {
@@ -79,7 +80,7 @@ public final class ContentFileResource e
public String getResourceSuperType() {
if (resourceSuperType == null) {
- resourceSuperType = contentFile.getValueMap().get("sling:resourceSuperType", String.class);
+ resourceSuperType = getValueMap().get("sling:resourceSuperType", String.class);
}
return resourceSuperType;
}
Modified: sling/trunk/bundles/extensions/fsresource/src/main/java/org/apache/sling/fsprovider/internal/mapper/ContentFileResourceMapper.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/fsresource/src/main/java/org/apache/sling/fsprovider/internal/mapper/ContentFileResourceMapper.java?rev=1784324&r1=1784323&r2=1784324&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/fsresource/src/main/java/org/apache/sling/fsprovider/internal/mapper/ContentFileResourceMapper.java (original)
+++ sling/trunk/bundles/extensions/fsresource/src/main/java/org/apache/sling/fsprovider/internal/mapper/ContentFileResourceMapper.java Fri Feb 24 20:45:26 2017
@@ -32,6 +32,7 @@ import org.apache.sling.api.resource.Res
import org.apache.sling.api.resource.ResourceUtil;
import org.apache.sling.fsprovider.internal.ContentFileExtensions;
import org.apache.sling.fsprovider.internal.FsResourceMapper;
+import org.apache.sling.fsprovider.internal.parser.ContentFileCache;
public final class ContentFileResourceMapper implements FsResourceMapper {
@@ -42,18 +43,21 @@ public final class ContentFileResourceMa
private final File providerFile;
private final ContentFileExtensions contentFileExtensions;
+ private final ContentFileCache contentFileCache;
- public ContentFileResourceMapper(String providerRoot, File providerFile, ContentFileExtensions contentFileExtensions) {
+ public ContentFileResourceMapper(String providerRoot, File providerFile,
+ ContentFileExtensions contentFileExtensions, ContentFileCache contentFileCache) {
this.providerRootPrefix = providerRoot.concat("/");
this.providerFile = providerFile;
this.contentFileExtensions = contentFileExtensions;
+ this.contentFileCache = contentFileCache;
}
@Override
public Resource getResource(final ResourceResolver resolver, final String resourcePath) {
ContentFile contentFile = getFile(resourcePath, null);
if (contentFile != null && contentFile.hasContent()) {
- return new ContentFileResource(resolver, resourcePath, contentFile);
+ return new ContentFileResource(resolver, contentFile);
}
else {
return null;
@@ -78,9 +82,9 @@ public final class ContentFileResourceMa
for (File file : parentFile.listFiles()) {
String filenameSuffix = contentFileExtensions.getSuffix(file);
if (filenameSuffix != null) {
- ContentFile contentFile = new ContentFile(file, null);
String path = parentPath + "/" + StringUtils.substringBeforeLast(file.getName(), filenameSuffix);
- childResources.add(new ContentFileResource(resolver, path, contentFile));
+ ContentFile contentFile = new ContentFile(file, path, null, contentFileCache);
+ childResources.add(new ContentFileResource(resolver, contentFile));
}
}
if (!childResources.isEmpty()) {
@@ -106,7 +110,7 @@ public final class ContentFileResourceMa
else {
subPath = parentContentFile.getSubPath() + "/" + entry.getKey();
}
- children.add(new ContentFile(parentContentFile.getFile(), subPath, entry.getValue()));
+ children.add(new ContentFile(parentContentFile.getFile(), parentContentFile.getPath(), subPath, contentFileCache, entry.getValue()));
}
}
}
@@ -118,8 +122,7 @@ public final class ContentFileResourceMa
@Override
public Object transform(Object input) {
ContentFile contentFile = (ContentFile)input;
- String path = parentPath + "/" + ResourceUtil.getName(contentFile.getSubPath());
- return new ContentFileResource(resolver, path, contentFile);
+ return new ContentFileResource(resolver, contentFile);
}
});
}
@@ -133,7 +136,7 @@ public final class ContentFileResourceMa
for (String filenameSuffix : contentFileExtensions.getSuffixes()) {
File file = new File(providerFile, relPath + filenameSuffix);
if (file.exists()) {
- return new ContentFile(file, subPath);
+ return new ContentFile(file, path, subPath, contentFileCache);
}
}
// try to find in parent path which contains content fragment
Modified: sling/trunk/bundles/extensions/fsresource/src/main/java/org/apache/sling/fsprovider/internal/mapper/ValueMapUtil.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/fsresource/src/main/java/org/apache/sling/fsprovider/internal/mapper/ValueMapUtil.java?rev=1784324&r1=1784323&r2=1784324&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/fsresource/src/main/java/org/apache/sling/fsprovider/internal/mapper/ValueMapUtil.java (original)
+++ sling/trunk/bundles/extensions/fsresource/src/main/java/org/apache/sling/fsprovider/internal/mapper/ValueMapUtil.java Fri Feb 24 20:45:26 2017
@@ -22,6 +22,8 @@ import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
+import javax.jcr.nodetype.NodeType;
+
import org.apache.sling.api.resource.ValueMap;
import org.apache.sling.api.wrappers.ValueMapDecorator;
@@ -38,6 +40,7 @@ final class ValueMapUtil {
*/
public static ValueMap toValueMap(Map<String,Object> content) {
Map<String,Object> props = new HashMap<>();
+
for (Map.Entry<String, Object> entry : ((Map<String,Object>)content).entrySet()) {
if (entry.getValue() instanceof Map) {
// skip child resources
@@ -51,6 +54,12 @@ final class ValueMapUtil {
props.put(entry.getKey(), entry.getValue());
}
}
+
+ // fallback to default jcr:primaryType is none is set
+ if (!props.containsKey("jcr:primaryType")) {
+ props.put("jcr:primaryType", NodeType.NT_UNSTRUCTURED);
+ }
+
return new ValueMapDecorator(props);
}
Modified: sling/trunk/bundles/extensions/fsresource/src/main/java/org/apache/sling/fsprovider/internal/mapper/jcr/FsNode.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/fsresource/src/main/java/org/apache/sling/fsprovider/internal/mapper/jcr/FsNode.java?rev=1784324&r1=1784323&r2=1784324&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/fsresource/src/main/java/org/apache/sling/fsprovider/internal/mapper/jcr/FsNode.java (original)
+++ sling/trunk/bundles/extensions/fsresource/src/main/java/org/apache/sling/fsprovider/internal/mapper/jcr/FsNode.java Fri Feb 24 20:45:26 2017
@@ -63,6 +63,14 @@ public final class FsNode extends FsItem
super(resource);
}
+ private String getPrimaryTypeName() {
+ return props.get("jcr:primaryType", String.class);
+ }
+
+ private String[] getMixinTypeNames() {
+ return props.get("jcr:mixinTypes", new String[0]);
+ }
+
@Override
public Node getNode(String relPath) throws PathNotFoundException, RepositoryException {
Resource child = resource.getChild(relPath);
@@ -123,7 +131,7 @@ public final class FsNode extends FsItem
@Override
public boolean isNodeType(String nodeTypeName) throws RepositoryException {
- return StringUtils.equals(nodeTypeName, props.get("jcr:primaryType", String.class));
+ return StringUtils.equals(nodeTypeName, getPrimaryTypeName());
}
@Override
@@ -146,6 +154,21 @@ public final class FsNode extends FsItem
return false;
}
+ @Override
+ public NodeType getPrimaryNodeType() throws RepositoryException {
+ return new FsNodeType(getPrimaryTypeName(), false);
+ }
+
+ @Override
+ public NodeType[] getMixinNodeTypes() throws RepositoryException {
+ String[] mixinTypeNames = getMixinTypeNames();
+ NodeType[] mixinTypes = new NodeType[mixinTypeNames.length];
+ for (int i=0; i<mixinTypeNames.length; i++) {
+ mixinTypes[i] = new FsNodeType(mixinTypeNames[i], true);
+ }
+ return mixinTypes;
+ }
+
// --- unsupported methods ---
@@ -444,11 +467,6 @@ public final class FsNode extends FsItem
}
@Override
- public NodeType getPrimaryNodeType() throws RepositoryException {
- throw new UnsupportedOperationException();
- }
-
- @Override
public String getIdentifier() throws RepositoryException {
throw new UnsupportedOperationException();
}
@@ -458,11 +476,6 @@ public final class FsNode extends FsItem
throw new UnsupportedOperationException();
}
- @Override
- public NodeType[] getMixinNodeTypes() throws RepositoryException {
- throw new UnsupportedOperationException();
- }
-
@Override
public Item getPrimaryItem() throws ItemNotFoundException, RepositoryException {
throw new UnsupportedOperationException();
Added: sling/trunk/bundles/extensions/fsresource/src/main/java/org/apache/sling/fsprovider/internal/mapper/jcr/FsNodeType.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/fsresource/src/main/java/org/apache/sling/fsprovider/internal/mapper/jcr/FsNodeType.java?rev=1784324&view=auto
==============================================================================
--- sling/trunk/bundles/extensions/fsresource/src/main/java/org/apache/sling/fsprovider/internal/mapper/jcr/FsNodeType.java (added)
+++ sling/trunk/bundles/extensions/fsresource/src/main/java/org/apache/sling/fsprovider/internal/mapper/jcr/FsNodeType.java Fri Feb 24 20:45:26 2017
@@ -0,0 +1,157 @@
+/*
+ * 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.fsprovider.internal.mapper.jcr;
+
+import javax.jcr.Value;
+import javax.jcr.nodetype.NodeDefinition;
+import javax.jcr.nodetype.NodeType;
+import javax.jcr.nodetype.NodeTypeIterator;
+import javax.jcr.nodetype.PropertyDefinition;
+
+import org.apache.commons.lang3.StringUtils;
+
+class FsNodeType implements NodeType {
+
+ private final String name;
+ private final boolean mixin;
+
+ public FsNodeType(String name, boolean mixin) {
+ this.name = name;
+ this.mixin = mixin;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public String[] getDeclaredSupertypeNames() {
+ return new String[0];
+ }
+
+ @Override
+ public boolean isAbstract() {
+ return false;
+ }
+
+ @Override
+ public boolean isMixin() {
+ return mixin;
+ }
+
+ @Override
+ public boolean hasOrderableChildNodes() {
+ return false;
+ }
+
+ @Override
+ public boolean isQueryable() {
+ return false;
+ }
+
+ @Override
+ public String getPrimaryItemName() {
+ return null;
+ }
+
+ @Override
+ public NodeType[] getSupertypes() {
+ return new NodeType[0];
+ }
+
+ @Override
+ public NodeType[] getDeclaredSupertypes() {
+ return new NodeType[0];
+ }
+
+ @Override
+ public boolean isNodeType(String nodeTypeName) {
+ return StringUtils.equals(name, nodeTypeName);
+ }
+
+
+ // --- unsupported methods ---
+
+ @Override
+ public PropertyDefinition[] getDeclaredPropertyDefinitions() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public NodeDefinition[] getDeclaredChildNodeDefinitions() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public NodeTypeIterator getSubtypes() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public NodeTypeIterator getDeclaredSubtypes() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public PropertyDefinition[] getPropertyDefinitions() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public NodeDefinition[] getChildNodeDefinitions() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean canSetProperty(String propertyName, Value value) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean canSetProperty(String propertyName, Value[] values) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean canAddChildNode(String childNodeName) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean canAddChildNode(String childNodeName, String nodeTypeName) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean canRemoveItem(String itemName) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean canRemoveNode(String nodeName) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean canRemoveProperty(String propertyName) {
+ throw new UnsupportedOperationException();
+ }
+
+}
Propchange: sling/trunk/bundles/extensions/fsresource/src/main/java/org/apache/sling/fsprovider/internal/mapper/jcr/FsNodeType.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: sling/trunk/bundles/extensions/fsresource/src/main/java/org/apache/sling/fsprovider/internal/mapper/jcr/FsNodeType.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Fri Feb 24 20:45:26 2017
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author
Propchange: sling/trunk/bundles/extensions/fsresource/src/main/java/org/apache/sling/fsprovider/internal/mapper/jcr/FsNodeType.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Modified: sling/trunk/bundles/extensions/fsresource/src/main/java/org/apache/sling/fsprovider/internal/mapper/jcr/FsProperty.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/fsresource/src/main/java/org/apache/sling/fsprovider/internal/mapper/jcr/FsProperty.java?rev=1784324&r1=1784323&r2=1784324&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/fsresource/src/main/java/org/apache/sling/fsprovider/internal/mapper/jcr/FsProperty.java (original)
+++ sling/trunk/bundles/extensions/fsresource/src/main/java/org/apache/sling/fsprovider/internal/mapper/jcr/FsProperty.java Fri Feb 24 20:45:26 2017
@@ -143,7 +143,12 @@ class FsProperty extends FsItem implemen
return getValue().getType();
}
+ @Override
+ public PropertyDefinition getDefinition() throws RepositoryException {
+ return new FsPropertyDefinition(propertyName);
+ }
+
// --- unsupported methods ---
@Override
@@ -218,11 +223,6 @@ class FsProperty extends FsItem implemen
throw new UnsupportedOperationException();
}
- @Override
- public PropertyDefinition getDefinition() throws RepositoryException {
- throw new UnsupportedOperationException();
- }
-
@Override
public Property getProperty() throws ItemNotFoundException, ValueFormatException, RepositoryException {
throw new UnsupportedOperationException();
Added: sling/trunk/bundles/extensions/fsresource/src/main/java/org/apache/sling/fsprovider/internal/mapper/jcr/FsPropertyDefinition.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/fsresource/src/main/java/org/apache/sling/fsprovider/internal/mapper/jcr/FsPropertyDefinition.java?rev=1784324&view=auto
==============================================================================
--- sling/trunk/bundles/extensions/fsresource/src/main/java/org/apache/sling/fsprovider/internal/mapper/jcr/FsPropertyDefinition.java (added)
+++ sling/trunk/bundles/extensions/fsresource/src/main/java/org/apache/sling/fsprovider/internal/mapper/jcr/FsPropertyDefinition.java Fri Feb 24 20:45:26 2017
@@ -0,0 +1,100 @@
+/*
+ * 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.fsprovider.internal.mapper.jcr;
+
+import javax.jcr.PropertyType;
+import javax.jcr.Value;
+import javax.jcr.nodetype.NodeType;
+import javax.jcr.nodetype.PropertyDefinition;
+import javax.jcr.version.OnParentVersionAction;
+
+class FsPropertyDefinition implements PropertyDefinition {
+
+ private final String name;
+
+ public FsPropertyDefinition(String name) {
+ this.name = name;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public NodeType getDeclaringNodeType() {
+ return null;
+ }
+
+ @Override
+ public boolean isAutoCreated() {
+ return false;
+ }
+
+ @Override
+ public boolean isMandatory() {
+ return false;
+ }
+
+ @Override
+ public int getOnParentVersion() {
+ return OnParentVersionAction.COPY;
+ }
+
+ @Override
+ public boolean isProtected() {
+ return false;
+ }
+
+ @Override
+ public int getRequiredType() {
+ return PropertyType.UNDEFINED;
+ }
+
+ @Override
+ public String[] getValueConstraints() {
+ return new String[0];
+ }
+
+ @Override
+ public Value[] getDefaultValues() {
+ return new Value[0];
+ }
+
+ @Override
+ public boolean isMultiple() {
+ return false;
+ }
+
+ @Override
+ public String[] getAvailableQueryOperators() {
+ return new String[0];
+ }
+
+ @Override
+ public boolean isFullTextSearchable() {
+ return false;
+ }
+
+ @Override
+ public boolean isQueryOrderable() {
+ return false;
+ }
+
+}
Propchange: sling/trunk/bundles/extensions/fsresource/src/main/java/org/apache/sling/fsprovider/internal/mapper/jcr/FsPropertyDefinition.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: sling/trunk/bundles/extensions/fsresource/src/main/java/org/apache/sling/fsprovider/internal/mapper/jcr/FsPropertyDefinition.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Fri Feb 24 20:45:26 2017
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author
Propchange: sling/trunk/bundles/extensions/fsresource/src/main/java/org/apache/sling/fsprovider/internal/mapper/jcr/FsPropertyDefinition.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: sling/trunk/bundles/extensions/fsresource/src/main/java/org/apache/sling/fsprovider/internal/parser/ContentFileCache.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/fsresource/src/main/java/org/apache/sling/fsprovider/internal/parser/ContentFileCache.java?rev=1784324&view=auto
==============================================================================
--- sling/trunk/bundles/extensions/fsresource/src/main/java/org/apache/sling/fsprovider/internal/parser/ContentFileCache.java (added)
+++ sling/trunk/bundles/extensions/fsresource/src/main/java/org/apache/sling/fsprovider/internal/parser/ContentFileCache.java Fri Feb 24 20:45:26 2017
@@ -0,0 +1,107 @@
+/*
+ * 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.fsprovider.internal.parser;
+
+import java.io.File;
+import java.util.Collections;
+import java.util.Map;
+
+import org.apache.commons.collections.map.LRUMap;
+
+/**
+ * Cache for parsed content from content files (e.g. JSON, JCR XML).
+ */
+public final class ContentFileCache {
+
+ private final Map<String,Map<String,Object>> contentCache;
+ private final Map<String,Object> NULL_MAP = Collections.emptyMap();
+
+ /**
+ * @param maxSize Cache size. 0 = caching disabled.
+ */
+ @SuppressWarnings("unchecked")
+ public ContentFileCache(int maxSize) {
+ if (maxSize > 0) {
+ this.contentCache = Collections.synchronizedMap(new LRUMap(maxSize));
+ }
+ else {
+ this.contentCache = null;
+ }
+ }
+
+ /**
+ * Get content.
+ * @param path Path (used as cache key).
+ * @param file File
+ * @return Content or null
+ */
+ public Map<String,Object> get(String path, File file) {
+ Map<String,Object> content = null;
+ if (contentCache != null) {
+ content = contentCache.get(path);
+ }
+ if (content == null) {
+ content = ContentFileParser.parse(file);
+ if (content == null) {
+ content = NULL_MAP;
+ }
+ if (contentCache != null) {
+ contentCache.put(path, content);
+ }
+ }
+ if (content == NULL_MAP) {
+ return null;
+ }
+ else {
+ return content;
+ }
+ }
+
+ /**
+ * Remove content from cache.
+ * @param path Path (used as cache key)
+ */
+ public void remove(String path) {
+ if (contentCache != null) {
+ contentCache.remove(path);
+ }
+ }
+
+ /**
+ * Clear whole cache
+ */
+ public void clear() {
+ if (contentCache != null) {
+ contentCache.clear();
+ }
+ }
+
+ /**
+ * @return Current cache size
+ */
+ public int size() {
+ if (contentCache != null) {
+ return contentCache.size();
+ }
+ else {
+ return 0;
+ }
+ }
+
+}
Propchange: sling/trunk/bundles/extensions/fsresource/src/main/java/org/apache/sling/fsprovider/internal/parser/ContentFileCache.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: sling/trunk/bundles/extensions/fsresource/src/main/java/org/apache/sling/fsprovider/internal/parser/ContentFileCache.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Fri Feb 24 20:45:26 2017
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author
Propchange: sling/trunk/bundles/extensions/fsresource/src/main/java/org/apache/sling/fsprovider/internal/parser/ContentFileCache.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Modified: sling/trunk/bundles/extensions/fsresource/src/main/java/org/apache/sling/fsprovider/internal/parser/ContentFileParser.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/fsresource/src/main/java/org/apache/sling/fsprovider/internal/parser/ContentFileParser.java?rev=1784324&r1=1784323&r2=1784324&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/fsresource/src/main/java/org/apache/sling/fsprovider/internal/parser/ContentFileParser.java (original)
+++ sling/trunk/bundles/extensions/fsresource/src/main/java/org/apache/sling/fsprovider/internal/parser/ContentFileParser.java Fri Feb 24 20:45:26 2017
@@ -18,20 +18,21 @@
*/
package org.apache.sling.fsprovider.internal.parser;
+import static org.apache.sling.fsprovider.internal.parser.ContentFileTypes.JSON_SUFFIX;
+
import java.io.File;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
* Parses file that contains content fragments (e.g. JSON, JCR XML).
*/
-public final class ContentFileParser {
+class ContentFileParser {
- /**
- * JSON content files.
- */
- public static final String JSON_SUFFIX = ".json";
+ private static final Logger log = LoggerFactory.getLogger(ContentFileParser.class);
private ContentFileParser() {
// static methods only
@@ -43,8 +44,13 @@ public final class ContentFileParser {
* @return Content or null if content could not be parsed.
*/
public static Map<String,Object> parse(File file) {
- if (StringUtils.endsWith(file.getName(), JSON_SUFFIX)) {
- return JsonFileParser.parse(file);
+ try {
+ if (StringUtils.endsWith(file.getName(), JSON_SUFFIX)) {
+ return JsonFileParser.parse(file);
+ }
+ }
+ catch (Throwable ex) {
+ log.warn("Error parsing content from " + file.getPath(), ex);
}
return null;
}
Added: sling/trunk/bundles/extensions/fsresource/src/main/java/org/apache/sling/fsprovider/internal/parser/ContentFileTypes.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/fsresource/src/main/java/org/apache/sling/fsprovider/internal/parser/ContentFileTypes.java?rev=1784324&view=auto
==============================================================================
--- sling/trunk/bundles/extensions/fsresource/src/main/java/org/apache/sling/fsprovider/internal/parser/ContentFileTypes.java (added)
+++ sling/trunk/bundles/extensions/fsresource/src/main/java/org/apache/sling/fsprovider/internal/parser/ContentFileTypes.java Fri Feb 24 20:45:26 2017
@@ -0,0 +1,35 @@
+/*
+ * 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.fsprovider.internal.parser;
+
+/**
+ * Content file types.
+ */
+public final class ContentFileTypes {
+
+ /**
+ * JSON content files.
+ */
+ public static final String JSON_SUFFIX = ".json";
+
+ private ContentFileTypes() {
+ // static methods only
+ }
+
+}
Propchange: sling/trunk/bundles/extensions/fsresource/src/main/java/org/apache/sling/fsprovider/internal/parser/ContentFileTypes.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: sling/trunk/bundles/extensions/fsresource/src/main/java/org/apache/sling/fsprovider/internal/parser/ContentFileTypes.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Fri Feb 24 20:45:26 2017
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author
Propchange: sling/trunk/bundles/extensions/fsresource/src/main/java/org/apache/sling/fsprovider/internal/parser/ContentFileTypes.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Modified: sling/trunk/bundles/extensions/fsresource/src/test/java/org/apache/sling/fsprovider/internal/FileMonitorTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/fsresource/src/test/java/org/apache/sling/fsprovider/internal/FileMonitorTest.java?rev=1784324&r1=1784323&r2=1784324&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/fsresource/src/test/java/org/apache/sling/fsprovider/internal/FileMonitorTest.java (original)
+++ sling/trunk/bundles/extensions/fsresource/src/test/java/org/apache/sling/fsprovider/internal/FileMonitorTest.java Fri Feb 24 20:45:26 2017
@@ -37,6 +37,8 @@ import org.apache.sling.testing.mock.sli
import org.junit.Rule;
import org.junit.Test;
+import com.google.common.collect.ImmutableSet;
+
/**
* Test events when changing filesystem content.
*/
@@ -164,8 +166,10 @@ public class FileMonitorTest {
Thread.sleep(250);
- assertEquals(1, changes.size());
- assertChange(changes, 0, "/fs-test/folder2/content", ChangeType.CHANGED);
+ assertTrue(changes.size() > 1);
+ assertChange(changes, 0, "/fs-test/folder2/content", ChangeType.REMOVED);
+ assertChange(changes, 1, "/fs-test/folder2/content", ChangeType.ADDED);
+ assertChange(changes, 2, "/fs-test/folder2/content/jcr:content", ChangeType.ADDED);
}
@Test
@@ -174,13 +178,14 @@ public class FileMonitorTest {
assertTrue(changes.isEmpty());
File file1c = new File(tempDir, "folder1/file1c.json");
- FileUtils.write(file1c, "{'prop1':'value1'}");
+ FileUtils.write(file1c, "{\"prop1\":\"value1\",\"child1\":{\"prop2\":\"value1\"}}");
Thread.sleep(250);
- assertEquals(2, changes.size());
+ assertEquals(3, changes.size());
assertChange(changes, 0, "/fs-test/folder1", ChangeType.CHANGED);
- assertChange(changes, 1, "/fs-test/folder1/file1c", ChangeType.ADDED);
+ assertChange(changes, 1, "/fs-test/folder1/file1c", ChangeType.ADDED, "prop1");
+ assertChange(changes, 2, "/fs-test/folder1/file1c/child1", ChangeType.ADDED, "prop2");
}
@Test
@@ -199,10 +204,13 @@ public class FileMonitorTest {
}
- private void assertChange(List<ResourceChange> changes, int index, String path, ChangeType changeType) {
+ private void assertChange(List<ResourceChange> changes, int index, String path, ChangeType changeType, String... addedPropertyNames) {
ResourceChange change = changes.get(index);
assertEquals(path, change.getPath());
assertEquals(changeType, change.getType());
+ if (addedPropertyNames.length > 0) {
+ assertEquals(ImmutableSet.copyOf(addedPropertyNames), change.getAddedPropertyNames());
+ }
}
static class ResourceListener implements ResourceChangeListener {
Modified: sling/trunk/bundles/extensions/fsresource/src/test/java/org/apache/sling/fsprovider/internal/FilesFolderTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/fsresource/src/test/java/org/apache/sling/fsprovider/internal/FilesFolderTest.java?rev=1784324&r1=1784323&r2=1784324&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/fsresource/src/test/java/org/apache/sling/fsprovider/internal/FilesFolderTest.java (original)
+++ sling/trunk/bundles/extensions/fsresource/src/test/java/org/apache/sling/fsprovider/internal/FilesFolderTest.java Fri Feb 24 20:45:26 2017
@@ -65,6 +65,7 @@ public class FilesFolderTest {
assertFile(fsroot, "folder1/file1b.txt", "file1b");
assertFile(fsroot, "folder1/folder11/file11a.txt", "file11a");
assertFile(fsroot, "folder2/content.json", null);
+ assertFile(fsroot, "folder2/content/file2content.txt", "file2content");
}
@Test
Modified: sling/trunk/bundles/extensions/fsresource/src/test/java/org/apache/sling/fsprovider/internal/JsonContentTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/fsresource/src/test/java/org/apache/sling/fsprovider/internal/JsonContentTest.java?rev=1784324&r1=1784323&r2=1784324&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/fsresource/src/test/java/org/apache/sling/fsprovider/internal/JsonContentTest.java (original)
+++ sling/trunk/bundles/extensions/fsresource/src/test/java/org/apache/sling/fsprovider/internal/JsonContentTest.java Fri Feb 24 20:45:26 2017
@@ -38,6 +38,7 @@ import javax.jcr.PropertyIterator;
import javax.jcr.PropertyType;
import javax.jcr.RepositoryException;
import javax.jcr.Value;
+import javax.jcr.nodetype.NodeType;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ValueMap;
@@ -85,6 +86,7 @@ public class JsonContentTest {
assertFile(fsroot, "folder1/file1b.txt", "file1b");
assertFile(fsroot, "folder1/folder11/file11a.txt", "file11a");
assertNull(fsroot.getChild("folder2/content.json"));
+ assertFile(fsroot, "folder2/content/file2content.txt", "file2content");
}
@Test
@@ -144,11 +146,11 @@ public class JsonContentTest {
assertEquals("/fs-test/folder2/content/toolbar/profiles/jcr:content", node.getPath());
assertEquals(6, node.getDepth());
- assertTrue(node.isNodeType("app:PageContent"));
assertTrue(node.hasProperty("jcr:title"));
assertEquals(PropertyType.STRING, node.getProperty("jcr:title").getType());
assertFalse(node.getProperty("jcr:title").isMultiple());
+ assertEquals("jcr:title", node.getProperty("jcr:title").getDefinition().getName());
assertEquals("/fs-test/folder2/content/toolbar/profiles/jcr:content/jcr:title", node.getProperty("jcr:title").getPath());
assertEquals("Profiles", node.getProperty("jcr:title").getString());
assertEquals(PropertyType.BOOLEAN, node.getProperty("booleanProp").getType());
@@ -196,10 +198,27 @@ public class JsonContentTest {
Node parent = rightpar.getParent();
assertTrue(node.isSame(parent));
Node ancestor = (Node)rightpar.getAncestor(4);
- assertEquals(underTest.getParent().getPath(), ancestor.getPath());
+ assertEquals(underTest.getParent().getPath(), ancestor.getPath());
+
+ // node types
+ assertTrue(node.isNodeType("app:PageContent"));
+ assertEquals("app:PageContent", node.getPrimaryNodeType().getName());
+ assertFalse(node.getPrimaryNodeType().isMixin());
+ NodeType[] mixinTypes = node.getMixinNodeTypes();
+ assertEquals(2, mixinTypes.length);
+ assertEquals("type1", mixinTypes[0].getName());
+ assertEquals("type2", mixinTypes[1].getName());
+ assertTrue(mixinTypes[0].isMixin());
+ assertTrue(mixinTypes[1].isMixin());
}
@Test
+ public void testFallbackNodeType() throws RepositoryException {
+ Resource underTest = fsroot.getChild("folder2/content/jcr:content/par/title_2");
+ assertEquals(NodeType.NT_UNSTRUCTURED, underTest.adaptTo(Node.class).getPrimaryNodeType().getName());
+ }
+
+ @Test
public void testJsonContent_InvalidPath() {
Resource underTest = fsroot.getChild("folder2/content/jcr:content/xyz");
assertNull(underTest);
Modified: sling/trunk/bundles/extensions/fsresource/src/test/java/org/apache/sling/fsprovider/internal/mapper/ContentFileTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/fsresource/src/test/java/org/apache/sling/fsprovider/internal/mapper/ContentFileTest.java?rev=1784324&r1=1784323&r2=1784324&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/fsresource/src/test/java/org/apache/sling/fsprovider/internal/mapper/ContentFileTest.java (original)
+++ sling/trunk/bundles/extensions/fsresource/src/test/java/org/apache/sling/fsprovider/internal/mapper/ContentFileTest.java Fri Feb 24 20:45:26 2017
@@ -27,16 +27,19 @@ import java.io.File;
import java.util.Map;
import org.apache.sling.api.resource.ValueMap;
+import org.apache.sling.fsprovider.internal.parser.ContentFileCache;
import org.junit.Test;
public class ContentFileTest {
+
+ private ContentFileCache contentFileCache = new ContentFileCache(0);
@SuppressWarnings("unchecked")
@Test
public void testRootContent() {
File file = new File("src/test/resources/fs-test/folder2/content.json");
- ContentFile underTest = new ContentFile(file, null);
+ ContentFile underTest = new ContentFile(file, "/fs-test/folder2/content", null, contentFileCache);
assertEquals(file, underTest.getFile());
assertNull(underTest.getSubPath());
@@ -56,7 +59,7 @@ public class ContentFileTest {
public void testContentLevel1() {
File file = new File("src/test/resources/fs-test/folder2/content.json");
- ContentFile underTest = new ContentFile(file, "jcr:content");
+ ContentFile underTest = new ContentFile(file, "/fs-test/folder2/content", "jcr:content", contentFileCache);
assertEquals(file, underTest.getFile());
assertEquals("jcr:content", underTest.getSubPath());
@@ -74,7 +77,7 @@ public class ContentFileTest {
public void testContentLevel5() {
File file = new File("src/test/resources/fs-test/folder2/content.json");
- ContentFile underTest = new ContentFile(file, "jcr:content/par/image/file/jcr:content");
+ ContentFile underTest = new ContentFile(file, "/fs-test/folder2/content", "jcr:content/par/image/file/jcr:content", contentFileCache);
assertEquals(file, underTest.getFile());
assertEquals("jcr:content/par/image/file/jcr:content", underTest.getSubPath());
@@ -91,7 +94,7 @@ public class ContentFileTest {
public void testContentProperty() {
File file = new File("src/test/resources/fs-test/folder2/content.json");
- ContentFile underTest = new ContentFile(file, "jcr:content/jcr:title");
+ ContentFile underTest = new ContentFile(file, "/fs-test/folder2/content", "jcr:content/jcr:title", contentFileCache);
assertEquals(file, underTest.getFile());
assertEquals("jcr:content/jcr:title", underTest.getSubPath());
@@ -105,7 +108,7 @@ public class ContentFileTest {
@Test
public void testInvalidFile() {
File file = new File("src/test/resources/fs-test/folder1/file1a.txt");
- ContentFile underTest = new ContentFile(file, null);
+ ContentFile underTest = new ContentFile(file, "/fs-test/folder1/file1a", null, contentFileCache);
assertFalse(underTest.hasContent());
}
Added: sling/trunk/bundles/extensions/fsresource/src/test/java/org/apache/sling/fsprovider/internal/parser/ContentFileCacheTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/fsresource/src/test/java/org/apache/sling/fsprovider/internal/parser/ContentFileCacheTest.java?rev=1784324&view=auto
==============================================================================
--- sling/trunk/bundles/extensions/fsresource/src/test/java/org/apache/sling/fsprovider/internal/parser/ContentFileCacheTest.java (added)
+++ sling/trunk/bundles/extensions/fsresource/src/test/java/org/apache/sling/fsprovider/internal/parser/ContentFileCacheTest.java Fri Feb 24 20:45:26 2017
@@ -0,0 +1,92 @@
+/*
+ * 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.fsprovider.internal.parser;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import java.io.File;
+import java.util.Map;
+
+import org.junit.experimental.theories.DataPoint;
+import org.junit.experimental.theories.Theories;
+import org.junit.experimental.theories.Theory;
+import org.junit.runner.RunWith;
+
+@RunWith(Theories.class)
+public class ContentFileCacheTest {
+
+ @DataPoint
+ public static final int NO_CACHE = 0;
+ @DataPoint
+ public static final int SMALL_CACHE = 1;
+ @DataPoint
+ public static final int HUGE_CACHE = 1000;
+
+ @Theory
+ public void testCache(int cacheSize) {
+ ContentFileCache underTest = new ContentFileCache(cacheSize);
+
+ Map<String,Object> content1 = underTest.get("/fs-test/folder2/content", new File("src/test/resources/fs-test/folder2/content.json"));
+ assertNotNull(content1);
+
+ switch (cacheSize) {
+ case NO_CACHE:
+ assertEquals(0, underTest.size());
+ break;
+ case SMALL_CACHE:
+ case HUGE_CACHE:
+ assertEquals(1, underTest.size());
+ break;
+ }
+
+ Map<String,Object> content2 = underTest.get("/fs-test/folder1/file1a", new File("src/test/resources/fs-test/folder1/file1a.txt"));
+ assertNull(content2);
+
+ switch (cacheSize) {
+ case NO_CACHE:
+ assertEquals(0, underTest.size());
+ break;
+ case SMALL_CACHE:
+ assertEquals(1, underTest.size());
+ break;
+ case HUGE_CACHE:
+ assertEquals(2, underTest.size());
+ break;
+ }
+
+ underTest.remove("/fs-test/folder1/file1a");
+
+ switch (cacheSize) {
+ case NO_CACHE:
+ case SMALL_CACHE:
+ assertEquals(0, underTest.size());
+ break;
+ case HUGE_CACHE:
+ assertEquals(1, underTest.size());
+ break;
+ }
+
+ underTest.clear();
+
+ assertEquals(0, underTest.size());
+ }
+
+}
Propchange: sling/trunk/bundles/extensions/fsresource/src/test/java/org/apache/sling/fsprovider/internal/parser/ContentFileCacheTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: sling/trunk/bundles/extensions/fsresource/src/test/java/org/apache/sling/fsprovider/internal/parser/ContentFileCacheTest.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Fri Feb 24 20:45:26 2017
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author
Propchange: sling/trunk/bundles/extensions/fsresource/src/test/java/org/apache/sling/fsprovider/internal/parser/ContentFileCacheTest.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Modified: sling/trunk/bundles/extensions/fsresource/src/test/resources/fs-test/folder2/content.json
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/fsresource/src/test/resources/fs-test/folder2/content.json?rev=1784324&r1=1784323&r2=1784324&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/fsresource/src/test/resources/fs-test/folder2/content.json (original)
+++ sling/trunk/bundles/extensions/fsresource/src/test/resources/fs-test/folder2/content.json Fri Feb 24 20:45:26 2017
@@ -102,7 +102,6 @@
}
},
"title_2": {
- "jcr:primaryType": "nt:unstructured",
"jcr:createdBy": "admin",
"jcr:title": "Shape Technology",
"jcr:lastModifiedBy": "admin",
@@ -220,6 +219,7 @@
"jcr:created": "Thu Aug 07 2014 16:33:00 GMT+0200",
"jcr:content": {
"jcr:primaryType": "app:PageContent",
+ "jcr:mixinTypes": ["type1","type2"],
"jcr:createdBy": "admin",
"jcr:title": "Profiles",
"app:template": "/apps/sample/templates/contentpage",
Added: sling/trunk/bundles/extensions/fsresource/src/test/resources/fs-test/folder2/content/file2content.txt
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/fsresource/src/test/resources/fs-test/folder2/content/file2content.txt?rev=1784324&view=auto
==============================================================================
--- sling/trunk/bundles/extensions/fsresource/src/test/resources/fs-test/folder2/content/file2content.txt (added)
+++ sling/trunk/bundles/extensions/fsresource/src/test/resources/fs-test/folder2/content/file2content.txt Fri Feb 24 20:45:26 2017
@@ -0,0 +1 @@
+file2content
\ No newline at end of file
Propchange: sling/trunk/bundles/extensions/fsresource/src/test/resources/fs-test/folder2/content/file2content.txt
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: sling/trunk/bundles/extensions/fsresource/src/test/resources/fs-test/folder2/content/file2content.txt
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Fri Feb 24 20:45:26 2017
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author
Propchange: sling/trunk/bundles/extensions/fsresource/src/test/resources/fs-test/folder2/content/file2content.txt
------------------------------------------------------------------------------
svn:mime-type = text/plain