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/28 15:40:57 UTC
svn commit: r1784765 [1/5] - in /sling/branches/fsresource-1.1.x: ./
src/main/java/org/apache/sling/fsprovider/internal/
src/main/java/org/apache/sling/fsprovider/internal/mapper/
src/main/java/org/apache/sling/fsprovider/internal/mapper/jcr/ src/main/...
Author: sseifert
Date: Tue Feb 28 15:40:56 2017
New Revision: 1784765
URL: http://svn.apache.org/viewvc?rev=1784765&view=rev
Log:
backport of changes from SLING-6440 and SLING-6537 to 1.1.x version of fsresource based on old resource provider SPI
Added:
sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/ContentFileExtensions.java (with props)
sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/FsResourceMapper.java (with props)
sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/mapper/
sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/mapper/ContentFile.java (with props)
sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/mapper/ContentFileResource.java (with props)
sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/mapper/ContentFileResourceMapper.java (with props)
sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/mapper/FileResource.java (with props)
sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/mapper/FileResourceMapper.java (with props)
sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/mapper/ValueMapUtil.java (with props)
sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/mapper/jcr/
sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/mapper/jcr/FsItem.java (with props)
sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/mapper/jcr/FsNode.java (with props)
sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/mapper/jcr/FsNodeIterator.java (with props)
sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/mapper/jcr/FsNodeType.java (with props)
sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/mapper/jcr/FsProperty.java (with props)
sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/mapper/jcr/FsPropertyDefinition.java (with props)
sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/mapper/jcr/FsPropertyIterator.java (with props)
sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/mapper/jcr/FsValue.java (with props)
sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/parser/
sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/parser/ContentFileCache.java (with props)
sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/parser/ContentFileParser.java (with props)
sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/parser/ContentFileTypes.java (with props)
sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/parser/JcrXmlFileParser.java (with props)
sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/parser/JcrXmlValueConverter.java (with props)
sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/parser/JsonFileParser.java (with props)
sling/branches/fsresource-1.1.x/src/test/
sling/branches/fsresource-1.1.x/src/test/java/
sling/branches/fsresource-1.1.x/src/test/java/org/
sling/branches/fsresource-1.1.x/src/test/java/org/apache/
sling/branches/fsresource-1.1.x/src/test/java/org/apache/sling/
sling/branches/fsresource-1.1.x/src/test/java/org/apache/sling/fsprovider/
sling/branches/fsresource-1.1.x/src/test/java/org/apache/sling/fsprovider/internal/
sling/branches/fsresource-1.1.x/src/test/java/org/apache/sling/fsprovider/internal/FileMonitorTest.java (with props)
sling/branches/fsresource-1.1.x/src/test/java/org/apache/sling/fsprovider/internal/FilesFolderTest.java (with props)
sling/branches/fsresource-1.1.x/src/test/java/org/apache/sling/fsprovider/internal/InvalidRootFolderTest.java (with props)
sling/branches/fsresource-1.1.x/src/test/java/org/apache/sling/fsprovider/internal/JcrMixedTest.java (with props)
sling/branches/fsresource-1.1.x/src/test/java/org/apache/sling/fsprovider/internal/JcrXmlContentTest.java (with props)
sling/branches/fsresource-1.1.x/src/test/java/org/apache/sling/fsprovider/internal/JsonContentTest.java (with props)
sling/branches/fsresource-1.1.x/src/test/java/org/apache/sling/fsprovider/internal/TestUtils.java (with props)
sling/branches/fsresource-1.1.x/src/test/java/org/apache/sling/fsprovider/internal/mapper/
sling/branches/fsresource-1.1.x/src/test/java/org/apache/sling/fsprovider/internal/mapper/ContentFileTest.java (with props)
sling/branches/fsresource-1.1.x/src/test/java/org/apache/sling/fsprovider/internal/mapper/ValueMapUtilTest.java (with props)
sling/branches/fsresource-1.1.x/src/test/java/org/apache/sling/fsprovider/internal/parser/
sling/branches/fsresource-1.1.x/src/test/java/org/apache/sling/fsprovider/internal/parser/ContentFileCacheTest.java (with props)
sling/branches/fsresource-1.1.x/src/test/java/org/apache/sling/fsprovider/internal/parser/ContentFileParserTest.java (with props)
sling/branches/fsresource-1.1.x/src/test/java/org/apache/sling/fsprovider/internal/parser/JcrXmlFileParserTest.java (with props)
sling/branches/fsresource-1.1.x/src/test/java/org/apache/sling/fsprovider/internal/parser/JcrXmlValueConverterTest.java (with props)
sling/branches/fsresource-1.1.x/src/test/resources/
sling/branches/fsresource-1.1.x/src/test/resources/fs-test/
sling/branches/fsresource-1.1.x/src/test/resources/fs-test/folder1/
sling/branches/fsresource-1.1.x/src/test/resources/fs-test/folder1/file1a.txt (with props)
sling/branches/fsresource-1.1.x/src/test/resources/fs-test/folder1/file1b.txt (with props)
sling/branches/fsresource-1.1.x/src/test/resources/fs-test/folder1/folder11/
sling/branches/fsresource-1.1.x/src/test/resources/fs-test/folder1/folder11/file11a.txt (with props)
sling/branches/fsresource-1.1.x/src/test/resources/fs-test/folder2/
sling/branches/fsresource-1.1.x/src/test/resources/fs-test/folder2/content/
sling/branches/fsresource-1.1.x/src/test/resources/fs-test/folder2/content.json (with props)
sling/branches/fsresource-1.1.x/src/test/resources/fs-test/folder2/content/content2.json (with props)
sling/branches/fsresource-1.1.x/src/test/resources/fs-test/folder2/content/file2content.txt (with props)
sling/branches/fsresource-1.1.x/src/test/resources/fs-test/folder2/folder21/
sling/branches/fsresource-1.1.x/src/test/resources/fs-test/folder2/folder21/file21a.txt (with props)
sling/branches/fsresource-1.1.x/src/test/resources/fs-test/folder3/
sling/branches/fsresource-1.1.x/src/test/resources/fs-test/folder3/content/
sling/branches/fsresource-1.1.x/src/test/resources/fs-test/folder3/content.jcr.xml (with props)
sling/branches/fsresource-1.1.x/src/test/resources/fs-test/folder3/content/content2.jcr.xml (with props)
sling/branches/fsresource-1.1.x/src/test/resources/fs-test/folder3/folder31/
sling/branches/fsresource-1.1.x/src/test/resources/fs-test/folder3/folder31/file31a.txt (with props)
sling/branches/fsresource-1.1.x/src/test/resources/invalid-test/
sling/branches/fsresource-1.1.x/src/test/resources/invalid-test/invalid.jcr.xml (with props)
sling/branches/fsresource-1.1.x/src/test/resources/invalid-test/invalid.json (with props)
sling/branches/fsresource-1.1.x/src/test/resources/simplelogger.properties (with props)
sling/branches/fsresource-1.1.x/src/test/resources/vaultfs-test/
sling/branches/fsresource-1.1.x/src/test/resources/vaultfs-test/META-INF/
sling/branches/fsresource-1.1.x/src/test/resources/vaultfs-test/META-INF/vault/
sling/branches/fsresource-1.1.x/src/test/resources/vaultfs-test/META-INF/vault/filter.xml (with props)
sling/branches/fsresource-1.1.x/src/test/resources/vaultfs-test/META-INF/vault/settings.xml (with props)
sling/branches/fsresource-1.1.x/src/test/resources/vaultfs-test/jcr_root/
sling/branches/fsresource-1.1.x/src/test/resources/vaultfs-test/jcr_root/.content.xml (with props)
sling/branches/fsresource-1.1.x/src/test/resources/vaultfs-test/jcr_root/content/
sling/branches/fsresource-1.1.x/src/test/resources/vaultfs-test/jcr_root/content/.content.xml (with props)
sling/branches/fsresource-1.1.x/src/test/resources/vaultfs-test/jcr_root/content/dam/
sling/branches/fsresource-1.1.x/src/test/resources/vaultfs-test/jcr_root/content/dam/.content.xml (with props)
sling/branches/fsresource-1.1.x/src/test/resources/vaultfs-test/jcr_root/content/dam/talk.png/
sling/branches/fsresource-1.1.x/src/test/resources/vaultfs-test/jcr_root/content/dam/talk.png/.content.xml (with props)
sling/branches/fsresource-1.1.x/src/test/resources/vaultfs-test/jcr_root/content/dam/talk.png/_jcr_content/
sling/branches/fsresource-1.1.x/src/test/resources/vaultfs-test/jcr_root/content/dam/talk.png/_jcr_content/renditions/
sling/branches/fsresource-1.1.x/src/test/resources/vaultfs-test/jcr_root/content/dam/talk.png/_jcr_content/renditions/original (with props)
sling/branches/fsresource-1.1.x/src/test/resources/vaultfs-test/jcr_root/content/dam/talk.png/_jcr_content/renditions/original.dir/
sling/branches/fsresource-1.1.x/src/test/resources/vaultfs-test/jcr_root/content/dam/talk.png/_jcr_content/renditions/original.dir/.content.xml (with props)
sling/branches/fsresource-1.1.x/src/test/resources/vaultfs-test/jcr_root/content/dam/talk.png/_jcr_content/renditions/web.1280.1280.png (with props)
sling/branches/fsresource-1.1.x/src/test/resources/vaultfs-test/jcr_root/content/samples/
sling/branches/fsresource-1.1.x/src/test/resources/vaultfs-test/jcr_root/content/samples/.content.xml (with props)
sling/branches/fsresource-1.1.x/src/test/resources/vaultfs-test/jcr_root/content/samples/en/
sling/branches/fsresource-1.1.x/src/test/resources/vaultfs-test/jcr_root/content/samples/en/.content.xml (with props)
sling/branches/fsresource-1.1.x/src/test/resources/vaultfs-test/jcr_root/content/samples/en/conference/
sling/branches/fsresource-1.1.x/src/test/resources/vaultfs-test/jcr_root/content/samples/en/conference/.content.xml (with props)
sling/branches/fsresource-1.1.x/src/test/resources/vaultfs-test/jcr_root/content/samples/en/tools/
sling/branches/fsresource-1.1.x/src/test/resources/vaultfs-test/jcr_root/content/samples/en/tools/.content.xml (with props)
sling/branches/fsresource-1.1.x/src/test/resources/vaultfs-test/jcr_root/content/samples/en/tools/navigation/
sling/branches/fsresource-1.1.x/src/test/resources/vaultfs-test/jcr_root/content/samples/en/tools/navigation/.content.xml (with props)
Removed:
sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/FsResource.java
sling/branches/fsresource-1.1.x/src/main/resources/
Modified:
sling/branches/fsresource-1.1.x/pom.xml
sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/FileMonitor.java
sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/FsResourceProvider.java
Modified: sling/branches/fsresource-1.1.x/pom.xml
URL: http://svn.apache.org/viewvc/sling/branches/fsresource-1.1.x/pom.xml?rev=1784765&r1=1784764&r2=1784765&view=diff
==============================================================================
--- sling/branches/fsresource-1.1.x/pom.xml (original)
+++ sling/branches/fsresource-1.1.x/pom.xml Tue Feb 28 15:40:56 2017
@@ -22,8 +22,8 @@
<parent>
<groupId>org.apache.sling</groupId>
<artifactId>sling</artifactId>
- <version>26</version>
- <relativePath/>
+ <version>29</version>
+ <relativePath />
</parent>
<artifactId>org.apache.sling.fsresource</artifactId>
@@ -41,17 +41,10 @@
<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>
</scm>
-
+
<build>
<plugins>
<plugin>
- <groupId>org.apache.felix</groupId>
- <artifactId>maven-scr-plugin</artifactId>
- <configuration>
- <specVersion>1.1</specVersion>
- </configuration>
- </plugin>
- <plugin>
<groupId>org.apache.sling</groupId>
<artifactId>maven-sling-plugin</artifactId>
<executions>
@@ -68,25 +61,60 @@
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
+ <executions>
+ <!-- Configure extra execution of 'manifest' in process-classes phase to make sure SCR metadata is generated before unit test runs -->
+ <execution>
+ <id>scr-metadata</id>
+ <goals>
+ <goal>manifest</goal>
+ </goals>
+ <configuration>
+ <supportIncrementalBuild>true</supportIncrementalBuild>
+ </configuration>
+ </execution>
+ </executions>
<configuration>
+ <!-- Export SCR metadata to classpath to have them available in unit tests -->
+ <exportScr>true</exportScr>
<instructions>
- <Private-Package>
- org.apache.sling.fsprovider.internal
- </Private-Package>
+ <!-- Embed Apache Johnzon -->
+ <Embed-Dependency>
+ johnzon-core;scope=compile;inline=false,
+ geronimo-json_1.0_spec;scope=compile;inline=false
+ </Embed-Dependency>
+ <!-- Embed the nessecary parts of the jackrabbit-jcr-commons bundle as described in http://njbartlett.name/2014/05/26/static-linking.html -->
+ <Conditional-Package>org.apache.jackrabbit.util</Conditional-Package>
+ <Import-Package>
+ !org.apache.jackrabbit.*,
+ *
+ </Import-Package>
</instructions>
</configuration>
</plugin>
+ <plugin>
+ <groupId>org.apache.rat</groupId>
+ <artifactId>apache-rat-plugin</artifactId>
+ <configuration>
+ <excludes>
+ <exclude>src/test/resources/fs-test/**</exclude>
+ <exclude>src/test/resources/invalid-test/**</exclude>
+ <exclude>src/test/resources/vaultfs-test/**/original</exclude>
+ </excludes>
+ </configuration>
+ </plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
+ <version>2.4</version>
+ <scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.sling</groupId>
<artifactId>org.apache.sling.api</artifactId>
- <version>2.3.0</version>
+ <version>2.4.0</version>
</dependency>
<dependency>
<groupId>org.apache.sling</groupId>
@@ -95,19 +123,41 @@
</dependency>
<dependency>
<groupId>org.osgi</groupId>
- <artifactId>org.osgi.core</artifactId>
+ <artifactId>osgi.core</artifactId>
</dependency>
<dependency>
<groupId>org.osgi</groupId>
- <artifactId>org.osgi.compendium</artifactId>
+ <artifactId>osgi.cmpn</artifactId>
</dependency>
<dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>slf4j-api</artifactId>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-lang3</artifactId>
+ <version>3.3.2</version>
+ <scope>compile</scope>
</dependency>
<dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
+ <groupId>commons-collections</groupId>
+ <artifactId>commons-collections</artifactId>
+ <version>3.2.1</version>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.johnzon</groupId>
+ <artifactId>johnzon-core</artifactId>
+ <version>1.0.0</version>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.geronimo.specs</groupId>
+ <artifactId>geronimo-json_1.0_spec</artifactId>
+ <version>1.0-alpha-1</version>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.jackrabbit</groupId>
+ <artifactId>jackrabbit-jcr-commons</artifactId>
+ <version>2.8.0</version>
+ <scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.sling</groupId>
@@ -116,9 +166,33 @@
<scope>provided</scope>
</dependency>
<dependency>
- <groupId>org.apache.felix</groupId>
- <artifactId>org.apache.felix.scr.annotations</artifactId>
- <scope>compile</scope>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.sling</groupId>
+ <artifactId>org.apache.sling.testing.sling-mock</artifactId>
+ <version>1.9.4</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.sling</groupId>
+ <artifactId>org.apache.sling.testing.osgi-mock</artifactId>
+ <version>2.2.2</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.sling</groupId>
+ <artifactId>org.apache.sling.testing.logging-mock</artifactId>
+ <version>1.0.0</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.sling</groupId>
+ <artifactId>org.apache.sling.testing.hamcrest</artifactId>
+ <version>1.0.2</version>
+ <scope>test</scope>
</dependency>
</dependencies>
</project>
Added: sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/ContentFileExtensions.java
URL: http://svn.apache.org/viewvc/sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/ContentFileExtensions.java?rev=1784765&view=auto
==============================================================================
--- sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/ContentFileExtensions.java (added)
+++ sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/ContentFileExtensions.java Tue Feb 28 15:40:56 2017
@@ -0,0 +1,75 @@
+/*
+ * 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;
+
+import java.io.File;
+import java.util.Collection;
+import java.util.List;
+
+import org.apache.commons.lang3.StringUtils;
+
+/**
+ * Matches file names for content file extensions.
+ */
+public final class ContentFileExtensions {
+
+ private final List<String> contentFileSuffixes;
+
+ public ContentFileExtensions(List<String> contentFileSuffixes) {
+ this.contentFileSuffixes = contentFileSuffixes;
+ }
+
+ /**
+ * Get suffix from file name.
+ * @param file File
+ * @return Content file name suffix or null if not a context file.
+ */
+ public String getSuffix(File file) {
+ for (String suffix : contentFileSuffixes) {
+ if (StringUtils.endsWith(file.getName(), suffix)) {
+ return suffix;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Checks suffix from file name.
+ * @param file File
+ * @return true if content file
+ */
+ public boolean matchesSuffix(File file) {
+ return getSuffix(file) != null;
+ }
+
+ /**
+ * @return Content file suffixes.
+ */
+ public Collection<String> getSuffixes() {
+ return contentFileSuffixes;
+ }
+
+ /**
+ * @return true if not suffixes are defined.
+ */
+ public boolean isEmpty() {
+ return contentFileSuffixes.isEmpty();
+ }
+
+}
Propchange: sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/ContentFileExtensions.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/ContentFileExtensions.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Tue Feb 28 15:40:56 2017
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author
Propchange: sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/ContentFileExtensions.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Modified: sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/FileMonitor.java
URL: http://svn.apache.org/viewvc/sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/FileMonitor.java?rev=1784765&r1=1784764&r2=1784765&view=diff
==============================================================================
--- sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/FileMonitor.java (original)
+++ sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/FileMonitor.java Tue Feb 28 15:40:56 2017
@@ -19,12 +19,21 @@
package org.apache.sling.fsprovider.internal;
import java.io.File;
+import java.util.ArrayList;
import java.util.Dictionary;
+import java.util.HashSet;
import java.util.Hashtable;
+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.SlingConstants;
+import org.apache.sling.fsprovider.internal.mapper.ContentFile;
+import org.apache.sling.fsprovider.internal.mapper.FileResource;
+import org.apache.sling.fsprovider.internal.parser.ContentFileCache;
import org.osgi.service.event.EventAdmin;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -33,10 +42,9 @@ import org.slf4j.LoggerFactory;
* This class is a monitor for the file system
* that periodically checks for changes.
*/
-public class FileMonitor extends TimerTask {
+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;
@@ -45,17 +53,23 @@ public class FileMonitor extends TimerTa
private final Monitorable root;
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) {
+ public FileMonitor(final FsResourceProvider provider, final long interval,
+ final ContentFileExtensions contentFileExtensions, final ContentFileCache contentFileCache) {
this.provider = provider;
- this.root = new Monitorable(this.provider.getProviderRoot(), this.provider.getRootFile());
- createStatus(this.root);
- logger.debug("Starting file monitor for {} with an interval of {}ms", this.root.file, interval);
+ this.contentFileExtensions = contentFileExtensions;
+ this.contentFileCache = contentFileCache;
+ this.root = new Monitorable(this.provider.getProviderRoot(), this.provider.getRootFile(), null);
+ 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);
}
@@ -85,12 +99,13 @@ public class FileMonitor extends TimerTa
Thread.currentThread().interrupt();
}
}
- logger.debug("Stopped file monitor for {}", this.root.file);
+ log.debug("Stopped file monitor for {}", this.root.file);
}
/**
* @see java.util.TimerTask#run()
*/
+ @Override
public void run() {
synchronized (timer) {
stopped = false;
@@ -123,24 +138,21 @@ public class FileMonitor extends TimerTa
* @param localEA The event admin
*/
private void check(final Monitorable monitorable, final EventAdmin localEA) {
- 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);
- sendEvents(monitorable,
- SlingConstants.TOPIC_RESOURCE_ADDED,
- localEA);
+ createStatus(monitorable, contentFileExtensions, contentFileCache);
+ sendEvents(monitorable, SlingConstants.TOPIC_RESOURCE_ADDED, localEA);
}
} else {
// check if the file has been removed
if ( !monitorable.file.exists() ) {
// removed file and update status
- sendEvents(monitorable,
- SlingConstants.TOPIC_RESOURCE_REMOVED,
- localEA);
+ sendEvents(monitorable, SlingConstants.TOPIC_RESOURCE_REMOVED, localEA);
monitorable.status = NonExistingStatus.SINGLETON;
+ contentFileCache.remove(monitorable.path);
} else {
// check for changes
final FileStatus fs = (FileStatus)monitorable.status;
@@ -148,10 +160,9 @@ public class FileMonitor extends TimerTa
if ( fs.lastModified < monitorable.file.lastModified() ) {
fs.lastModified = monitorable.file.lastModified();
// changed
- sendEvents(monitorable,
- SlingConstants.TOPIC_RESOURCE_CHANGED,
- localEA);
+ sendEvents(monitorable, SlingConstants.TOPIC_RESOURCE_CHANGED, localEA);
changed = true;
+ contentFileCache.remove(monitorable.path);
}
if ( fs instanceof DirStatus ) {
// directory
@@ -174,9 +185,8 @@ public class FileMonitor extends TimerTa
}
}
if (children[i] == null) {
- children[i] = new Monitorable(
- monitorable.path + '/'
- + files[i].getName(), files[i]);
+ children[i] = new Monitorable(monitorable.path + '/' + files[i].getName(), files[i],
+ contentFileExtensions.getSuffix(files[i]));
children[i].status = NonExistingStatus.SINGLETON;
check(children[i], localEA);
}
@@ -195,40 +205,112 @@ public class FileMonitor extends TimerTa
* Send the event async via the event admin.
*/
private void sendEvents(final Monitorable monitorable, final String topic, final EventAdmin localEA) {
- if ( logger.isDebugEnabled() ) {
- logger.debug("Detected change for resource {} : {}", monitorable.path, topic);
+ if (log.isDebugEnabled()) {
+ log.debug("Detected change for resource {} : {}", monitorable.path, topic);
}
- final Dictionary<String, String> properties = new Hashtable<String, String>();
- properties.put(SlingConstants.PROPERTY_PATH, monitorable.path);
- final String type = monitorable.status instanceof FileStatus ?
- FsResource.RESOURCE_TYPE_FILE : FsResource.RESOURCE_TYPE_FOLDER;
- properties.put(SlingConstants.PROPERTY_RESOURCE_TYPE, type);
- localEA.postEvent(new org.osgi.service.event.Event(topic, properties));
+ List<ResourceChange> changes = collectResourceChanges(monitorable, topic);
+ for (ResourceChange change : changes) {
+ if (log.isTraceEnabled()) {
+ log.debug("Send change for resource {}: {}", change.path, change.topic);
+ }
+ final Dictionary<String, String> properties = new Hashtable<String, String>();
+ properties.put(SlingConstants.PROPERTY_PATH, change.path);
+ if (change.resourceType != null) {
+ properties.put(SlingConstants.PROPERTY_RESOURCE_TYPE, change.resourceType);
+ }
+ localEA.postEvent(new org.osgi.service.event.Event(change.topic, properties));
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private List<ResourceChange> collectResourceChanges(final Monitorable monitorable, final String topic) {
+ List<ResourceChange> changes = new ArrayList<>();
+ if (monitorable.status instanceof ContentFileStatus) {
+ ContentFile contentFile = ((ContentFileStatus)monitorable.status).contentFile;
+ if (StringUtils.equals(topic, SlingConstants.TOPIC_RESOURCE_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(SlingConstants.TOPIC_RESOURCE_REMOVED, content, monitorable.path));
+ addContentResourceChanges(changes, SlingConstants.TOPIC_RESOURCE_ADDED, content, monitorable.path);
+ }
+ else {
+ addContentResourceChanges(changes, topic, (Map<String,Object>)contentFile.getContent(), monitorable.path);
+ }
+ }
+ else {
+ ResourceChange change = new ResourceChange();
+ change.path = monitorable.path;
+ change.resourceType = monitorable.status instanceof FileStatus ?
+ FileResource.RESOURCE_TYPE_FILE : FileResource.RESOURCE_TYPE_FOLDER;
+ change.topic = topic;
+ changes.add(change);
+ }
+ return changes;
+ }
+ @SuppressWarnings("unchecked")
+ private void addContentResourceChanges(final List<ResourceChange> changes, final String topic,
+ final Map<String,Object> content, final String path) {
+ changes.add(buildContentResourceChange(topic, 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, topic, (Map<String,Object>)entry.getValue(), childPath);
+ }
+ }
+ }
+ }
+ private ResourceChange buildContentResourceChange(final String topic, final Map<String,Object> content, final String path) {
+ Set<String> addedPropertyNames = null;
+ if (content != null && topic == SlingConstants.TOPIC_RESOURCE_ADDED) {
+ addedPropertyNames = new HashSet<>();
+ for (Map.Entry<String,Object> entry : content.entrySet()) {
+ if (!(entry.getValue() instanceof Map)) {
+ addedPropertyNames.add(entry.getKey());
+ }
+ }
+ }
+ ResourceChange change = new ResourceChange();
+ change.path = path;
+ change.resourceType = content != null ? (String)content.get("sling:resourceType") : null;
+ change.topic = topic;
+ return change;
}
/**
* Create a status object for the monitorable
*/
- private static void createStatus(final Monitorable monitorable) {
+ 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);
+ monitorable.status = new DirStatus(monitorable.file, monitorable.path, contentFileExtensions, contentFileCache);
}
}
/** The monitorable to hold the resource path, the file and the status. */
private static final class Monitorable {
public final String path;
- public final File file;
+ public final File file;
public Object status;
-
- public Monitorable(final String path, final File file) {
- this.path = path;
+ public Monitorable(final String path, final File file, String contentFileSuffix) {
this.file = file;
+ if (contentFileSuffix != null) {
+ this.path = StringUtils.substringBeforeLast(path, contentFileSuffix);
+ }
+ else {
+ this.path = path;
+ }
}
}
@@ -239,20 +321,30 @@ public class FileMonitor extends TimerTa
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) {
+ public DirStatus(final File dir, final String path,
+ final ContentFileExtensions contentFileExtensions, final ContentFileCache contentFileCache) {
super(dir);
final File[] files = dir.listFiles();
if (files != null) {
this.children = new Monitorable[files.length];
for (int i = 0; i < files.length; i++) {
- this.children[i] = new Monitorable(path + '/'
- + files[i].getName(), files[i]);
- FileMonitor.createStatus(this.children[i]);
+ this.children[i] = new Monitorable(path + '/' + files[i].getName(), files[i],
+ contentFileExtensions.getSuffix(files[i]));
+ FileMonitor.createStatus(this.children[i], contentFileExtensions, contentFileCache);
}
} else {
this.children = new Monitorable[0];
@@ -264,4 +356,11 @@ public class FileMonitor extends TimerTa
private static final class NonExistingStatus {
public static NonExistingStatus SINGLETON = new NonExistingStatus();
}
-}
\ No newline at end of file
+
+ static class ResourceChange {
+ public String path;
+ public String resourceType;
+ public String topic;
+ }
+
+}
Added: sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/FsResourceMapper.java
URL: http://svn.apache.org/viewvc/sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/FsResourceMapper.java?rev=1784765&view=auto
==============================================================================
--- sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/FsResourceMapper.java (added)
+++ sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/FsResourceMapper.java Tue Feb 28 15:40:56 2017
@@ -0,0 +1,47 @@
+/*
+ * 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;
+
+import java.util.Iterator;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceResolver;
+
+/**
+ * Maps files to resources.
+ */
+public interface FsResourceMapper {
+
+ /**
+ * Get single resource.
+ * @param resolver Resource resolver
+ * @param resourcePath Resource path
+ * @return Resource or null if not exists
+ */
+ Resource getResource(ResourceResolver resolver, String resourcePath);
+
+ /**
+ * Get children of resource.
+ * @param resolver Resource resolver.
+ * @param parent Parent resource.
+ * @return Child resources or null if no children exist
+ */
+ Iterator<Resource> getChildren(ResourceResolver resolver, Resource parent);
+
+}
Propchange: sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/FsResourceMapper.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/FsResourceMapper.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Tue Feb 28 15:40:56 2017
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author
Propchange: sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/FsResourceMapper.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Modified: sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/FsResourceProvider.java
URL: http://svn.apache.org/viewvc/sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/FsResourceProvider.java?rev=1784765&r1=1784764&r2=1784765&view=diff
==============================================================================
--- sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/FsResourceProvider.java (original)
+++ sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/FsResourceProvider.java Tue Feb 28 15:40:56 2017
@@ -19,101 +19,135 @@
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.Iterator;
-import java.util.Map;
-import java.util.NoSuchElementException;
+import java.util.List;
+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.commons.collections.IteratorUtils;
+import org.apache.commons.collections.Predicate;
+import org.apache.commons.lang3.StringUtils;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceProvider;
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.ContentFileCache;
+import org.apache.sling.fsprovider.internal.parser.ContentFileTypes;
import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.ConfigurationPolicy;
+import org.osgi.service.component.annotations.Deactivate;
+import org.osgi.service.component.annotations.Reference;
+import org.osgi.service.component.annotations.ReferenceCardinality;
+import org.osgi.service.component.annotations.ReferencePolicy;
import org.osgi.service.event.EventAdmin;
+import org.osgi.service.metatype.annotations.AttributeDefinition;
+import org.osgi.service.metatype.annotations.Designate;
+import org.osgi.service.metatype.annotations.ObjectClassDefinition;
/**
* The <code>FsResourceProvider</code> is a resource provider which maps
- * filesystem files and folders into the virtual resource tree. The provider is
+ * file system files and folders into the virtual resource tree. The provider is
* implemented in terms of a component factory, that is multiple instances of
* this provider may be created by creating respective configuration.
* <p>
* Each provider instance is configured with two properties: The location in the
- * resource tree where resources are provided ({@link ResourceProvider#ROOTS})
+ * resource tree where resources are provided (provider.root)
* and the file system path from where files and folders are mapped into the
- * resource ({@link #PROP_PROVIDER_FILE}).
+ * resource (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),
- @Property(name = "webconsole.configurationFactory.nameHint",
- value = "Root paths: {" + ResourceProvider.ROOTS + "}")
-})
-public class FsResourceProvider implements ResourceProvider {
-
- /**
- * 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";
-
- public static final long DEFAULT_CHECKINTERVAL = 1000;
+@Component(name="org.apache.sling.fsprovider.internal.FsResourceProvider",
+ service=ResourceProvider.class,
+ configurationPolicy=ConfigurationPolicy.REQUIRE,
+ property={
+ Constants.SERVICE_DESCRIPTION + "=Sling Filesystem Resource Provider",
+ Constants.SERVICE_VENDOR + "=The Apache Software Foundation"
+ })
+@Designate(ocd=FsResourceProvider.Config.class, factory=true)
+public final class FsResourceProvider implements ResourceProvider {
+
+ @ObjectClassDefinition(name = "Apache Sling Filesystem Resource Provider",
+ description = "Configure an instance of the filesystem " +
+ "resource provider in terms of provider root and filesystem location")
+ public @interface Config {
+ /**
+ * The name of the configuration property providing file system path of
+ * files and folders mapped into the resource tree (value is
+ * "provider.file").
+ */
+ @AttributeDefinition(name = "Filesystem Root",
+ description = "Filesystem directory mapped to the virtual " +
+ "resource tree. This property must not be an empty string. If the path is " +
+ "relative it is resolved against sling.home or the current working directory. " +
+ "The path may be a file or folder. If the path does not address an existing " +
+ "file or folder, an empty folder is created.")
+ String provider_file();
+
+ /**
+ * The name of the configuration property providing the check interval
+ * for file changes (value is "provider.checkinterval").
+ */
+ @AttributeDefinition(name = "Check Interval",
+ description = "If the interval has a value higher than 100, the provider will " +
+ "check the file system for changes periodically. This interval defines the period in milliseconds " +
+ "(the default is 1000). If a change is detected, resource events are sent through the event admin.")
+ long provider_checkinterval() default 1000;
+
+ @AttributeDefinition(name = "Provider Roots",
+ description = "Locations in the virtual resource tree where the " +
+ "filesystem resources are mapped in. This property must contain at least one non-empty string.")
+ String[] provider_roots();
+
+ @AttributeDefinition(name = "Mount json",
+ description = "Mount .json files as content in the resource hierarchy.")
+ boolean provider_json_content();
+
+ @AttributeDefinition(name = "Mount jcr.xml",
+ description = "Mount .jcr.xml files as content in the resource hierarchy.")
+ boolean provider_jcrxml_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.
+ */
+ String webconsole_configurationFactory_nameHint() default "Root paths: {" + ResourceProvider.ROOTS + "}";
+ }
// The location in the resource tree where the resources are mapped
private String providerRoot;
- // providerRoot + "/" to be used for prefix matching of paths
- private String providerRootPrefix;
-
// The "root" file or folder in the file system
private File providerFile;
- /** The monitor to detect file changes. */
+ // The monitor to detect file changes.
private FileMonitor monitor;
+
+ // maps filesystem to resources
+ private FsResourceMapper fileMapper;
+ private FsResourceMapper contentFileMapper;
+
+ // cache for parsed content files
+ private ContentFileCache contentFileCache;
- @Reference(cardinality=ReferenceCardinality.OPTIONAL_UNARY, policy=ReferencePolicy.DYNAMIC)
+ @Reference(cardinality=ReferenceCardinality.OPTIONAL, policy=ReferencePolicy.DYNAMIC)
private volatile EventAdmin eventAdmin;
-
- /**
- * Same as {@link #getResource(ResourceResolver, String)}, i.e. the
- * <code>request</code> parameter is ignored.
- *
- * @see #getResource(ResourceResolver, String)
- */
- public Resource getResource(ResourceResolver resourceResolver,
- HttpServletRequest request, String path) {
+
+ @Override
+ public Resource getResource(ResourceResolver resourceResolver, HttpServletRequest request, String path) {
return getResource(resourceResolver, path);
}
/**
- * Returns a resource wrapping a filesystem file or folder for the given
+ * Returns a resource wrapping a file system file or folder for the given
* path. If the <code>path</code> is equal to the configured resource tree
* location of this provider, the configured file system file or folder is
* used for the resource. Otherwise the configured resource tree location
@@ -121,130 +155,107 @@ public class FsResourceProvider implemen
* to access the file or folder. If no such file or folder exists, this
* method returns <code>null</code>.
*/
- public Resource getResource(ResourceResolver resourceResolver, String path) {
- return getResource(resourceResolver, path, getFile(path));
+ @Override
+ public Resource getResource(ResourceResolver resolver, String path) {
+ Resource rsrc = contentFileMapper.getResource(resolver, path);
+ if (rsrc == null) {
+ rsrc = fileMapper.getResource(resolver, path);
+ }
+ return rsrc;
}
-
+
/**
* Returns an iterator of resources.
*/
+ @SuppressWarnings("unchecked")
+ @Override
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) {
- // if the parent path is at or below the provider root, get
- // the respective file
- parentFile = 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) {
-
- String parentPath = parent.getPath().concat("/");
- if (providerRoot.startsWith(parentPath)) {
- String relPath = providerRoot.substring(parentPath.length());
- if (relPath.indexOf('/') < 0) {
- Resource res = getResource(
- parent.getResourceResolver(), providerRoot,
- providerFile);
- if (res != null) {
- return Collections.singletonList(res).iterator();
- }
- }
- }
-
- // no children here
- return null;
- }
- }
-
- final File[] children = parentFile.listFiles();
-
- if (children != null && children.length > 0) {
- final ResourceResolver resolver = parent.getResourceResolver();
- final String parentPath = parent.getPath();
- return new Iterator<Resource>() {
- int index = 0;
-
- Resource next = seek();
-
- public boolean hasNext() {
- return next != null;
- }
-
- public Resource next() {
- if (!hasNext()) {
- throw new NoSuchElementException();
- }
-
- Resource result = next;
- next = seek();
- return result;
+ ResourceResolver resolver = parent.getResourceResolver();
+
+ List<Iterator<Resource>> allChildren = new ArrayList<>();
+ Iterator<Resource> children;
+
+ children = contentFileMapper.getChildren(resolver, parent);
+ if (children != null) {
+ allChildren.add(children);
+ }
+
+ children = fileMapper.getChildren(resolver, parent);
+ if (children != null) {
+ allChildren.add(children);
+ }
+
+ if (allChildren.isEmpty()) {
+ return null;
+ }
+ else if (allChildren.size() == 1) {
+ return allChildren.get(0);
+ }
+ else {
+ // merge all children from the different iterators, but filter out potential duplicates with same resource name
+ return IteratorUtils.filteredIterator(IteratorUtils.chainedIterator(allChildren), new Predicate() {
+ private Set<String> names = new HashSet<>();
+ @Override
+ public boolean evaluate(Object object) {
+ Resource resource = (Resource)object;
+ return names.add(resource.getName());
}
-
- public void remove() {
- throw new UnsupportedOperationException("remove");
- }
-
- private Resource seek() {
- while (index < children.length) {
- File file = children[index++];
- String path = parentPath + "/" + file.getName();
- Resource result = getResource(resolver, path, file);
- if (result != null) {
- return result;
- }
- }
-
- // nothing found any more
- return null;
- }
- };
- }
-
- // no children
- return null;
+ });
+ }
}
// ---------- SCR Integration
-
- 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");
+ @Activate
+ protected void activate(BundleContext bundleContext, final Config config) {
+ String[] providerRoots = config.provider_roots();
+ if (providerRoots == null || providerRoots.length != 1 || StringUtils.isBlank(providerRoots[0])) {
+ throw new IllegalArgumentException("provider.roots property must be set to exactly one entry.");
}
+ String providerRoot = config.provider_roots()[0];
- String providerFileName = (String) props.get(PROP_PROVIDER_FILE);
+ String providerFileName = config.provider_file();
if (providerFileName == null || providerFileName.length() == 0) {
- throw new IllegalArgumentException(PROP_PROVIDER_FILE
- + " property must be set");
+ throw new IllegalArgumentException("provider.file property must be set");
}
this.providerRoot = providerRoot;
- this.providerRootPrefix = providerRoot.concat("/");
this.providerFile = getProviderFile(providerFileName, bundleContext);
+
+ List<String> contentFileSuffixes = new ArrayList<>();
+ if (config.provider_json_content()) {
+ contentFileSuffixes.add(ContentFileTypes.JSON_SUFFIX);
+ }
+ if (config.provider_jcrxml_content()) {
+ contentFileSuffixes.add(ContentFileTypes.JCR_XML_SUFFIX);
+ }
+ 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.contentFileCache);
+
// 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);
+ if ( config.provider_checkinterval() > 100 ) {
+ this.monitor = new FileMonitor(this, config.provider_checkinterval(),
+ contentFileExtensions, this.contentFileCache);
}
}
+ @Deactivate
protected void deactivate() {
if ( this.monitor != null ) {
this.monitor.stop();
this.monitor = null;
}
this.providerRoot = null;
- this.providerRootPrefix = null;
this.providerFile = null;
+ this.fileMapper = null;
+ this.contentFileMapper = null;
+ if (this.contentFileCache != null) {
+ this.contentFileCache.clear();
+ this.contentFileCache = null;
+ }
}
EventAdmin getEventAdmin() {
@@ -288,41 +299,4 @@ public class FsResourceProvider implemen
return providerFile;
}
- /**
- * 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);
- }
-
- return null;
- }
-
- private Resource getResource(ResourceResolver resourceResolver,
- String resourcePath, File file) {
-
- if (file != 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);
- }
-
- }
-
- // not applicable or not an existing file path
- return null;
- }
}
Added: sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/mapper/ContentFile.java
URL: http://svn.apache.org/viewvc/sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/mapper/ContentFile.java?rev=1784765&view=auto
==============================================================================
--- sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/mapper/ContentFile.java (added)
+++ sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/mapper/ContentFile.java Tue Feb 28 15:40:56 2017
@@ -0,0 +1,166 @@
+/*
+ * 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;
+
+import java.io.File;
+import java.util.Map;
+
+import org.apache.sling.api.resource.ValueMap;
+import org.apache.sling.fsprovider.internal.parser.ContentFileCache;
+
+/**
+ * Reference to a file that contains a content fragment (e.g. JSON, JCR XML).
+ */
+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 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 path, String subPath, ContentFileCache contentFileCache, Object content) {
+ this(file, path, subPath, contentFileCache);
+ this.contentInitialized = true;
+ this.content = content;
+ }
+
+ /**
+ * @return File with content fragment
+ */
+ public File getFile() {
+ return file;
+ }
+
+ /**
+ * @return Root path of content file
+ */
+ public String getPath() {
+ return path;
+ }
+
+ /**
+ * @return Relative path addressing content fragment inside file
+ */
+ public String getSubPath() {
+ return subPath;
+ }
+
+ /**
+ * Content object referenced by sub path.
+ * @return Map if resource, property value if property.
+ */
+ public Object getContent() {
+ if (!contentInitialized) {
+ Map<String,Object> rootContent = contentFileCache.get(path, file);
+ content = getDeepContent(rootContent, subPath);
+ contentInitialized = true;
+ }
+ return content;
+ }
+
+ /**
+ * @return true if any content was found.
+ */
+ public boolean hasContent() {
+ return getContent() != null;
+ }
+
+ /**
+ * @return true if content references resource map.
+ */
+ public boolean isResource() {
+ return (getContent() instanceof Map);
+ }
+
+ /**
+ * @return ValueMap for resource. Never null.
+ */
+ @SuppressWarnings("unchecked")
+ public ValueMap getValueMap() {
+ if (valueMap == null) {
+ Object currentContent = getContent();
+ if (currentContent instanceof Map) {
+ valueMap = ValueMapUtil.toValueMap((Map<String,Object>)currentContent);
+ }
+ else {
+ valueMap = ValueMap.EMPTY;
+ }
+ }
+ return valueMap;
+ }
+
+ /**
+ * Navigate to another sub path position in content file.
+ * @param newSubPath New sub path
+ * @return Content file
+ */
+ public ContentFile navigateTo(String newSubPath) {
+ return new ContentFile(file, path, newSubPath, contentFileCache);
+ }
+
+ @SuppressWarnings("unchecked")
+ private static Object getDeepContent(Object object, String subPath) {
+ if (object == null) {
+ return null;
+ }
+ if (subPath == null) {
+ return object;
+ }
+ if (!(object instanceof Map)) {
+ return null;
+ }
+ String name;
+ String remainingSubPath;
+ int slashIndex = subPath.indexOf('/');
+ if (slashIndex >= 0) {
+ name = subPath.substring(0, slashIndex);
+ remainingSubPath = subPath.substring(slashIndex + 1);
+ }
+ else {
+ name = subPath;
+ remainingSubPath = null;
+ }
+ Object subObject = ((Map<String,Object>)object).get(name);
+ return getDeepContent(subObject, remainingSubPath);
+ }
+
+}
Propchange: sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/mapper/ContentFile.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/mapper/ContentFile.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Tue Feb 28 15:40:56 2017
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author
Propchange: sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/mapper/ContentFile.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/mapper/ContentFileResource.java
URL: http://svn.apache.org/viewvc/sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/mapper/ContentFileResource.java?rev=1784765&view=auto
==============================================================================
--- sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/mapper/ContentFileResource.java (added)
+++ sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/mapper/ContentFileResource.java Tue Feb 28 15:40:56 2017
@@ -0,0 +1,127 @@
+/*
+ * 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;
+
+import javax.jcr.Node;
+
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+import org.apache.sling.api.resource.AbstractResource;
+import org.apache.sling.api.resource.ResourceMetadata;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.api.resource.ResourceUtil;
+import org.apache.sling.api.resource.ValueMap;
+import org.apache.sling.fsprovider.internal.mapper.jcr.FsNode;
+
+/**
+ * Represents a JSON File with resource content.
+ */
+public final class ContentFileResource extends AbstractResource {
+
+ // the owning resource resolver
+ private final ResourceResolver resolver;
+
+ // the path of this resource in the resource tree
+ private final String resourcePath;
+
+ // the file wrapped by this instance
+ private final ContentFile contentFile;
+
+ // the resource type, assigned on demand
+ private String resourceType;
+ private String resourceSuperType;
+
+ // the resource metadata, assigned on demand
+ private ResourceMetadata metaData;
+
+ /**
+ * @param resolver The owning resource resolver
+ * @param resourcePath The resource path in the resource tree
+ * @param contentFile Content file with sub path
+ */
+ ContentFileResource(ResourceResolver resolver, ContentFile contentFile) {
+ this.resolver = resolver;
+ this.contentFile = contentFile;
+ this.resourcePath = contentFile.getPath()
+ + (contentFile.getSubPath() != null ? "/" + contentFile.getSubPath() : "");
+ }
+
+ public String getPath() {
+ return resourcePath;
+ }
+
+ public ResourceMetadata getResourceMetadata() {
+ if (metaData == null) {
+ metaData = new ResourceMetadata();
+ metaData.setModificationTime(contentFile.getFile().lastModified());
+ metaData.setResolutionPath(resourcePath);
+ }
+ return metaData;
+ }
+
+ public ResourceResolver getResourceResolver() {
+ return resolver;
+ }
+
+ public String getResourceSuperType() {
+ if (resourceSuperType == null) {
+ resourceSuperType = ResourceUtil.getValueMap(this).get("sling:resourceSuperType", String.class);
+ }
+ return resourceSuperType;
+ }
+
+ public String getResourceType() {
+ if (resourceType == null) {
+ ValueMap props = ResourceUtil.getValueMap(this);
+ resourceType = props.get("sling:resourceType", String.class);
+ if (resourceType == null) {
+ // fallback to jcr:primaryType when resource type not set
+ resourceType = props.get("jcr:primaryType", String.class);
+ }
+ }
+ return resourceType;
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public <AdapterType> AdapterType adaptTo(Class<AdapterType> type) {
+ if (type == ContentFile.class) {
+ return (AdapterType)this.contentFile;
+ }
+ else if (type == ValueMap.class) {
+ return (AdapterType)contentFile.getValueMap();
+ }
+ else if (type == Node.class && contentFile.isResource()) {
+ // support a subset of JCR API for content file resources
+ return (AdapterType)new FsNode(contentFile, getResourceResolver());
+ }
+ return super.adaptTo(type);
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE)
+ .append("path", resourcePath)
+ .append("file", contentFile.getFile().getPath())
+ .append("subPath", contentFile.getSubPath())
+ .append("resourceType", getResourceType())
+ .build();
+ }
+
+}
Propchange: sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/mapper/ContentFileResource.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/mapper/ContentFileResource.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Tue Feb 28 15:40:56 2017
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author
Propchange: sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/mapper/ContentFileResource.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/mapper/ContentFileResourceMapper.java
URL: http://svn.apache.org/viewvc/sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/mapper/ContentFileResourceMapper.java?rev=1784765&view=auto
==============================================================================
--- sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/mapper/ContentFileResourceMapper.java (added)
+++ sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/mapper/ContentFileResourceMapper.java Tue Feb 28 15:40:56 2017
@@ -0,0 +1,155 @@
+/*
+ * 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;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.collections.IteratorUtils;
+import org.apache.commons.collections.Transformer;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceResolver;
+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 {
+
+ // providerRoot + "/" to be used for prefix matching of paths
+ private final String providerRootPrefix;
+
+ // The "root" file or folder in the file system
+ private final File providerFile;
+
+ private final ContentFileExtensions contentFileExtensions;
+ private final ContentFileCache contentFileCache;
+
+ 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) {
+ if (contentFileExtensions.isEmpty()) {
+ return null;
+ }
+ ContentFile contentFile = getFile(resourcePath, null);
+ if (contentFile != null && contentFile.hasContent()) {
+ return new ContentFileResource(resolver, contentFile);
+ }
+ else {
+ return null;
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public Iterator<Resource> getChildren(final ResourceResolver resolver, final Resource parent) {
+ if (contentFileExtensions.isEmpty()) {
+ return null;
+ }
+ final String parentPath = parent.getPath();
+ ContentFile parentContentFile = parent.adaptTo(ContentFile.class);
+
+ // not a FsResource, try to create one from the resource
+ if (parentContentFile == null) {
+ parentContentFile = getFile(parentPath, null);
+ if (parentContentFile == null) {
+
+ // check if parent is a file resource that contains a file content resource
+ File parentFile = parent.adaptTo(File.class);
+ if (parentFile != null && parentFile.isDirectory()) {
+ List<Resource> childResources = new ArrayList<>();
+ for (File file : parentFile.listFiles()) {
+ String filenameSuffix = contentFileExtensions.getSuffix(file);
+ if (filenameSuffix != null) {
+ String path = parentPath + "/" + StringUtils.substringBeforeLast(file.getName(), filenameSuffix);
+ ContentFile contentFile = new ContentFile(file, path, null, contentFileCache);
+ childResources.add(new ContentFileResource(resolver, contentFile));
+ }
+ }
+ if (!childResources.isEmpty()) {
+ return childResources.iterator();
+ }
+ }
+
+ // no children here
+ return null;
+ }
+ }
+
+ // get child resources from content fragments in content file
+ List<ContentFile> children = new ArrayList<>();
+ if (parentContentFile.hasContent() && parentContentFile.isResource()) {
+ Map<String,Object> content = (Map<String,Object>)parentContentFile.getContent();
+ for (Map.Entry<String, Object> entry: content.entrySet()) {
+ if (entry.getValue() instanceof Map) {
+ String subPath;
+ if (parentContentFile.getSubPath() == null) {
+ subPath = entry.getKey();
+ }
+ else {
+ subPath = parentContentFile.getSubPath() + "/" + entry.getKey();
+ }
+ children.add(new ContentFile(parentContentFile.getFile(), parentContentFile.getPath(), subPath, contentFileCache, entry.getValue()));
+ }
+ }
+ }
+ if (children.isEmpty()) {
+ return null;
+ }
+ else {
+ return IteratorUtils.transformedIterator(children.iterator(), new Transformer() {
+ @Override
+ public Object transform(Object input) {
+ ContentFile contentFile = (ContentFile)input;
+ return new ContentFileResource(resolver, contentFile);
+ }
+ });
+ }
+ }
+
+ private ContentFile getFile(String path, String subPath) {
+ if (!StringUtils.startsWith(path, providerRootPrefix)) {
+ return null;
+ }
+ String relPath = path.substring(providerRootPrefix.length());
+ for (String filenameSuffix : contentFileExtensions.getSuffixes()) {
+ File file = new File(providerFile, relPath + filenameSuffix);
+ if (file.exists()) {
+ return new ContentFile(file, path, subPath, contentFileCache);
+ }
+ }
+ // try to find in parent path which contains content fragment
+ String parentPath = ResourceUtil.getParent(path);
+ String nextSubPath = path.substring(parentPath.length() + 1)
+ + (subPath != null ? "/" + subPath : "");
+ return getFile(parentPath, nextSubPath);
+ }
+
+}
Propchange: sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/mapper/ContentFileResourceMapper.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/mapper/ContentFileResourceMapper.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Tue Feb 28 15:40:56 2017
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author
Propchange: sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/mapper/ContentFileResourceMapper.java
------------------------------------------------------------------------------
svn:mime-type = text/plain