Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

MODE-1483 - Extra properties files stored via the file system connect…

…or are now removed.

The original problem was caused by the incomplete handling for removal of nodes by the FileSystemWorkspace and the fact that the StoreProperties stores additional file & folder properties in external files (external to the file nodes themselves)
  • Loading branch information...
commit c11bc70bb073ba06fd1a7372aba714670eb7b21c 1 parent d2a4788
@hchiorean authored
View
16 ...deshape-connector-filesystem/src/main/java/org/modeshape/connector/filesystem/BasePropertiesFactory.java
@@ -23,6 +23,7 @@
*/
package org.modeshape.connector.filesystem;
+import java.io.File;
import java.io.FilenameFilter;
import java.util.Arrays;
import java.util.Collection;
@@ -86,4 +87,19 @@ protected BasePropertiesFactory() {
public FilenameFilter getFilenameFilter( FilenameFilter exclusionFilter ) {
return exclusionFilter;
}
+
+ @Override
+ public File propertiesFileForFile( File file ) {
+ return null;
+ }
+
+ @Override
+ public File propertiesFileForFolder( File folder ) {
+ return null;
+ }
+
+ @Override
+ public File propertiesFileForResource( File resource ) {
+ return null;
+ }
}
View
24 ...shape-connector-filesystem/src/main/java/org/modeshape/connector/filesystem/CustomPropertiesFactory.java
@@ -152,4 +152,28 @@
File file,
Map<Name, Property> properties ) throws RepositorySourceException;
+ /**
+ * Returns the file used for storing extra properties for files.
+
+ * @param file a non-null {@link File} representing an existing file.
+ * @return the file in which the properties are be stored or {@code null} if custom properties are not supported
+ */
+ File propertiesFileForFile( File file );
+
+ /**
+ * Returns the file used for storing extra properties for folders.
+
+ * @param folder a non-null {@link File} representing an existing folder.
+ * @return the file in which the properties are be stored or {@code null} if custom properties are not supported
+ */
+ File propertiesFileForFolder( File folder );
+
+ /**
+ * Returns the file used for storing properties for resources.
+
+ * @param resource a non-null {@link File} representing an existing file.
+ * @return the file in which the properties are be stored or {@code null} if custom properties are not supported
+ */
+ File propertiesFileForResource(File resource);
+
}
View
51 ...modeshape-connector-filesystem/src/main/java/org/modeshape/connector/filesystem/FileSystemWorkspace.java
@@ -402,6 +402,10 @@ public PathNode removeNode( Path nodePath ) {
Location.create(nodePath),
nodeFile,
NO_PROPERTIES);
+ File propertiesFile = customPropertiesFactory.propertiesFileForResource(nodeFile);
+ if (propertiesFile != null) {
+ FileUtil.delete(propertiesFile);
+ }
if (!nodeFile.exists()) return null;
FileOutputStream fos = null;
@@ -413,21 +417,60 @@ public PathNode removeNode( Path nodePath ) {
getName(),
source.getName()));
} finally {
+ FileUtil.delete(nodeFile);
if (fos != null) try {
fos.close();
} catch (IOException ioe) {
}
}
} else {
+ PathNode node = getNode(nodePath);
+ if (node == null) {
+ return null;
+ }
+
nodeFile = fileFor(nodePath);
- // Have the custom property factory remote all properties ...
- customPropertiesFactory.recordResourceProperties(context,
+
+ //remove all the children first
+ for (Segment segment : node.getChildren()) {
+ Path childPath = pathFactory.create(nodePath, segment);
+ removeNode(childPath);
+ }
+
+ Name primaryType = nameFactory.create(node.getProperty(JcrLexicon.PRIMARY_TYPE).getFirstValue());
+ if (JcrNtLexicon.FILE.equals(primaryType)) {
+ // Have the custom property factory remote all properties ...
+ customPropertiesFactory.recordFileProperties(context,
source.getName(),
Location.create(nodePath),
nodeFile,
NO_PROPERTIES);
- if (!nodeFile.exists()) return null;
-
+ File propertiesFile = customPropertiesFactory.propertiesFileForFile(nodeFile);
+ if (propertiesFile != null) {
+ FileUtil.delete(propertiesFile);
+ }
+ } else if (JcrNtLexicon.FOLDER.equals(primaryType)) {
+ // Have the custom property factory remote all properties ...
+ customPropertiesFactory.recordDirectoryProperties(context,
+ source.getName(),
+ Location.create(nodePath),
+ nodeFile,
+ NO_PROPERTIES);
+ File propertiesFile = customPropertiesFactory.propertiesFileForFolder(nodeFile);
+ if (propertiesFile != null) {
+ FileUtil.delete(propertiesFile);
+ }
+ } else {
+ customPropertiesFactory.recordResourceProperties(context,
+ source.getName(),
+ Location.create(nodePath),
+ nodeFile,
+ NO_PROPERTIES);
+ File propertiesFile = customPropertiesFactory.propertiesFileForResource(nodeFile);
+ if (propertiesFile != null) {
+ FileUtil.delete(propertiesFile);
+ }
+ }
FileUtil.delete(nodeFile);
}
View
17 ...ons/modeshape-connector-filesystem/src/main/java/org/modeshape/connector/filesystem/StoreProperties.java
@@ -241,14 +241,25 @@ public void setSourceName( String sourceName ) {
return write(propertiesFileForResource(file), context, properties);
}
- protected File propertiesFileFor( File fileOrDirectory ) {
- return new File(fileOrDirectory.getPath() + extension);
+ @Override
+ public File propertiesFileForFile( File file ) {
+ return propertiesFileFor(file);
+ }
+
+ @Override
+ public File propertiesFileForFolder( File folder ) {
+ return propertiesFileFor(folder);
}
- protected File propertiesFileForResource( File fileOrDirectory ) {
+ @Override
+ public File propertiesFileForResource( File fileOrDirectory ) {
return new File(fileOrDirectory.getPath() + resourceExtension);
}
+ protected File propertiesFileFor( File fileOrDirectory ) {
+ return new File(fileOrDirectory.getPath() + extension);
+ }
+
protected Map<Name, Property> load( File propertiesFile,
ExecutionContext context ) throws RepositorySourceException {
if (!propertiesFile.exists() || !propertiesFile.canRead()) return NO_PROPERTIES_MAP;
View
35 ...n-tests/src/test/java/org/modeshape/test/integration/filesystem/FileSystemRepositoryIntegrationTest.java
@@ -39,9 +39,11 @@
import javax.jcr.nodetype.NodeTypeManager;
import javax.jcr.nodetype.NodeTypeTemplate;
import javax.jcr.nodetype.PropertyDefinitionTemplate;
+import static org.junit.Assert.assertTrue;
import org.junit.Test;
import org.modeshape.common.FixFor;
import org.modeshape.common.util.FileUtil;
+import org.modeshape.jcr.JcrTools;
import org.modeshape.test.ModeShapeSingleUseTest;
public class FileSystemRepositoryIntegrationTest extends ModeShapeSingleUseTest {
@@ -334,6 +336,39 @@ public void shouldAllowReindexingSubgraphAsynchronously() throws Exception {
logout();
}
+ @FixFor("MODE-1483")
+ @Test
+ public void shouldRemoveFileCreatedByFilesystemConnector() throws Exception {
+ File repositoryRoot = new File("./target/fileSystemSource");
+ try {
+ if (!repositoryRoot.exists() || !repositoryRoot.isDirectory()) {
+ assertTrue(repositoryRoot.mkdir());
+ }
+
+ startEngineUsing("config/configRepositoryForFileSystem_MODE1483.xml");
+
+ Session session = session();
+ JcrTools jcrTools = new JcrTools();
+
+ String resourcePath = "filesystem/workspace1/TestFile.txt";
+
+ Node fileUnderRoot = jcrTools.uploadFile(session, "test.file", getClass().getClassLoader().getResource(resourcePath));
+ Node folder = session().getRootNode().addNode("folder", "nt:folder");
+ jcrTools.uploadFile(session, "/folder/file1", getClass().getClassLoader().getResource(resourcePath));
+ jcrTools.uploadFile(session, "/folder/file2", getClass().getClassLoader().getResource(resourcePath));
+ session.save();
+
+ fileUnderRoot.remove();
+ folder.remove();
+ session.save();
+
+ File workspaceRoot = new File("./target/fileSystemSource/" + session.getWorkspace().getName());
+ assertTrue(workspaceRoot.list().length == 0);
+ } finally {
+ FileUtil.delete(repositoryRoot);
+ }
+ }
+
protected void registryNamespaceIfMissing( String prefix,
String url ) throws RepositoryException {
NamespaceRegistry registry = session().getWorkspace().getNamespaceRegistry();
View
56 modeshape-integration-tests/src/test/resources/config/configRepositoryForFileSystem_MODE1483.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<configuration xmlns:mode="http://www.modeshape.org/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0">
+ <!--
+ Define the sources for the content. These sources are directly accessible using the ModeShape-specific Graph API.
+ In fact, this is how the ModeShape JCR implementation works. You can think of these as being similar to
+ JDBC DataSource objects, except that they expose graph content via the Graph API instead of records via SQL or JDBC.
+ -->
+ <!--<mode:clustering clusterName="modeshape-cluster" configuration="jgroups-modeshape.xml"/>-->
+
+
+ <mode:sources jcr:primaryType="nt:unstructured">
+
+ <mode:source jcr:name="Files" mode:classname="org.modeshape.connector.filesystem.FileSystemSource"
+ mode:extraPropertiesBehavior="store"
+ mode:exclusionPattern="^.*\.modeshape$"
+ mode:workspaceRootPath="./target/fileSystemSource"
+ mode:defaultWorkspaceName="fileSystemWorkspace"
+ mode:creatingWorkspacesAllowed="false"
+ mode:updatesAllowed="true"/>
+ </mode:sources>
+
+ <!--
+ Define the mime type detectors. This is an optional section. By default, each engine will use the
+ MIME type detector that uses filename extensions. So we wouldn't need to define the same detector again,
+ but this is how you'd define another extension.
+ -->
+ <mode:mimeTypeDetectors>
+ <mode:mimeTypeDetector jcr:name="Detector">
+ <mode:description>Standard extension-based MIME type detector</mode:description>
+ <!--
+ Specify the implementation class (required), as a child element or attribute on parent element.
+ -->
+ <mode:classname>org.modeshape.graph.mimetype.ExtensionBasedMimeTypeDetector</mode:classname>
+ </mode:mimeTypeDetector>
+ </mode:mimeTypeDetectors>
+ <!--
+ Define the JCR repositories
+ -->
+ <mode:repositories>
+
+ <mode:repository jcr:name="Files">
+ <!-- Specify the source that should be used for the repository -->
+ <mode:source>Files</mode:source>
+
+ <!-- Define the options for the JCR repository, using camelcase version of JcrRepository.Option names -->
+ <mode:options jcr:primaryType="mode:options">
+ <jaasLoginConfigName jcr:primaryType="mode:option" mode:value="modeshape-jcr"/>
+ <queryIndexDirectory jcr:primaryType="mode:option"
+ mode:value="./target/fileSystemSource/indexes"/>
+ <!--<systemSourceName jcr:primaryType="mode:option" mode:value="system@SystemStore"/>-->
+ </mode:options>
+ </mode:repository>
+
+ </mode:repositories>
+</configuration>
View
2  modeshape-jcr/src/main/resources/org/modeshape/jcr/JcrI18n.properties
@@ -133,7 +133,7 @@ cannotRemoveParentNodeOfTarget = The node at "{0}" with UUID "{1}" is a parent o
invalidPropertyType = Invalid property type: {0}
-unableToRemoveRootNode = Unable to remove the root node in workspace "{1}"
+unableToRemoveRootNode = Unable to remove the root node in workspace "{0}"
unableToMoveNodeToBeChildOfDecendent = Node "{0}" in workspace "{2}" cannot be moved under a decendant node ("{1}")
nodeHasAlreadyBeenRemovedFromThisSession = Node "{0}" in workspace "{1} has already been removed from this session
Please sign in to comment.
Something went wrong with that request. Please try again.