<?xml version="1.0" encoding="UTF-8"?>
<!--
  ~ ModeShape (http://www.modeshape.org)
  ~
  ~ See the COPYRIGHT.txt file distributed with this work for information
  ~ regarding copyright ownership.  Some portions may be licensed
  ~ to Red Hat, Inc. under one or more contributor license agreements.
  ~ See the AUTHORS.txt file in the distribution for a full listing of 
  ~ individual contributors.
  ~
  ~ ModeShape is free software. Unless otherwise indicated, all code in ModeShape
  ~ is licensed to you under the terms of the GNU Lesser General Public License as
  ~ published by the Free Software Foundation; either version 2.1 of
  ~ the License, or (at your option) any later version.
  ~
  ~ ModeShape is distributed in the hope that it will be useful,
  ~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  ~ or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
  ~ for more details.
  ~
  ~ You should have received a copy of the GNU Lesser General Public License
  ~ along with this distribution; if not, write to:
  ~ Free Software Foundation, Inc.
  ~ 51 Franklin Street, Fifth Floor
  ~ Boston, MA  02110-1301  USA
  -->
<!DOCTYPE preface PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd"	[
<!ENTITY % CustomDTD SYSTEM "../../custom.dtd">
%CustomDTD;
]>
<chapter id="file-system-connector">
  <title>File System Connector</title>
  <para>
		This connector exposes an area of the local file system as a graph of "nt:file" and "nt:folder" nodes. 
		The connector can be configured so that the workspace name is either a path to the directory on the file system that represents the root of that
		workspace <emphasis>or</emphasis> the name of subdirectory within a root directory (see the <code>workspaceRootPath</code> property below). Each 
		connector can define whether it allows new workspaces to be created.  <emphasis>If the directory for a workspace does not exist, this connector
		will attempt to create the directory (and any missing parent directories).</emphasis>
	</para>
	<para>
		By default, this connector is not capable of storing extra properties other than those defined on the <code>nt:file</code>, <code>nt:folder</code>
		and <code>nt:resource</code> node types. This is because such properties cannot be represented natively on the file system. 
		When the connector is asked to store such properties, the default behavior is to log warnings and then to ignore these extra properties.
		Obviously this is probably not sufficient for production (unless only the standard properties are to be used). To explicitly turn on this
		behavior, set the "extraPropertiesBehavior" to "log".
	</para>
	<para>
		However, the connector can be configured differently. If the "extraPropertiesBehavior" is set to "ignore", then these extra properties will
		simply be silently ignored and lost: none will be stored, none will be loaded, and no warnings will be logged. If the "extraPropertiesBehavior"
		is set to "error", the connector will throw an exception if any extra properties are used.
	</para>
	<para>
		Perhaps the best setting for general use, however, is to set the "extraPropertiesBehavior" to "store". In this mode, any extra properties
		are written to files on the file system that are adjacent to the actual file or folder. For example, given a "nt:folder" node that represents
		the "folder1" directory, all extra properties will be stored in a text file named "folder1.modeshape" in the same parent 
		directory as the "folder1" directory.  Similarly, given a "nt:file" node that represents the "file1" file on the file system, all
		extra properties will be stored in a text file named "file1.modeshape" located next to the "file1" file. Note that the "nt:resource" node for
		our "nt:file" node also is stored in the same location, so we can't use the "file1.modeshape" file (it's already used for the "nt:file" node),
		so the connector uses the "file1.content.modeshape" file instead.
	</para>
	<note>
		<para>
			The "store" behavior may result in the creation of many "*.modeshape" files, and because of this the "store" behavior is not the default.
		</para>
	</note>
	<para>
		The &FileSystemSource; class provides a number of JavaBean properties that control its behavior:
	</para>
  <variablelist>
    <varlistentry>
      <term>cachePolicy</term>
      <listitem>
        <para>
          Optional property that, if used, defines the cache policy for this repository source.  When not used, this source will not define a specific
					duration for caching information.
				</para>
      </listitem>
    </varlistentry>
    <varlistentry>
      <term>creatingWorkspaceAllowed</term>
      <listitem>
        <para>
          Optional property that defines whether clients can create additional workspaces.  The default value is "true".
				</para>
      </listitem>
    </varlistentry>
    <varlistentry>
      <term>customPropertiesFactory</term>
      <listitem>
        <para>
          Optional property that specifies the &CustomPropertiesFactory; implementation that should be used to augment the default properties 
					available on each node.  This property can be set either from an object that implements the &CustomPropertiesFactory;
					interface or from the name of a class with a public, no-argument constructor that implements the &CustomPropertiesFactory;
					interface.  In the latter case, a the named class will be instantiated and used as the custom properties factory implementation.
				</para>
				<para>
					This is really intended for cases where the "extraPropertiesBehavior" is not sufficient. Most often, however, the
					"extraPropertiesBehavior" setting will be sufficient and should be used instead of "customPropertiesFactory".
				</para>
      </listitem>
    </varlistentry>
    <varlistentry>
      <term>defaultWorkspaceName</term>
      <listitem>
        <para>
          Optional property that defines the name for the workspace that will be used in cases when clients do not explicitly specify
          the workspace name. If not specified, "<code>default</code>" will be used.
				</para>
      </listitem>
    </varlistentry>
    <varlistentry>
      <term>extraPropertiesBehavior</term>
      <listitem>
        <para>
          Optional setting that specifies how to handle the extra properties on "nt:file", "nt:folder", and "nt:resource" nodes that
					cannot be represented on the native files themselves. Set this to "log" if warnings are to be sent to the log 
					(the default), or "error" if setting such properties should cause an error, or "store" if they should be stored in ancillary 
					files next to the files and folders, or "ignore" if they should be silently ignored. The "log" value will be used by default 
					or an invalid value is specified.
				</para>
				<para>
					This setting will be ignored if a "customPropertiesFactory" class name is specified.
				</para>
      </listitem>
    </varlistentry>
    <varlistentry>
      <term>exclusionPattern</term>
      <listitem>
        <para>
          Optional property that specifies a regular expression that is used to determine which files and folders in the underlying file system are exposed through
					this connector. Files and folders with a name that matches the provided regular expression will <emphasis>not</emphasis> be exposed 
					by this source. Setting this property to <code>null</code> has the effect of removing the exclusion pattern.
				</para>
        <para>
          This may be combined with an "inclusionPattern", in which a file or folder will be exposed by this connector only when it
          satisfies the "inclusionPattern" and does not satisfy the "exclusionPattern". Also, the "inclusionPattern" and "exclusionPattern"
          cannot be used with "filenameFilter", since the latter will always override the patterns.
        </para>
      </listitem>
    </varlistentry>
    <varlistentry>
      <term>inclusionPattern</term>
      <listitem>
        <para>
          Optional property that specifies a regular expression that is used to determine which files and folders in the underlying file system are exposed through
					this connector. Files and folders with a name that matches the provided regular expression will be exposed by this source. 
					Setting this property to <code>null</code> has the effect of removing the inclusion pattern.
				</para>
        <para>
          This may be combined with an "exclusionPattern", in which a file or folder will be exposed by this connector only when it
          satisfies the "inclusionPattern" and does not satisfy the "exclusionPattern". Also, the "inclusionPattern" and "exclusionPattern"
          cannot be used with "filenameFilter", since the latter will always override the patterns.
        </para>
      </listitem>
    </varlistentry>
    <varlistentry>
      <term>filenameFilter</term>
      <listitem>
				<para>
					Optional property that specifies the name of the &FilenameFilter; implementation class that used to determine which files and folders in the underlying 
					file system are exposed through this connector. Only files and folders that the filter accepts will be accessible through this source.
					The &FilenameFilter; implementation class must have a public, no-argument constructor.
					Use this when the "inclusionPattern" and "exclusionPattern" values would be too complicated or are not able to represent the logic.
				</para>
				<para>
					Note that the "filenameFilter", "exclusionPattern", and "inclusionPattern" properties are somewhat mutually exclusive.  
					If a "filenameFilter" is specified, then "exclusionPattern" and "inclusionPattern" are both ignored.
					Setting this property to an empty value (or null) has the effect of clearing the filter.
				</para>
      </listitem>
    </varlistentry>
    <varlistentry>
      <term>name</term>
      <listitem>
        <para>
          Required property that specifies the name of the repository source, which is used by the &RepositoryService; 
          when obtaining a &RepositoryConnection; by name.
				</para>
      </listitem>
    </varlistentry>
    <varlistentry>
      <term>nodeCachePolicy</term>
      <listitem>
        <para>
          Optional property that, if used, defines the cache policy to use for caching nodes within the connector.  
				</para>
      </listitem>
    </varlistentry>
    <varlistentry>
      <term>predefinedWorkspaceNames</term>
      <listitem>
        <para>
          Optional property that, if used, defines names of the workspaces that are predefined and need not be created before being used.
					This can be coupled with a "false" value for the "creatingWorkspaceAllowed" property to allow only the use of only predefined workspaces.
				</para>
      </listitem>
    </varlistentry>
    <varlistentry>
      <term>rootNodeUuid</term>
      <listitem>
        <para>
          Optional property that, if used, specifies the UUID that should be used for the root node of each workspace.  If no value is
					specified, a default UUID is used.
				</para>
      </listitem>
    </varlistentry>
    <varlistentry>
      <term>retryLimit</term>
      <listitem>
        <para>
          Optional property that, if used, defines the number of times that any single operation on a &RepositoryConnection; to this source should be retried
					following a communication failure. The default value is '0'.
				</para>
      </listitem>
    </varlistentry>
    <varlistentry>
      <term>temporaryStoragePath</term>
      <listitem>
        <para>
          Optional property that specifies a location for the file system connector's temporary storage.
				  When writing file content, this connector first writes the content to a file in the temporary storage area. After
     			that write succeeds in full, the temporary file is moved to its final location in the workspace. This extra step is taken
     			so that an error or failure while writing the file does not cause corruption in the existing target file.
     		</para>
     		<para>
     		  This path must be set to a path on the same file system specified by the <code>workspaceRootPath</code> property.
     		  Otherwise, the temporary storage area will be located on a different file system than where the file will ultimately be written,
					so the rename operation cannot be used and a separate file copy must occur, increasing the risk of data loss if a network
					failure or hardware problem occurs.
     		</para>
     	</listitem>
    </varlistentry>
    <varlistentry>
      <term>updatesAllowed</term>
      <listitem>
        <para>
          Determines whether the content in the file system can be updated ("true"), or if the content may only be read ("false").
					The default value is "false" to avoid unintentional security vulnerabilities.
				</para>
      </listitem>
    </varlistentry>
    <varlistentry>
      <term>workspaceRootPath</term>
      <listitem>
				<para>
				  Optional property that, if used, specifies a path on the local file system to the root of all workspaces.  The source will will 
					use the name of the workspace as a relative path from the <code>workspaceRootPath</code> to determine the path for a particular workspace.  
					If no value (or a <code>null</code> value) is specified, the source will use the name of the workspace as a relative path from the current working 
					directory of this virtual machine (as defined by <code>new File(".")</code>.
				</para>
				<para>
				  As an example, if <code>workspaceRootPath</code> is set	to a non-null value, then for a workspace named <code>"default/foo"</code>
				  the source will use <code>new File(workspaceRootPath, "default/foo")</code> as the source directory for the workspace content.
				  If <code>workspaceRootPath</code> is not set (or set to an empty string or null value), then the source will use
				  <code>new File(".", "default/foo")</code> as the source directory for the workspace content.
				</para>
      </listitem>
    </varlistentry>
  </variablelist>
	<para>
		One way to configure the file system connector is to create &JcrConfiguration; instance with a repository source that uses the &FileSystemSource; class.
		For example:
	</para>
  <programlisting language="JAVA" role="JAVA"><![CDATA[
JcrConfiguration config = ...
config.repositorySource("FS Store")
      .usingClass(FileSystemSource.class)
      .setDescription("The repository for our content")
      .setProperty("workspaceRootPath", "/home/content/someApp")
      .setProperty("defaultWorkspaceName", "prod")
      .setProperty("predefinedWorkspaceNames", new String[] { "staging", "dev"})
      .setProperty("rootNodeUuid", UUID.fromString("fd129c12-81a8-42ed-aa4b-820dba49e6f0")
      .setProperty("updatesAllowed", "true")
      .setProperty("creatingWorkspaceAllowed", "false");
 ]]></programlisting>
	<para>
		Another way to configure the file system connector is to create &JcrConfiguration; instance and load an XML configuration file that contains a repository source that 
		uses the &FileSystemSource; class.
		For example a file named configRepository.xml can be created with these contents:
	</para>
	
  <programlisting language="XML" role="XML"><![CDATA[
<?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:sources jcr:primaryType="nt:unstructured">
        <!-- 
        The 'FS Store' repository is a file system source with a three predefined workspaces 
        ("prod", "staging", and "dev").
        -->
        <mode:source jcr:name="FS Store" 
        	mode:classname="org.modeshape.connector.filesystem.FileSystemSource"
        	mode:description="The repository for our content"
        	mode:workspaceRootPath="/home/content/someApp"
        	mode:defaultWorkspaceName="prod"
        	mode:creatingWorkspacesAllowed="false"
        	mode:rootNodeUuid="fd129c12-81a8-42ed-aa4b-820dba49e6f0"
        	mode:updatesAllowed="true" >
            <mode:predefinedWorkspaceNames>staging</mode:predefinedWorkspaceNames>
            <mode:predefinedWorkspaceNames>dev</mode:predefinedWorkspaceNames>
      	    <!-- 
      	    If desired, specify a cache policy that caches items in memory for 5 minutes (300 s).
      	    This fragment can be left out if the connector should not cache any content.
      	    -->
      	    <mode:cachePolicy jcr:name="nodeCachePolicy" 
      	      mode:classname="org.modeshape.graph.connector.base.cache.InMemoryNodeCache$PathCachePolicy"
      	      mode:timeToLive="300" />
        </mode:source>    
    </mode:sources>

	<!-- MIME type detectors and JCR repositories would be defined below --> 
</configuration>
 ]]></programlisting>
	<para>
		The configuration can then be loaded from Java like this:
	</para>
	
	<programlisting language="JAVA" role="JAVA"><![CDATA[
JcrConfiguration config = new JcrConfiguration().loadFrom("/configRepository.xml");
 ]]></programlisting>
 </chapter>

