DNA SVN: r1489 - in trunk/extensions/dna-connector-svn/src/main/java/org/jboss/dna/connector/svn: mgnt and 1 other directory.
by dna-commits@lists.jboss.org
Author: spagop
Date: 2009-12-29 17:46:08 -0500 (Tue, 29 Dec 2009)
New Revision: 1489
Added:
trunk/extensions/dna-connector-svn/src/main/java/org/jboss/dna/connector/svn/mgnt/
trunk/extensions/dna-connector-svn/src/main/java/org/jboss/dna/connector/svn/mgnt/AddDirectory.java
trunk/extensions/dna-connector-svn/src/main/java/org/jboss/dna/connector/svn/mgnt/AddFile.java
trunk/extensions/dna-connector-svn/src/main/java/org/jboss/dna/connector/svn/mgnt/ISVNEditorUtil.java
trunk/extensions/dna-connector-svn/src/main/java/org/jboss/dna/connector/svn/mgnt/MergeFile.java
Log:
some write svn access (add file/dir, update file)
Added: trunk/extensions/dna-connector-svn/src/main/java/org/jboss/dna/connector/svn/mgnt/AddDirectory.java
===================================================================
--- trunk/extensions/dna-connector-svn/src/main/java/org/jboss/dna/connector/svn/mgnt/AddDirectory.java (rev 0)
+++ trunk/extensions/dna-connector-svn/src/main/java/org/jboss/dna/connector/svn/mgnt/AddDirectory.java 2009-12-29 22:46:08 UTC (rev 1489)
@@ -0,0 +1,59 @@
+/*
+ * JBoss DNA (http://www.jboss.org/dna)
+ * 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.
+ *
+ * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
+ * 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.
+ *
+ * JBoss DNA 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 software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.dna.connector.svn.mgnt;
+
+import org.jboss.dna.connector.scm.ScmAction;
+import org.tmatesoft.svn.core.SVNException;
+import org.tmatesoft.svn.core.io.ISVNEditor;
+
+/**
+ * root should be the last, previously created, parent folder. Each directory in the path will be created.
+ */
+public class AddDirectory implements ScmAction {
+ private String rootDirPath;
+ private String childDirPath;
+
+ public AddDirectory( String rootPath,
+ String childDirPath ) {
+ this.rootDirPath = rootPath;
+ this.childDirPath = childDirPath;
+ }
+
+ public void applyAction( Object context ) throws SVNException {
+
+ ISVNEditor editor = (ISVNEditor)context;
+
+ ISVNEditorUtil.openDirectories(editor, this.rootDirPath);
+ String[] paths = this.childDirPath.split("/");
+ String newPath = this.rootDirPath;
+ for (int i = 0, length = paths.length; i < length; i++) {
+ newPath = (newPath.length() != 0) ? newPath + "/" + paths[i] : paths[i];
+
+ editor.addDir(newPath, null, -1);
+ }
+
+ ISVNEditorUtil.closeDirectories(editor, childDirPath);
+ ISVNEditorUtil.closeDirectories(editor, this.rootDirPath);
+ }
+}
Property changes on: trunk/extensions/dna-connector-svn/src/main/java/org/jboss/dna/connector/svn/mgnt/AddDirectory.java
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Added: trunk/extensions/dna-connector-svn/src/main/java/org/jboss/dna/connector/svn/mgnt/AddFile.java
===================================================================
--- trunk/extensions/dna-connector-svn/src/main/java/org/jboss/dna/connector/svn/mgnt/AddFile.java (rev 0)
+++ trunk/extensions/dna-connector-svn/src/main/java/org/jboss/dna/connector/svn/mgnt/AddFile.java 2009-12-29 22:46:08 UTC (rev 1489)
@@ -0,0 +1,57 @@
+/*
+ * JBoss DNA (http://www.jboss.org/dna)
+ * 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.
+ *
+ * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
+ * 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.
+ *
+ * JBoss DNA 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 software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.dna.connector.svn.mgnt;
+
+import java.io.ByteArrayInputStream;
+import org.jboss.dna.connector.scm.ScmAction;
+import org.tmatesoft.svn.core.io.ISVNEditor;
+import org.tmatesoft.svn.core.io.diff.SVNDeltaGenerator;
+
+public class AddFile implements ScmAction {
+ private String path;
+ private String file;
+ private byte[] content;
+
+ public AddFile( String path,
+ String file,
+ byte[] content ) {
+ this.path = path;
+ this.file = file;
+ this.content = content;
+ }
+
+ public void applyAction( Object context ) throws Exception {
+ ISVNEditor editor = (ISVNEditor)context;
+ ISVNEditorUtil.openDirectories(editor, this.path);
+ if(this.file.startsWith("/")) this.file = file.substring(1);
+ editor.addFile(this.path + "/" + this.file, null, -1);
+ editor.applyTextDelta(this.path + "/" + this.file, null);
+ SVNDeltaGenerator deltaGenerator = new SVNDeltaGenerator();
+ String checksum = deltaGenerator.sendDelta(this.path + "/" + this.file, new ByteArrayInputStream(this.content), editor, true);
+ editor.closeFile(this.path + "/" + this.file, checksum);
+
+ ISVNEditorUtil.closeDirectories(editor, this.path);
+ }
+
+}
Property changes on: trunk/extensions/dna-connector-svn/src/main/java/org/jboss/dna/connector/svn/mgnt/AddFile.java
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Added: trunk/extensions/dna-connector-svn/src/main/java/org/jboss/dna/connector/svn/mgnt/ISVNEditorUtil.java
===================================================================
--- trunk/extensions/dna-connector-svn/src/main/java/org/jboss/dna/connector/svn/mgnt/ISVNEditorUtil.java (rev 0)
+++ trunk/extensions/dna-connector-svn/src/main/java/org/jboss/dna/connector/svn/mgnt/ISVNEditorUtil.java 2009-12-29 22:46:08 UTC (rev 1489)
@@ -0,0 +1,73 @@
+/*
+ * JBoss DNA (http://www.jboss.org/dna)
+ * 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.
+ *
+ * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
+ * 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.
+ *
+ * JBoss DNA 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 software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.dna.connector.svn.mgnt;
+
+import org.tmatesoft.svn.core.SVNException;
+import org.tmatesoft.svn.core.io.ISVNEditor;
+
+/**
+ * @author sp
+ *
+ */
+public class ISVNEditorUtil {
+
+ /**
+ * Open the directories where change has to be made.
+ *
+ * @param editor - abstract editor.
+ * @param rootPath - the pa to open.
+ * @throws SVNException when a error occur.
+ */
+ protected static void openDirectories( ISVNEditor editor,
+ String rootPath ) throws SVNException {
+ assert rootPath != null;
+ int pos = rootPath.indexOf('/', 0);
+ while (pos != -1) {
+ String dir = rootPath.substring(0, pos);
+ editor.openDir(dir, -1);
+ pos = rootPath.indexOf('/', pos + 1);
+ }
+ String dir = rootPath.substring(0, rootPath.length());
+ editor.openDir(dir, -1);
+ }
+
+ /**
+ * Close the directories where change was made.
+ *
+ * @param editor - the abstract editor.
+ * @param path - the directories to open.
+ * @throws SVNException when a error occur.
+ */
+ protected static void closeDirectories( ISVNEditor editor,
+ String path ) throws SVNException {
+ int length = path.length() - 1;
+ int pos = path.lastIndexOf('/', length);
+ editor.closeDir();
+ while (pos != -1) {
+ editor.closeDir();
+ pos = path.lastIndexOf('/', pos - 1);
+ }
+ }
+
+}
Property changes on: trunk/extensions/dna-connector-svn/src/main/java/org/jboss/dna/connector/svn/mgnt/ISVNEditorUtil.java
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Added: trunk/extensions/dna-connector-svn/src/main/java/org/jboss/dna/connector/svn/mgnt/MergeFile.java
===================================================================
--- trunk/extensions/dna-connector-svn/src/main/java/org/jboss/dna/connector/svn/mgnt/MergeFile.java (rev 0)
+++ trunk/extensions/dna-connector-svn/src/main/java/org/jboss/dna/connector/svn/mgnt/MergeFile.java 2009-12-29 22:46:08 UTC (rev 1489)
@@ -0,0 +1,64 @@
+/*
+ * JBoss DNA (http://www.jboss.org/dna)
+ * 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.
+ *
+ * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
+ * 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.
+ *
+ * JBoss DNA 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 software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.dna.connector.svn.mgnt;
+
+import java.io.ByteArrayInputStream;
+import org.jboss.dna.connector.scm.ScmAction;
+import org.tmatesoft.svn.core.io.ISVNEditor;
+import org.tmatesoft.svn.core.io.diff.SVNDeltaGenerator;
+
+public class MergeFile implements ScmAction {
+ private String path;
+ private String file;
+ private byte[] oldData;
+ private byte[] newData;
+
+ public MergeFile( String path,
+ String file,
+ byte[] oldData,
+ byte[] newData ) {
+ this.path = path;
+ this.file = file;
+ this.oldData = oldData;
+ this.newData = newData;
+ }
+
+ public void applyAction( Object context ) throws Exception {
+ ISVNEditor editor = (ISVNEditor)context;
+ ISVNEditorUtil.openDirectories(editor, this.path);
+
+ editor.openFile(this.path + "/" + this.file, -1);
+ editor.applyTextDelta(this.path + "/" + this.file, null);
+ SVNDeltaGenerator deltaGenerator = new SVNDeltaGenerator();
+ String checksum = deltaGenerator.sendDelta(this.path + "/" + this.file,
+ new ByteArrayInputStream(this.oldData),
+ 0,
+ new ByteArrayInputStream(this.newData),
+ editor,
+ true);
+ editor.closeFile(this.path + "/" + this.file, checksum);
+ ISVNEditorUtil.closeDirectories(editor, path);
+ }
+
+}
\ No newline at end of file
Property changes on: trunk/extensions/dna-connector-svn/src/main/java/org/jboss/dna/connector/svn/mgnt/MergeFile.java
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
14 years, 4 months
DNA SVN: r1488 - trunk/extensions/dna-connector-svn.
by dna-commits@lists.jboss.org
Author: spagop
Date: 2009-12-29 17:44:44 -0500 (Tue, 29 Dec 2009)
New Revision: 1488
Modified:
trunk/extensions/dna-connector-svn/pom.xml
Log:
upgrade version svnkit to version 1.3.0
Modified: trunk/extensions/dna-connector-svn/pom.xml
===================================================================
--- trunk/extensions/dna-connector-svn/pom.xml 2009-12-29 16:27:37 UTC (rev 1487)
+++ trunk/extensions/dna-connector-svn/pom.xml 2009-12-29 22:44:44 UTC (rev 1488)
@@ -49,7 +49,7 @@
<dependency>
<groupId>org.tmatesoft.svnkit</groupId>
<artifactId>svnkit</artifactId>
- <version>1.2.3.5521</version>
+ <version>1.3.0.5847</version>
</dependency>
<!--
Testing (note the scope)
14 years, 4 months
DNA SVN: r1487 - in trunk/docs/reference/src/main/docbook/en-US/content: core and 1 other directories.
by dna-commits@lists.jboss.org
Author: bcarothers
Date: 2009-12-29 11:27:37 -0500 (Tue, 29 Dec 2009)
New Revision: 1487
Modified:
trunk/docs/reference/src/main/docbook/en-US/content/connectors/federation.xml
trunk/docs/reference/src/main/docbook/en-US/content/connectors/file_system.xml
trunk/docs/reference/src/main/docbook/en-US/content/connectors/in_memory.xml
trunk/docs/reference/src/main/docbook/en-US/content/connectors/infinispan.xml
trunk/docs/reference/src/main/docbook/en-US/content/connectors/jboss_cache.xml
trunk/docs/reference/src/main/docbook/en-US/content/connectors/jdbc_metadata.xml
trunk/docs/reference/src/main/docbook/en-US/content/connectors/jdbc_storage.xml
trunk/docs/reference/src/main/docbook/en-US/content/connectors/subversion.xml
trunk/docs/reference/src/main/docbook/en-US/content/core/graph.xml
trunk/docs/reference/src/main/docbook/en-US/content/jcr/configuration.xml
trunk/docs/reference/src/main/docbook/en-US/content/jcr/jcr.xml
trunk/docs/reference/src/main/docbook/en-US/content/jcr/rest_service.xml
Log:
DNA-595 Connector chapters in the Reference Guide should should examples of configuring in Java code and XML configuration
Applied patch that adds the XML examples as per the defect. The patch also updates the JCR section and cleans up a few places where a programlisting was overflowing horizontally.
Modified: trunk/docs/reference/src/main/docbook/en-US/content/connectors/federation.xml
===================================================================
--- trunk/docs/reference/src/main/docbook/en-US/content/connectors/federation.xml 2009-12-29 11:41:49 UTC (rev 1486)
+++ trunk/docs/reference/src/main/docbook/en-US/content/connectors/federation.xml 2009-12-29 16:27:37 UTC (rev 1487)
@@ -412,11 +412,15 @@
'Configuration' content (which is defined by this file) will appear under '/'. -->
<dna:projections>
<!-- Project the 'Cars' content, starting with the '/Cars' node. -->
- <dna:projection jcr:name="Cars projection" dna:source="Cars" dna:workspaceName="workspace1">
+ <dna:projection jcr:name="Cars projection"
+ dna:source="Cars"
+ dna:workspaceName="workspace1">
<dna:projectionRules>/Vehicles/Cars => /Cars</dna:projectionRules>
</dna:projection>
<!-- Project the 'Aicraft' content, starting with the '/Aircraft' node. -->
- <dna:projection jcr:name="Aircarft projection" dna:source="Aircraft" dna:workspaceName="workspace2">
+ <dna:projection jcr:name="Aircarft projection"
+ dna:source="Aircraft"
+ dna:workspaceName="workspace2">
<dna:projectionRules>/Vehicles/Aircraft => /Aircraft</dna:projectionRules>
</dna:projection>
<!-- Project the 'System' content. Only needed when this source is accessed through JCR. -->
Modified: trunk/docs/reference/src/main/docbook/en-US/content/connectors/file_system.xml
===================================================================
--- trunk/docs/reference/src/main/docbook/en-US/content/connectors/file_system.xml 2009-12-29 11:41:49 UTC (rev 1486)
+++ trunk/docs/reference/src/main/docbook/en-US/content/connectors/file_system.xml 2009-12-29 16:27:37 UTC (rev 1487)
@@ -132,19 +132,62 @@
</tgroup>
</table>
<para>
- The file system connector is used by creating in the &JcrConfiguration; a repository source that uses the &InMemoryRepositorySource; class.
+ 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 role="JAVA"><![CDATA[
JcrConfiguration config = ...
-config.repositorySource("source A")
+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>
-</chapter>
+ <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 role="XML"><![CDATA[
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration xmlns:dna="http://www.jboss.org/dna/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0">
+ <!--
+ Define the sources for the content. These sources are directly accessible using the
+ DNA-specific Graph API. In fact, this is how the DNA 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.
+ -->
+ <dna:sources jcr:primaryType="nt:unstructured">
+ <!--
+ The 'FS Store' repository is a file system source with a three predefined workspaces
+ ("prod", "staging", and "dev").
+ -->
+ <dna:source jcr:name="FS Store"
+ dna:classname="org.jboss.dna.connector.filesystem.FileSystemSource"
+ dna:description="The repository for our content"
+ dna:workspaceRootPath="/home/content/someApp"
+ dna:defaultWorkspaceName="prod"
+ dna:predefinedWorkspaceNames="staging, dev"
+ dna:rootNodeUuid="fd129c12-81a8-42ed-aa4b-820dba49e6f0"
+ dna:creatingWorkspacesAllowed="false"
+ dna:updatesAllowed="true"
+ />
+ </dna: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 role="JAVA"><![CDATA[
+JcrConfiguration config = new JcrConfiguration().loadFrom("/configRepository.xml");
+ ]]></programlisting>
+ </chapter>
+
Modified: trunk/docs/reference/src/main/docbook/en-US/content/connectors/in_memory.xml
===================================================================
--- trunk/docs/reference/src/main/docbook/en-US/content/connectors/in_memory.xml 2009-12-29 11:41:49 UTC (rev 1486)
+++ trunk/docs/reference/src/main/docbook/en-US/content/connectors/in_memory.xml 2009-12-29 16:27:37 UTC (rev 1487)
@@ -85,14 +85,51 @@
</tgroup>
</table>
<para>
- Using the in-memory connector is used by creating in the &JcrConfiguration; a repository source that uses the &InMemoryRepositorySource; class.
+ One way to configure the in-memory connector is to create &JcrConfiguration; instance with a repository source that uses the &InMemoryRepositorySource; class.
For example:
</para>
<programlisting role="JAVA"><![CDATA[
JcrConfiguration config = ...
-config.repositorySource("source A")
+config.repositorySource("IMR Store")
.usingClass(InMemoryRepositorySource.class)
.setDescription("The repository for our content")
.setProperty("defaultWorkspaceName", workspaceName);
]]></programlisting>
+ <para>
+ Another way to configure the in-memory connector is to create &JcrConfiguration; instance and load an XML configuration file that contains a repository source that
+ uses the &InMemoryRepositorySource; class.
+ For example a file named configRepository.xml can be created with these contents:
+ </para>
+
+ <programlisting role="XML"><![CDATA[
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration xmlns:dna="http://www.jboss.org/dna/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0">
+ <!--
+ Define the sources for the content. These sources are directly accessible using the
+ DNA-specific Graph API. In fact, this is how the DNA 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.
+ -->
+ <dna:sources jcr:primaryType="nt:unstructured">
+ <!--
+ The 'IMR Store' repository is an in-memory source with a single default workspace (though
+ others could be created, too).
+ -->
+ <dna:source jcr:name="IMR Store"
+ dna:classname="org.jboss.dna.graph.connector.inmemory.InMemoryRepositorySource"
+ dna:description="The repository for our content"
+ dna:defaultWorkspaceName="default"/>
+ </dna: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 role="JAVA"><![CDATA[
+JcrConfiguration config = new JcrConfiguration().loadFrom("/configRepository.xml");
+ ]]></programlisting>
+
</chapter>
\ No newline at end of file
Modified: trunk/docs/reference/src/main/docbook/en-US/content/connectors/infinispan.xml
===================================================================
--- trunk/docs/reference/src/main/docbook/en-US/content/connectors/infinispan.xml 2009-12-29 11:41:49 UTC (rev 1486)
+++ trunk/docs/reference/src/main/docbook/en-US/content/connectors/infinispan.xml 2009-12-29 16:27:37 UTC (rev 1487)
@@ -99,18 +99,58 @@
</tbody>
</tgroup>
</table>
- <para>
- The Infinispan connector is used by creating in the &JcrConfiguration; a repository source that uses the &InfinispanSource; class.
+ <para>
+ One way to configure the Infinispan connector is to create &JcrConfiguration; instance with a repository source that uses the &InfinispanSource; class.
For example:
</para>
<programlisting role="JAVA"><![CDATA[
JcrConfiguration config = ...
-config.repositorySource("source A")
+config.repositorySource("Infinispan Store")
.usingClass(InfinispanSource.class)
.setDescription("The repository for our content")
.setProperty("defaultWorkspaceName", "prod")
.setProperty("rootNodeUuid", UUID.fromString("84b73fc8-81a8-42ed-aa4b-3905094966f0")
.setProperty("predefinedWorkspaceNames", new String[] { "staging", "dev"});
+]]></programlisting>
+ <para>
+ Another way to configure the Infinispan connector is to create &JcrConfiguration; instance and load an XML configuration file that contains a repository source that
+ uses the &InfinispanSource; class.
+ For example a file named configRepository.xml can be created with these contents:
+ </para>
+
+ <programlisting role="XML"><![CDATA[
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration xmlns:dna="http://www.jboss.org/dna/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0">
+ <!--
+ Define the sources for the content. These sources are directly accessible using the
+ DNA-specific Graph API. In fact, this is how the DNA 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.
+ -->
+ <dna:sources jcr:primaryType="nt:unstructured">
+ <!--
+ The 'Infinispan Store' repository is a Infinispan repository with a single default
+ workspace (though others could be created, too).
+ -->
+ <dna:source jcr:name="Infinispan Store"
+ dna:classname="org.jboss.dna.graph.connector.infinispan.InfinispanSource"
+ dna:description="The repository for our content"
+ dna:defaultworkspaceName="prod"
+ dna:rootNodeUuid="84b73fc8-81a8-42ed-aa4b-3905094966f0"
+ dna:predefinedWorkspaceNames="staging,dev"/>
+ </dna: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 role="JAVA"><![CDATA[
+JcrConfiguration config = new JcrConfiguration().loadFrom("/configRepository.xml");
+ ]]></programlisting>
</chapter>
+
+
Modified: trunk/docs/reference/src/main/docbook/en-US/content/connectors/jboss_cache.xml
===================================================================
--- trunk/docs/reference/src/main/docbook/en-US/content/connectors/jboss_cache.xml 2009-12-29 11:41:49 UTC (rev 1486)
+++ trunk/docs/reference/src/main/docbook/en-US/content/connectors/jboss_cache.xml 2009-12-29 16:27:37 UTC (rev 1487)
@@ -116,17 +116,55 @@
</tgroup>
</table>
<para>
- The JBoss Cache connector is used by creating in the &JcrConfiguration; a repository source that uses the &JBossCacheSource; class.
+ One way to configure the JBoss Cache connector is to create &JcrConfiguration; instance with a repository source that uses the &JBossCacheSource; class.
For example:
</para>
<programlisting role="JAVA"><![CDATA[
JcrConfiguration config = ...
-config.repositorySource("source A")
+config.repositorySource("Store")
.usingClass(JBossCacheSource.class)
.setDescription("The repository for our content")
.setProperty("defaultWorkspaceName", "prod")
.setProperty("rootNodeUuid", UUID.fromString("12083e7e-2b55-4c8d-954d-627a9f5c45c2"))
.setProperty("predefinedWorkspaceNames", new String[] { "staging", "dev"});
]]></programlisting>
+ <para>
+ Another way to configure the JBoss Cache connector is to create &JcrConfiguration; instance and load an XML configuration file that contains a repository source that
+ uses the &JBossCacheSource; class.
+ For example a file named configRepository.xml can be created with these contents:
+ </para>
+
+ <programlisting role="XML"><![CDATA[
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration xmlns:dna="http://www.jboss.org/dna/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0">
+ <!--
+ Define the sources for the content. These sources are directly accessible using the
+ DNA-specific Graph API. In fact, this is how the DNA 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.
+ -->
+ <dna:sources jcr:primaryType="nt:unstructured">
+ <!--
+ The 'Store' repository is a JBoss Cache repository with a single default workspace (though
+ others could be created, too).
+ -->
+ <dna:source jcr:name="Store"
+ dna:classname="org.jboss.dna.graph.connector.jbosscache.JBossCacheSource"
+ dna:description="The repository for our content"
+ dna:defaultworkspaceName="prod"
+ dna:rootNodeUuid="12083e7e-2b55-4c8d-954d-627a9f5c45c2"
+ dna:predefinedWorkspaceNames="staging,dev"/>
+ </dna: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 role="JAVA"><![CDATA[
+JcrConfiguration config = new JcrConfiguration().loadFrom("/configRepository.xml");
+ ]]></programlisting>
</chapter>
Modified: trunk/docs/reference/src/main/docbook/en-US/content/connectors/jdbc_metadata.xml
===================================================================
--- trunk/docs/reference/src/main/docbook/en-US/content/connectors/jdbc_metadata.xml 2009-12-29 11:41:49 UTC (rev 1486)
+++ trunk/docs/reference/src/main/docbook/en-US/content/connectors/jdbc_metadata.xml 2009-12-29 16:27:37 UTC (rev 1487)
@@ -77,7 +77,7 @@
</row>
<row>
<entry>rootNodeUuid</entry>
- <entry>Optional property that, if used, defines the UUID of the root node in the in-memory repository. If not used,
+ <entry>Optional property that, if used, defines the UUID of the root node in the repository. If not used,
then a new UUID is generated.</entry>
</row>
<row>
@@ -210,21 +210,58 @@
</tbody>
</tgroup>
</table>
- <para>
- The JDBC metadata connector is used by creating in the &JcrConfiguration; a repository source that uses the &JdbcMetadataSource; class.
+ <para>
+ One way to configure the JDBC metadata connector is to create &JcrConfiguration; instance with a repository source that uses the &JdbcMetadataSource; class.
For example:
</para>
<programlisting role="JAVA"><![CDATA[
JcrConfiguration config = ...
-config.repositorySource("source A")
+config.repositorySource("Meta Store")
.usingClass(JdbcMetadataSource.class)
- .setDescription("The database store for our content")
+ .setDescription("The database source for our content")
.setProperty("dataSourceJndiName", "java:/MyDataSource")
- .setProperty("nameOfDefaultWorkspace", "default")
- ]]></programlisting>
+ .setProperty("nameOfDefaultWorkspace", "default");
+]]></programlisting>
<para>
Of course, setting other more advanced properties would entail calling <code>setProperty(...)</code> for each. Since almost all
of the properties have acceptable default values, however, we don't need to set very many of them.
</para>
-</chapter>
+ <para>
+ Another way to configure the JDBC metadata connector is to create &JcrConfiguration; instance and load an XML configuration file that contains a repository source that
+ uses the &JdbcMetadataSource; class.
+ For example a file named configRepository.xml can be created with these contents:
+ </para>
+
+ <programlisting role="XML"><![CDATA[
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration xmlns:dna="http://www.jboss.org/dna/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0">
+ <!--
+ Define the sources for the content. These sources are directly accessible using the
+ DNA-specific Graph API. In fact, this is how the DNA 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.
+ -->
+ <dna:sources jcr:primaryType="nt:unstructured">
+ <!--
+ The 'Meta Store' repository is a JDBC metadata repository with a single default
+ workspace (though others could be created, too).
+ -->
+ <dna:source jcr:name="Meta Store"
+ dna:classname="org.jboss.dna.graph.connector.meta.jdbc.JdbcMetadataSource"
+ dna:description="The database source for our content"
+ dna:dataSourceJndiName="java:/MyDataSource"
+ dna:defaultworkspaceName="default"/>
+ </dna: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 role="JAVA"><![CDATA[
+JcrConfiguration config = new JcrConfiguration().loadFrom("/configRepository.xml");
+ ]]></programlisting>
+ </chapter>
Modified: trunk/docs/reference/src/main/docbook/en-US/content/connectors/jdbc_storage.xml
===================================================================
--- trunk/docs/reference/src/main/docbook/en-US/content/connectors/jdbc_storage.xml 2009-12-29 11:41:49 UTC (rev 1486)
+++ trunk/docs/reference/src/main/docbook/en-US/content/connectors/jdbc_storage.xml 2009-12-29 16:27:37 UTC (rev 1487)
@@ -29,7 +29,7 @@
%CustomDTD;
]>
<chapter id="jdbc-storage-connector">
- <title>JDBC Storage (JPA) Connector</title>
+ <title>JPA Connector</title>
<para>
This connector stores a graph of any structure or size in a relational database, using a JPA provider on top of a JDBC driver.
Currently this connector relies upon some Hibernate-specific capabilities. The schema of the database is dictated by this
@@ -62,7 +62,7 @@
</row>
<row>
<entry>rootNodeUuid</entry>
- <entry>Optional property that, if used, defines the UUID of the root node in the in-memory repository. If not used,
+ <entry>Optional property that, if used, defines the UUID of the root node in the repository. If not used,
then a new UUID is generated.</entry>
</row>
<row>
@@ -251,25 +251,64 @@
</tbody>
</tgroup>
</table>
- <para>
- The JPA connector is used by creating in the &JcrConfiguration; a repository source that uses the &JpaSource; class.
+ <para>
+ One way to configure the JPA connector is to create &JcrConfiguration; instance with a repository source that uses the &JpaSource; class.
For example:
</para>
<programlisting role="JAVA"><![CDATA[
JcrConfiguration config = ...
-config.repositorySource("source A")
+config.repositorySource("JPA Store")
.usingClass(JpaSource.class)
.setDescription("The database store for our content")
.setProperty("dialect", "org.hibernate.dialect.MySQLDialect")
.setProperty("dataSourceJndiName", "java:/MyDataSource")
- .setProperty("nameOfDefaultWorkspace", "My Default Workspace")
+ .setProperty("defaultWorkspaceName", "My Default Workspace")
.setProperty("autoGenerateSchema", "validate");
]]></programlisting>
- <para>
+ <para>
Of course, setting other more advanced properties would entail calling <code>setProperty(...)</code> for each. Since almost all
of the properties have acceptable default values, however, we don't need to set very many of them.
</para>
+ <para>
+ Another way to configure the JPA connector is to create &JcrConfiguration; instance and load an XML configuration file that contains a repository source that
+ uses the &JpaSource; class.
+ For example a file named configRepository.xml can be created with these contents:
+ </para>
+
+ <programlisting role="XML"><![CDATA[
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration xmlns:dna="http://www.jboss.org/dna/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0">
+ <!--
+ Define the sources for the content. These sources are directly accessible using the
+ DNA-specific Graph API. In fact, this is how the DNA 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.
+ -->
+ <dna:sources jcr:primaryType="nt:unstructured">
+ <!--
+ The 'JPA Store' repository is an JPA source with a single default workspace (though
+ others could be created, too).
+ -->
+ <dna:source jcr:name="JPA Store"
+ dna:classname="org.jboss.dna.graph.connector.store.jpa.JpaSource"
+ dna:description="The database store for our content"
+ dna:dialect="org.hibernate.dialect.MySQLDialect"
+ dna:dataSourceJndiName="java:/MyDataSource"
+ dna:defaultWorkspaceName="default"
+ dna:autoGenerateSchema="validate"/>
+ </dna: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 role="JAVA"><![CDATA[
+JcrConfiguration config = new JcrConfiguration().loadFrom("/configRepository.xml");
+ ]]></programlisting>
+ <para>
DNA users who prefer not to give DDL privileges to the DNA database user for this connector can use the DNA JPA DDL generation
tool to create the proper DDL files for their database dialect. This tool is packaged as an executable jar in the
utils/dna-jpa-ddl-gen subproject and can be executed with the following syntax:
Modified: trunk/docs/reference/src/main/docbook/en-US/content/connectors/subversion.xml
===================================================================
--- trunk/docs/reference/src/main/docbook/en-US/content/connectors/subversion.xml 2009-12-29 11:41:49 UTC (rev 1486)
+++ trunk/docs/reference/src/main/docbook/en-US/content/connectors/subversion.xml 2009-12-29 16:27:37 UTC (rev 1487)
@@ -108,25 +108,57 @@
</tbody>
</tgroup>
</table>
- <para>
- Using the SVN connector can be used by creating in the &JcrConfiguration; a repository source that uses the &SVNRepositorySource; class.
+ <para>
+ One way to configure the Subversion connector is to create &JcrConfiguration; instance with a repository source that uses the &SVNRepositorySource; class.
For example:
</para>
<programlisting role="JAVA"><![CDATA[
JcrConfiguration config = ...
-config.repositorySource("SVN repository for JBoss DNA")
+config.repositorySource("SVN Store")
.usingClass(SVNRepositorySource.class)
.setDescription("The DNA SVN repository (anonymous access)")
.setProperty("repositoryRootUrl", "http://anonsvn.jboss.org/repos/dna");
.setProperty("directoryForDefaultWorkspace", "http://anonsvn.jboss.org/repos/dna/trunk");
- .setProperty("predefinedWorkspaceNames", new String[] {
- "http://anonsvn.jboss.org/repos/dna/trunk",
- "http://anonsvn.jboss.org/repos/dna/tags/0.1",
- "http://anonsvn.jboss.org/repos/dna/tags/0.2",
- "http://anonsvn.jboss.org/repos/dna/tags/0.3",
- "http://anonsvn.jboss.org/repos/dna/tags/0.4",
- "http://anonsvn.jboss.org/repos/dna/tags/0.5",
- "http://anonsvn.jboss.org/repos/dna/tags/0.6"
- });
+ .setProperty("predefinedWorkspaceNames", new String[] {"http://anonsvn.jboss.org/repos/dna/trunk });
]]></programlisting>
+ <para>
+ Another way to configure the Subversion connector is to create &JcrConfiguration; instance and load an XML configuration file that contains a repository source that
+ uses the &SVNRepositorySource; class.
+ For example a file named configRepository.xml can be created with these contents:
+ </para>
+
+ <programlisting role="XML"><![CDATA[
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration xmlns:dna="http://www.jboss.org/dna/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0">
+ <!--
+ Define the sources for the content. These sources are directly accessible using the
+ DNA-specific Graph API. In fact, this is how the DNA 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.
+ -->
+ <dna:sources jcr:primaryType="nt:unstructured">
+ <!--
+ The 'SVN Store' repository is an Subversion source with one workspace (although others could
+ be defined).
+ -->
+ <dna:source jcr:name="SVN Store"
+ dna:classname="org.jboss.dna.graph.connector.svn.SVNRepositorySource"
+ dna:description="The DNA SVN repository (anonymous access)"
+ dna:repositoryRootUrl="http://anonsvn.jboss.org/repos/dna"
+ dna:directoryForDefaultWorkspace="http://anonsvn.jboss.org/repos/dna/trunk"
+ dna:predefinedWorkspaceNames="http://anonsvn.jboss.org/repos/dna/trunk"
+ dna:defaultWorkspaceName="default"/>
+ </dna: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 role="JAVA"><![CDATA[
+JcrConfiguration config = new JcrConfiguration().loadFrom("/configRepository.xml");
+ ]]></programlisting>
+
</chapter>
Modified: trunk/docs/reference/src/main/docbook/en-US/content/core/graph.xml
===================================================================
--- trunk/docs/reference/src/main/docbook/en-US/content/core/graph.xml 2009-12-29 11:41:49 UTC (rev 1486)
+++ trunk/docs/reference/src/main/docbook/en-US/content/core/graph.xml 2009-12-29 16:27:37 UTC (rev 1487)
@@ -208,7 +208,8 @@
</para>
<programlisting>
@Immutable
-public static interface &PathSegment; extends Cloneable, Comparable<&PathSegment;>, &Serializable;, &Readable; {
+public static interface &PathSegment; extends Cloneable, Comparable<&PathSegment;>, &Serializable;, &Readable;
+{
/**
* Get the name component of this segment.
Modified: trunk/docs/reference/src/main/docbook/en-US/content/jcr/configuration.xml
===================================================================
--- trunk/docs/reference/src/main/docbook/en-US/content/jcr/configuration.xml 2009-12-29 11:41:49 UTC (rev 1486)
+++ trunk/docs/reference/src/main/docbook/en-US/content/jcr/configuration.xml 2009-12-29 16:27:37 UTC (rev 1487)
@@ -185,7 +185,8 @@
</dna:repository>
</dna:repositories>
<!--
- Define the sources for the content. These sources are directly accessible using the DNA-specific Graph API.
+ Define the sources for the content. These sources are directly accessible using the
+ DNA-specific Graph API.
-->
<dna:sources jcr:primaryType="nt:unstructured">
<dna:source jcr:name="Cars"
Modified: trunk/docs/reference/src/main/docbook/en-US/content/jcr/jcr.xml
===================================================================
--- trunk/docs/reference/src/main/docbook/en-US/content/jcr/jcr.xml 2009-12-29 11:41:49 UTC (rev 1486)
+++ trunk/docs/reference/src/main/docbook/en-US/content/jcr/jcr.xml 2009-12-29 16:27:37 UTC (rev 1487)
@@ -211,10 +211,11 @@
<sect2>
<title>Optional Features</title>
<para>
- JBoss DNA does not currently support any of the optional JCR features. Currently, the observation optional feature is planned to be complete prior
- to the 1.0 release. The locking optional feature <emphasis>may</emphasis> be implemented in this time frame as well.
+ JBoss DNA does currently supports the optional JCR locking feature. Currently, the observation optional feature is planned to be complete prior
+ to the 1.0 release.
<note>
- <para>The JCR-SQL optional feature is not planned to be implemented as it has been dropped from the <ulink url="&JSR283;">JSR-283</ulink> specification.
+ <para>
+ The JCR-SQL optional feature is not planned to be implemented as it has been dropped from the <ulink url="&JSR283;">JSR-283</ulink> specification.
</para>
</note>
</para>
@@ -227,9 +228,11 @@
and workspace level.
</para>
<para>
- JBoss DNA has extended the set of JCR-defined actions ("add_node", "set_property", "remove", and "read") with additional actions ("register_type" and
- "register_namespace") that restrict the ability to register (and unregister) types and namespaces, respectively. Permissions to perform these actions are aggregated in roles that
- can be assigned to users.
+ JBoss DNA has extended the set of JCR-defined actions ("add_node", "set_property", "remove", and "read") with additional actions ("register_type",
+ "register_namespace", and "unlock_any"). The register_type and register_namespace permissions restrict the ability to register (and unregister) types and namespaces, respectively.
+ The unlock_any permission grants the user the ability to unlock any locked node or branch (as opposed to users without that permission who can only unlock nodes or branches that they
+ have locked themselves or for which they hold the lock token).
+ Permissions to perform these actions are aggregated in roles that can be assigned to users.
</para>
<para>
JBoss DNA currently defines three roles: <code>READONLY</code>, <code>READWRITE</code>, and <code>ADMIN</code>. If the &Credentials; passed into
@@ -289,6 +292,12 @@
<entry></entry>
<entry>Allows</entry>
</row>
+ <row>
+ <entry>unlock_any</entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>Allows</entry>
+ </row>
</tbody>
</tgroup>
</table>
@@ -344,11 +353,11 @@
<sect2>
<title>Built-In Node Types</title>
<para>JBoss DNA supports all of the built-in node types described in the JSR-170 specification. However, several of these node types
- (mix:lockable, mix:versionable, nt:version, nt:versionLabels, nt:versionHistory, and nt:frozenNode) are semantically meaningless
- as JBoss DNA does not yet support the locking or versioning optional features.
+ (mix:versionable, nt:version, nt:versionLabels, nt:versionHistory, and nt:frozenNode) are semantically meaningless
+ as JBoss DNA does not yet support the versioning optional feature.
</para>
<para>Although JBoss DNA does define some custom node types in the <code>dna</code> namespace, none of these
- node types are intended to be used by developers integrating with JBoss DNA and may be changed or removed
+ node types except for <code>dna:resource</code> are intended to be used by developers integrating with JBoss DNA and may be changed or removed
at any time.
</para>
</sect2>
@@ -375,9 +384,10 @@
Node types can be defined like so:
<programlisting>
&Session; session = ... ;
+&Workspace; workspace = session.getWorkspace();
// Obtain the DNA-specific node type manager ...
-&JcrNodeTypeManager; nodeTypeManager = (JcrNodeTypeManager) session.getWorkspace().getNodeTypeManager();
+&JcrNodeTypeManager; nodeTypeManager = (JcrNodeTypeManager) workspace.getNodeTypeManager();
// Declare a mixin node type named "searchable" (with no namespace)
&NodeTypeTemplate; nodeType = nodeTypeManager.createNodeTypeTemplate();
@@ -429,7 +439,8 @@
&Session; session = ... ;
// Obtain the DNA-specific node type manager ...
-&JcrNodeTypeManager; nodeTypeManager = (JcrNodeTypeManager) session.getWorkspace().getNodeTypeManager();
+&Workspace; workspace = session.getWorkspace();
+&JcrNodeTypeManager; nodeTypeManager = (JcrNodeTypeManager) workspace.getNodeTypeManager();
nodeTypeManager.registerNodeTypes(nodeTypeSource);
</programlisting>
The &CndNodeTypeSource; class actually implements the &JcrNodeTypeSource; interface, so other implementations can actually be defined.
Modified: trunk/docs/reference/src/main/docbook/en-US/content/jcr/rest_service.xml
===================================================================
--- trunk/docs/reference/src/main/docbook/en-US/content/jcr/rest_service.xml 2009-12-29 11:41:49 UTC (rev 1486)
+++ trunk/docs/reference/src/main/docbook/en-US/content/jcr/rest_service.xml 2009-12-29 16:27:37 UTC (rev 1487)
@@ -250,11 +250,12 @@
"jcr:primaryType": "nt:unstructured",
"jcr:uuid": "163bc5e5-3b57-4e63-b2ae-ededf43d3445"
"options": [ "1", "2" ]
- "content/base64/": "TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieSB0aGlz
- IHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbmltYWxzLCB3aGljaCBpcyBhIGx1c3Qgb2Yg
- dGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodCBpbiB0aGUgY29udGlu
- dWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25vd2xlZGdlLCBleGNlZWRzIHRo
- ZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS4="
+ "content/base64/":
+ "TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieSB0aGlz
+IHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbmltYWxzLCB3aGljaCBpcyBhIGx1c3Qgb2Yg
+dGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodCBpbiB0aGUgY29udGlu
+dWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25vd2xlZGdlLCBleGNlZWRzIHRo
+ZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS4="
},
}
]]></programlisting>
14 years, 4 months
DNA SVN: r1486 - trunk/extensions/dna-connector-filesystem/src/test/java/org/jboss/dna/connector/filesystem.
by dna-commits@lists.jboss.org
Author: bcarothers
Date: 2009-12-29 06:41:49 -0500 (Tue, 29 Dec 2009)
New Revision: 1486
Modified:
trunk/extensions/dna-connector-filesystem/src/test/java/org/jboss/dna/connector/filesystem/FileSystemSourceTest.java
Log:
DNA-603 File System Repository Should Be Ported To Use Path Repository
Usual removal of @Override tag to fix usual Java5 compile error
Modified: trunk/extensions/dna-connector-filesystem/src/test/java/org/jboss/dna/connector/filesystem/FileSystemSourceTest.java
===================================================================
--- trunk/extensions/dna-connector-filesystem/src/test/java/org/jboss/dna/connector/filesystem/FileSystemSourceTest.java 2009-12-29 11:18:11 UTC (rev 1485)
+++ trunk/extensions/dna-connector-filesystem/src/test/java/org/jboss/dna/connector/filesystem/FileSystemSourceTest.java 2009-12-29 11:41:49 UTC (rev 1486)
@@ -56,27 +56,21 @@
this.source.setName("Test Repository");
this.source.initialize(new RepositoryContext() {
- @Override
public Subgraph getConfiguration( int depth ) {
return null;
}
- @Override
public ExecutionContext getExecutionContext() {
return context;
}
- @Override
public Observer getObserver() {
- // TODO Auto-generated method stub
return null;
}
- @Override
public RepositoryConnectionFactory getRepositoryConnectionFactory() {
return new RepositoryConnectionFactory() {
- @Override
public RepositoryConnection createConnection( String sourceName ) throws RepositorySourceException {
return source.getConnection();
}
14 years, 4 months
DNA SVN: r1485 - trunk/extensions/dna-connector-filesystem/src/main/java/org/jboss/dna/connector/filesystem.
by dna-commits@lists.jboss.org
Author: bcarothers
Date: 2009-12-29 06:18:11 -0500 (Tue, 29 Dec 2009)
New Revision: 1485
Modified:
trunk/extensions/dna-connector-filesystem/src/main/java/org/jboss/dna/connector/filesystem/FileSystemRepository.java
trunk/extensions/dna-connector-filesystem/src/main/java/org/jboss/dna/connector/filesystem/FileSystemSource.java
Log:
DNA-603 File System Repository Should Be Ported To Use Path Repository
Usual removal of @Override tag to fix usual Java5 compile error
Modified: trunk/extensions/dna-connector-filesystem/src/main/java/org/jboss/dna/connector/filesystem/FileSystemRepository.java
===================================================================
--- trunk/extensions/dna-connector-filesystem/src/main/java/org/jboss/dna/connector/filesystem/FileSystemRepository.java 2009-12-29 04:25:02 UTC (rev 1484)
+++ trunk/extensions/dna-connector-filesystem/src/main/java/org/jboss/dna/connector/filesystem/FileSystemRepository.java 2009-12-29 11:18:11 UTC (rev 1485)
@@ -192,7 +192,6 @@
this.context = context;
}
- @Override
public PathNode createNode( ExecutionContext context,
PathNode parentNode,
Name name,
@@ -386,7 +385,6 @@
return getNode(newPath);
}
- @Override
public boolean removeNode( ExecutionContext context,
Path nodePath ) {
File nodeFile;
@@ -419,7 +417,6 @@
return true;
}
- @Override
public PathNode removeProperties( ExecutionContext context,
Path nodePath,
Iterable<Name> propertyNames ) {
@@ -456,7 +453,6 @@
return getNode(nodePath);
}
- @Override
public PathNode setProperties( ExecutionContext context,
Path nodePath,
Iterable<Property> newProperties ) {
@@ -505,7 +501,6 @@
return super.moveNode(context, node, desiredNewName, originalWorkspace, newParent, beforeNode);
}
- @Override
public Path getLowestExistingPath( Path path ) {
File file = workspaceRoot;
for (Path.Segment segment : path) {
@@ -535,7 +530,6 @@
return path;
}
- @Override
public PathNode getNode( Path path ) {
Map<Name, Property> properties = new HashMap<Name, Property>();
Modified: trunk/extensions/dna-connector-filesystem/src/main/java/org/jboss/dna/connector/filesystem/FileSystemSource.java
===================================================================
--- trunk/extensions/dna-connector-filesystem/src/main/java/org/jboss/dna/connector/filesystem/FileSystemSource.java 2009-12-29 04:25:02 UTC (rev 1484)
+++ trunk/extensions/dna-connector-filesystem/src/main/java/org/jboss/dna/connector/filesystem/FileSystemSource.java 2009-12-29 11:18:11 UTC (rev 1485)
@@ -464,12 +464,10 @@
this.repositoryContext = context;
}
- @Override
public RepositoryContext getRepositoryContext() {
return this.repositoryContext;
}
- @Override
public CachePolicy getDefaultCachePolicy() {
return defaultCachePolicy;
}
14 years, 4 months
DNA SVN: r1484 - in trunk: dna-graph/src/main/java/org/jboss/dna/graph/connector/path and 6 other directories.
by dna-commits@lists.jboss.org
Author: bcarothers
Date: 2009-12-28 23:25:02 -0500 (Mon, 28 Dec 2009)
New Revision: 1484
Added:
trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/path/AbstractWritablePathWorkspace.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/path/PathRepositoryTransaction.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/path/WritablePathRepository.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/path/WritablePathWorkspace.java
trunk/extensions/dna-connector-filesystem/src/main/java/org/jboss/dna/connector/filesystem/FileSystemRepository.java
Removed:
trunk/extensions/dna-connector-filesystem/src/main/java/org/jboss/dna/connector/filesystem/FileSystemConnection.java
trunk/extensions/dna-connector-filesystem/src/main/java/org/jboss/dna/connector/filesystem/FileSystemRequestProcessor.java
Modified:
trunk/dna-graph/src/main/java/org/jboss/dna/graph/GraphI18n.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/path/DefaultPathNode.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/path/PathNode.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/path/PathRepository.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/path/PathRepositoryConnection.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/path/PathRepositorySource.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/path/PathRequestProcessor.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/path/PathWorkspace.java
trunk/dna-graph/src/main/resources/org/jboss/dna/graph/GraphI18n.properties
trunk/extensions/dna-connector-filesystem/src/main/java/org/jboss/dna/connector/filesystem/FileSystemI18n.java
trunk/extensions/dna-connector-filesystem/src/main/java/org/jboss/dna/connector/filesystem/FileSystemSource.java
trunk/extensions/dna-connector-filesystem/src/main/java/org/jboss/dna/connector/filesystem/FileSystemTransaction.java
trunk/extensions/dna-connector-filesystem/src/main/java/org/jboss/dna/connector/filesystem/package-info.java
trunk/extensions/dna-connector-filesystem/src/main/resources/org/jboss/dna/connector/filesystem/FileSystemI18n.properties
trunk/extensions/dna-connector-filesystem/src/test/java/org/jboss/dna/connector/filesystem/FileSystemSourceTest.java
trunk/extensions/dna-connector-jdbc-metadata/src/main/java/org/jboss/dna/connector/meta/jdbc/JdbcMetadataI18n.java
trunk/extensions/dna-connector-jdbc-metadata/src/main/java/org/jboss/dna/connector/meta/jdbc/JdbcMetadataRepository.java
trunk/extensions/dna-connector-jdbc-metadata/src/main/java/org/jboss/dna/connector/meta/jdbc/JdbcMetadataSource.java
trunk/extensions/dna-connector-jdbc-metadata/src/main/resources/org/jboss/dna/connector/meta/jdbc/JdbcMetadataI18n.properties
Log:
DNA-603 File System Repository Should Be Ported To Use Path Repository
Applied patch that augments the path repository framework to support writes and moves the file system repository over onto the framework. All tests pass.
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/GraphI18n.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/GraphI18n.java 2009-12-27 20:45:58 UTC (rev 1483)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/GraphI18n.java 2009-12-29 04:25:02 UTC (rev 1484)
@@ -104,6 +104,7 @@
public static I18n workspaceDoesNotExistInRepository;
public static I18n workspaceAlreadyExistsInRepository;
public static I18n sourceIsReadOnly;
+ public static I18n workspaceIsReadOnly;
/* Federation Connection */
public static I18n namePropertyIsRequiredForFederatedRepositorySource;
Added: trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/path/AbstractWritablePathWorkspace.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/path/AbstractWritablePathWorkspace.java (rev 0)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/path/AbstractWritablePathWorkspace.java 2009-12-29 04:25:02 UTC (rev 1484)
@@ -0,0 +1,137 @@
+/*
+ * JBoss DNA (http://www.jboss.org/dna)
+ * 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.
+ *
+ * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
+ * 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.
+ *
+ * JBoss DNA 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 software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.dna.graph.connector.path;
+
+import java.util.Map;
+import java.util.UUID;
+import org.jboss.dna.graph.ExecutionContext;
+import org.jboss.dna.graph.NodeConflictBehavior;
+import org.jboss.dna.graph.connector.LockFailedException;
+import org.jboss.dna.graph.property.Name;
+import org.jboss.dna.graph.property.Path;
+import org.jboss.dna.graph.property.PathFactory;
+import org.jboss.dna.graph.property.Property;
+import org.jboss.dna.graph.property.Path.Segment;
+import org.jboss.dna.graph.query.QueryResults;
+import org.jboss.dna.graph.request.AccessQueryRequest;
+import org.jboss.dna.graph.request.LockBranchRequest.LockScope;
+
+/**
+ * Implementation of some methods from {@link WritablePathWorkspace} to assist in the development of path-based connectors.
+ * Subclasses of this class should be made thread-safe.
+ */
+public abstract class AbstractWritablePathWorkspace implements WritablePathWorkspace {
+
+ private final String name;
+ protected final UUID rootNodeUuid;
+
+ public AbstractWritablePathWorkspace( String name,
+ UUID rootNodeUuid ) {
+ super();
+ this.name = name;
+ this.rootNodeUuid = rootNodeUuid;
+ }
+
+ /**
+ * This should copy the subgraph rooted at the original node and place the new copy under the supplied new parent. Note that
+ * internal references between nodes within the original subgraph must be reflected as internal nodes within the new subgraph.
+ *
+ * @param context the context; may not be null
+ * @param original the node to be copied; may not be null
+ * @param originalWorkspace the workspace containing the original node; may not be null
+ * @param newParent the parent where the copy is to be placed; may not be null
+ * @param desiredName the desired name for the node; if null, the name will be obtained from the original node
+ * @param recursive true if the copy should be recursive
+ * @return the new node, which is the top of the new subgraph
+ */
+ public PathNode copyNode( ExecutionContext context,
+ PathNode original,
+ PathWorkspace originalWorkspace,
+ PathNode newParent,
+ Name desiredName,
+ boolean recursive ) {
+ PathFactory pathFactory = context.getValueFactories().getPathFactory();
+ PathNode copy = createNode(context, newParent, desiredName, original.getProperties(), NodeConflictBehavior.REPLACE);
+
+ if (recursive) {
+ Path originalPath = original.getPath();
+
+ for (Segment childSegment : original.getChildSegments()) {
+ Path childPath = pathFactory.create(originalPath, childSegment);
+ PathNode childNode = originalWorkspace.getNode(childPath);
+ copyNode(context, childNode, originalWorkspace, copy, childSegment.getName(), true);
+ }
+ }
+ return copy;
+ }
+
+ public PathNode createNode( ExecutionContext context,
+ String pathToNewNode,
+ Map<Name, Property> properties,
+ NodeConflictBehavior conflictBehavior ) {
+ PathFactory pathFactory = context.getValueFactories().getPathFactory();
+ Path newPath = pathFactory.create(pathToNewNode);
+
+ return createNode(context, getNode(newPath.getParent()), newPath.getLastSegment().getName(), properties, conflictBehavior);
+ }
+
+ public PathNode moveNode( ExecutionContext context,
+ PathNode node,
+ Name desiredNewName,
+ WritablePathWorkspace originalWorkspace,
+ PathNode newParent,
+ PathNode beforeNode ) {
+ if (desiredNewName == null) {
+ assert !node.getPath().isRoot();
+ desiredNewName = node.getPath().getLastSegment().getName();
+ }
+
+ PathNode newCopy = copyNode(context, node, originalWorkspace, newParent, desiredNewName, true);
+ originalWorkspace.removeNode(context, node.getPath());
+ return newCopy;
+ }
+
+ public QueryResults query( ExecutionContext context,
+ AccessQueryRequest accessQuery ) {
+ return null;
+ }
+
+ public QueryResults search( ExecutionContext context,
+ String fullTextSearchExpression ) {
+ return null;
+ }
+
+ public String getName() {
+ return this.name;
+ }
+
+ public void lockNode( PathNode node,
+ LockScope lockScope,
+ long lockTimeoutInMillis ) throws LockFailedException {
+ }
+
+ public void unlockNode( PathNode node ) {
+ }
+
+}
Property changes on: trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/path/AbstractWritablePathWorkspace.java
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/path/DefaultPathNode.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/path/DefaultPathNode.java 2009-12-27 20:45:58 UTC (rev 1483)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/path/DefaultPathNode.java 2009-12-29 04:25:02 UTC (rev 1484)
@@ -5,6 +5,7 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.UUID;
import net.jcip.annotations.Immutable;
import org.jboss.dna.graph.ExecutionContext;
import org.jboss.dna.graph.property.Name;
@@ -22,13 +23,16 @@
private final Path path;
private final Map<Name, Property> properties;
private final List<Segment> childSegments;
+ private final UUID uuid;
private Set<Name> uniqueChildNames;
public DefaultPathNode( Path path,
+ UUID uuid,
Map<Name, Property> properties,
List<Segment> childSegments ) {
super();
this.path = path;
+ this.uuid = uuid;
this.properties = properties;
this.childSegments = childSegments;
}
@@ -41,6 +45,10 @@
return this.path;
}
+ public UUID getUuid() {
+ return this.uuid;
+ }
+
public Map<Name, Property> getProperties() {
return Collections.unmodifiableMap(this.properties);
}
@@ -70,4 +78,5 @@
return null;
}
+
}
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/path/PathNode.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/path/PathNode.java 2009-12-27 20:45:58 UTC (rev 1483)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/path/PathNode.java 2009-12-29 04:25:02 UTC (rev 1484)
@@ -3,6 +3,7 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.UUID;
import org.jboss.dna.graph.ExecutionContext;
import org.jboss.dna.graph.property.Name;
import org.jboss.dna.graph.property.NameFactory;
@@ -22,6 +23,14 @@
public Path getPath();
/**
+ * Returns the UUID for this node. Only the root node in a {@link PathWorkspace} should have a UUID. All other nodes should
+ * return null from this method.
+ *
+ * @return the UUID for this node; may be null
+ */
+ public UUID getUuid();
+
+ /**
* Returns the set of child names for this node
*
* @return the set of child names for this node
@@ -57,5 +66,4 @@
* @return a map of property names to the property for the given name
*/
public Map<Name, Property> getProperties();
-
}
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/path/PathRepository.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/path/PathRepository.java 2009-12-27 20:45:58 UTC (rev 1483)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/path/PathRepository.java 2009-12-29 04:25:02 UTC (rev 1484)
@@ -1,18 +1,21 @@
package org.jboss.dna.graph.connector.path;
-import java.util.HashMap;
-import java.util.Map;
import java.util.Set;
import java.util.UUID;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import net.jcip.annotations.ThreadSafe;
import org.jboss.dna.common.util.CheckArg;
+@ThreadSafe
public abstract class PathRepository {
protected final UUID rootNodeUuid;
private final String sourceName;
private final String defaultWorkspaceName;
- protected final Map<String, PathWorkspace> workspaces = new HashMap<String, PathWorkspace>();
+ protected final ConcurrentMap<String, PathWorkspace> workspaces = new ConcurrentHashMap<String, PathWorkspace>();
+
/**
* Creates a {@code PathRepository} with the given repository source name, root node UUID, and a default workspace named
* {@code ""} (the empty string).
@@ -103,4 +106,31 @@
*/
protected abstract void initialize();
+ /**
+ * Begin a transaction, hinting whether the transaction will be used only to read the content. If this is called, then the
+ * transaction must be either {@link PathRepositoryTransaction#commit() committed} or
+ * {@link PathRepositoryTransaction#rollback() rolled back}.
+ *
+ * @param readonly true if the transaction will not modify any content, or false if changes are to be made
+ * @return the transaction; never null
+ * @see PathRepositoryTransaction#commit()
+ * @see PathRepositoryTransaction#rollback()
+ */
+ public PathRepositoryTransaction startTransaction( boolean readonly ) {
+
+ // Read-only repositories can return a default NOP implementation
+ return new PathRepositoryTransaction() {
+
+ public void commit() {
+ }
+
+ public void rollback() {
+ }
+
+ };
+ }
+
+ public boolean isWritable() {
+ return false;
+ }
}
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/path/PathRepositoryConnection.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/path/PathRepositoryConnection.java 2009-12-27 20:45:58 UTC (rev 1483)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/path/PathRepositoryConnection.java 2009-12-29 04:25:02 UTC (rev 1484)
@@ -76,21 +76,49 @@
sw = new Stopwatch();
sw.start();
}
+
// Do any commands update/write?
+ PathRepositoryTransaction txn = repository.startTransaction(request.isReadOnly());
RepositoryContext repositoryContext = this.source.getRepositoryContext();
Observer observer = repositoryContext != null ? repositoryContext.getObserver() : null;
- RequestProcessor processor = new PathRequestProcessor(context, this.repository, observer);
+ RequestProcessor processor = new PathRequestProcessor(context, this.repository, observer, source.areUpdatesAllowed());
+ boolean commit = true;
try {
// Obtain the lock and execute the commands ...
processor.process(request);
+ if (request.hasError() && !request.isReadOnly()) {
+ // The changes failed, so we need to rollback so we have 'all-or-nothing' behavior
+ commit = false;
+ }
+ } catch (Throwable error) {
+ commit = false;
} finally {
try {
processor.close();
} finally {
- processor.notifyObserverOfChanges();
+ // Now commit or rollback ...
+ try {
+ if (commit) {
+ txn.commit();
+ } else {
+ // Need to rollback the changes made to the repository ...
+ txn.rollback();
+ }
+ } catch (Throwable commitOrRollbackError) {
+ if (commit && !request.hasError() && !request.isFrozen()) {
+ // Record the error on the request ...
+ request.setError(commitOrRollbackError);
+ }
+ commit = false; // couldn't do it
+ }
+ if (commit) {
+ // Now that we've closed our transaction, we can notify the observer of the committed changes ...
+ processor.notifyObserverOfChanges();
+ }
}
}
+
if (logger.isTraceEnabled()) {
assert sw != null;
sw.stop();
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/path/PathRepositorySource.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/path/PathRepositorySource.java 2009-12-27 20:45:58 UTC (rev 1483)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/path/PathRepositorySource.java 2009-12-29 04:25:02 UTC (rev 1484)
@@ -11,6 +11,23 @@
public interface PathRepositorySource extends RepositorySource {
/**
+ * Get whether this source allows updates.
+ *
+ * @return true if this source allows updates by clients, or false if no updates are allowed
+ * @see #setUpdatesAllowed(boolean)
+ */
+ boolean areUpdatesAllowed();
+
+ /**
+ * Set whether this source allows updates to data within workspaces
+ *
+ * @param updatesAllowed true if this source allows updates to data within workspaces clients, or false if updates are not
+ * allowed.
+ * @see #areUpdatesAllowed()
+ */
+ void setUpdatesAllowed( boolean updatesAllowed );
+
+ /**
* Returns the {@link CachePolicy cache policy} for the repository source
*
* @return the {@link CachePolicy cache policy} for the repository source
Added: trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/path/PathRepositoryTransaction.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/path/PathRepositoryTransaction.java (rev 0)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/path/PathRepositoryTransaction.java 2009-12-29 04:25:02 UTC (rev 1484)
@@ -0,0 +1,53 @@
+/*
+ * JBoss DNA (http://www.jboss.org/dna)
+ * 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.
+ *
+ * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
+ * 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.
+ *
+ * JBoss DNA 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 software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.dna.graph.connector.path;
+
+import org.jboss.dna.graph.connector.map.MapRepositoryTransaction;
+
+/**
+ * A transaction returned by the {@link PathRepository#startTransaction(boolean)}.
+ *
+ * @see MapRepositoryTransaction
+ */
+public interface PathRepositoryTransaction {
+
+ /**
+ * Commit any changes that have been made to the repository. This method may throw runtime exceptions if there are failures
+ * committing the changes, but the transaction is still expected to be closed.
+ *
+ * @see #rollback()
+ * @see PathRepository#startTransaction(boolean)
+ */
+ void commit();
+
+ /**
+ * Rollback any changes that have been made to this repository. This method may throw runtime exceptions if there are failures
+ * rolling back the changes, but the transaction is still expected to be closed.
+ *
+ * @see #commit()
+ * @see PathRepository#startTransaction(boolean)
+ */
+ void rollback();
+
+}
\ No newline at end of file
Property changes on: trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/path/PathRepositoryTransaction.java
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/path/PathRequestProcessor.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/path/PathRequestProcessor.java 2009-12-27 20:45:58 UTC (rev 1483)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/path/PathRequestProcessor.java 2009-12-29 04:25:02 UTC (rev 1484)
@@ -1,16 +1,26 @@
package org.jboss.dna.graph.connector.path;
+import java.util.Collections;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
+import java.util.Map;
import java.util.Set;
import org.jboss.dna.common.i18n.I18n;
+import org.jboss.dna.common.util.CheckArg;
import org.jboss.dna.graph.ExecutionContext;
import org.jboss.dna.graph.GraphI18n;
import org.jboss.dna.graph.Location;
+import org.jboss.dna.graph.NodeConflictBehavior;
import org.jboss.dna.graph.observe.Observer;
+import org.jboss.dna.graph.property.Name;
import org.jboss.dna.graph.property.Path;
import org.jboss.dna.graph.property.PathFactory;
import org.jboss.dna.graph.property.PathNotFoundException;
+import org.jboss.dna.graph.property.Property;
+import org.jboss.dna.graph.property.Path.Segment;
+import org.jboss.dna.graph.query.QueryResults;
+import org.jboss.dna.graph.request.AccessQueryRequest;
import org.jboss.dna.graph.request.CloneBranchRequest;
import org.jboss.dna.graph.request.CloneWorkspaceRequest;
import org.jboss.dna.graph.request.CopyBranchRequest;
@@ -18,14 +28,17 @@
import org.jboss.dna.graph.request.CreateWorkspaceRequest;
import org.jboss.dna.graph.request.DeleteBranchRequest;
import org.jboss.dna.graph.request.DestroyWorkspaceRequest;
+import org.jboss.dna.graph.request.FullTextSearchRequest;
import org.jboss.dna.graph.request.GetWorkspacesRequest;
import org.jboss.dna.graph.request.InvalidRequestException;
import org.jboss.dna.graph.request.InvalidWorkspaceException;
+import org.jboss.dna.graph.request.LockBranchRequest;
import org.jboss.dna.graph.request.MoveBranchRequest;
import org.jboss.dna.graph.request.ReadAllChildrenRequest;
import org.jboss.dna.graph.request.ReadAllPropertiesRequest;
import org.jboss.dna.graph.request.ReadNodeRequest;
import org.jboss.dna.graph.request.Request;
+import org.jboss.dna.graph.request.UnlockBranchRequest;
import org.jboss.dna.graph.request.UpdatePropertiesRequest;
import org.jboss.dna.graph.request.VerifyWorkspaceRequest;
import org.jboss.dna.graph.request.processor.RequestProcessor;
@@ -37,17 +50,23 @@
private final PathFactory pathFactory;
private final PathRepository repository;
+ private final boolean updatesAllowed;
public PathRequestProcessor( ExecutionContext context,
PathRepository repository,
- Observer observer ) {
+ Observer observer,
+ boolean updatesAllowed ) {
super(repository.getSourceName(), context, observer);
this.repository = repository;
pathFactory = context.getValueFactories().getPathFactory();
+ this.updatesAllowed = updatesAllowed;
}
- private void updatesNotSupported( Request request ) {
- request.setError(new InvalidRequestException(GraphI18n.unsupportedRequestType.text(request.getClass().getName(), request)));
+ protected boolean updatesAllowed( Request request ) {
+ if (!updatesAllowed) {
+ request.setError(new InvalidRequestException(GraphI18n.sourceIsReadOnly.text(getSourceName())));
+ }
+ return !request.hasError();
}
@Override
@@ -69,49 +88,321 @@
@Override
public void process( CreateWorkspaceRequest request ) {
- updatesNotSupported(request);
+ // There's a separate flag to allow creating workspaces (which may not require modifying existing data)
+ // if (!updatesAllowed(request)) return;
+
+ if (!repository.isWritable()) {
+ String msg = GraphI18n.sourceIsReadOnly.text(repository.getSourceName());
+ request.setError(new InvalidRequestException(msg));
+ return;
+ }
+
+ WritablePathRepository writableRepo = (WritablePathRepository)repository;
+
+ PathWorkspace workspace = writableRepo.createWorkspace(getExecutionContext(),
+ request.desiredNameOfNewWorkspace(),
+ request.conflictBehavior());
+ if (workspace == null) {
+ String msg = GraphI18n.workspaceAlreadyExistsInRepository.text(request.desiredNameOfNewWorkspace(),
+ repository.getSourceName());
+ request.setError(new InvalidWorkspaceException(msg));
+ } else {
+ request.setActualRootLocation(Location.create(pathFactory.createRootPath(), repository.getRootNodeUuid()));
+ request.setActualWorkspaceName(workspace.getName());
+ recordChange(request);
+ }
}
@Override
public void process( CloneBranchRequest request ) {
- updatesNotSupported(request);
+ if (!updatesAllowed(request)) return;
+
+ PathWorkspace workspace = getWorkspace(request, request.fromWorkspace());
+ PathWorkspace intoWorkspace = getWorkspace(request, request.intoWorkspace());
+
+ if (workspace == null || intoWorkspace == null) return;
+ PathNode node = getTargetNode(workspace, request, request.from());
+ if (node == null) return;
+
+ if (!(intoWorkspace instanceof WritablePathWorkspace)) {
+ I18n msg = GraphI18n.workspaceIsReadOnly;
+ request.setError(new InvalidRequestException(msg.text(repository.getSourceName(), intoWorkspace.getName())));
+ return;
+ }
+
+ WritablePathWorkspace newWorkspace = (WritablePathWorkspace)intoWorkspace;
+
+ // Look up the new parent, which must exist ...
+ Path newParentPath = request.into().getPath();
+ PathNode newParent = newWorkspace.getNode(newParentPath);
+ Set<Location> removedExistingNodes = new HashSet<Location>();
+ Name desiredName = request.desiredName();
+ PathNode newNode = newWorkspace.copyNode(getExecutionContext(), node, workspace, newParent, desiredName, true);
+
+ Location oldLocation = Location.create(node.getPath(), node.getUuid());
+ Location newLocation = Location.create(newNode.getPath(), newNode.getUuid());
+ request.setActualLocations(oldLocation, newLocation);
+ request.setRemovedNodes(Collections.unmodifiableSet(removedExistingNodes));
+ recordChange(request);
}
@Override
public void process( CloneWorkspaceRequest request ) {
- updatesNotSupported(request);
+ if (!updatesAllowed(request)) return;
+
+ // Find the original workspace that we're cloning ...
+ final ExecutionContext context = getExecutionContext();
+ String targetWorkspaceName = request.desiredNameOfTargetWorkspace();
+ String nameOfWorkspaceToBeCloned = request.nameOfWorkspaceToBeCloned();
+ PathWorkspace original = repository.getWorkspace(nameOfWorkspaceToBeCloned);
+ PathWorkspace target = repository.getWorkspace(targetWorkspaceName);
+
+ if (!repository.isWritable()) {
+ String msg = GraphI18n.sourceIsReadOnly.text(repository.getSourceName());
+ request.setError(new InvalidRequestException(msg));
+ return;
+ }
+
+ WritablePathRepository writableRepo = (WritablePathRepository)repository;
+
+ if (target != null) {
+ String msg = GraphI18n.workspaceAlreadyExistsInRepository.text(targetWorkspaceName, repository.getSourceName());
+ request.setError(new InvalidWorkspaceException(msg));
+ return;
+ }
+
+ if (original == null) {
+ switch (request.cloneConflictBehavior()) {
+ case DO_NOT_CLONE:
+ String msg = GraphI18n.workspaceDoesNotExistInRepository.text(nameOfWorkspaceToBeCloned,
+ repository.getSourceName());
+ request.setError(new InvalidWorkspaceException(msg));
+ return;
+ case SKIP_CLONE:
+ target = writableRepo.createWorkspace(context, targetWorkspaceName, request.targetConflictBehavior());
+ assert target != null;
+
+ request.setActualRootLocation(Location.create(pathFactory.createRootPath(), writableRepo.getRootNodeUuid()));
+ request.setActualWorkspaceName(target.getName());
+ return;
+ }
+ }
+ assert original != null;
+ target = writableRepo.createWorkspace(context,
+ targetWorkspaceName,
+ request.targetConflictBehavior(),
+ nameOfWorkspaceToBeCloned);
+ assert target != null;
+
+ request.setActualRootLocation(Location.create(pathFactory.createRootPath(), writableRepo.getRootNodeUuid()));
+ request.setActualWorkspaceName(target.getName());
+ recordChange(request);
}
@Override
public void process( DestroyWorkspaceRequest request ) {
- updatesNotSupported(request);
+ if (!updatesAllowed(request)) return;
+
+ PathWorkspace workspace = repository.getWorkspace(request.workspaceName());
+ if (workspace != null) {
+ request.setActualRootLocation(Location.create(pathFactory.createRootPath(), repository.getRootNodeUuid()));
+ recordChange(request);
+ } else {
+ String msg = GraphI18n.workspaceDoesNotExistInRepository.text(request.workspaceName(), repository.getSourceName());
+ request.setError(new InvalidWorkspaceException(msg));
+ }
}
@Override
public void process( CopyBranchRequest request ) {
- updatesNotSupported(request);
+ if (!updatesAllowed(request)) return;
+
+ PathWorkspace workspace = getWorkspace(request, request.fromWorkspace());
+ PathWorkspace intoWorkspace = getWorkspace(request, request.intoWorkspace());
+ if (workspace == null || intoWorkspace == null) return;
+ PathNode node = getTargetNode(workspace, request, request.from());
+ if (node == null) return;
+
+ if (!(intoWorkspace instanceof WritablePathWorkspace)) {
+ I18n msg = GraphI18n.workspaceIsReadOnly;
+ request.setError(new InvalidRequestException(msg.text(repository.getSourceName(), intoWorkspace.getName())));
+ return;
+ }
+
+ WritablePathWorkspace newWorkspace = (WritablePathWorkspace)intoWorkspace;
+
+ // Look up the new parent, which must exist ...
+ Path newParentPath = request.into().getPath();
+ Name desiredName = request.desiredName();
+ PathNode newParent = newWorkspace.getNode(newParentPath);
+ PathNode newNode = newWorkspace.copyNode(getExecutionContext(), node, workspace, newParent, desiredName, true);
+ Location oldLocation = Location.create(node.getPath(), node.getUuid());
+ Location newLocation = Location.create(newNode.getPath(), newNode.getUuid());
+ request.setActualLocations(oldLocation, newLocation);
+ recordChange(request);
}
@Override
public void process( CreateNodeRequest request ) {
- updatesNotSupported(request);
+ if (!updatesAllowed(request)) return;
+
+ PathWorkspace workspace = getWorkspace(request, request.inWorkspace());
+ if (workspace == null) return;
+ Path parent = request.under().getPath();
+ CheckArg.isNotNull(parent, "request.under().getPath()");
+ PathNode node = null;
+ // Look up the parent node, which must exist ...
+
+ PathNode parentNode = workspace.getNode(parent);
+ if (parentNode == null) {
+ Path lowestExisting = workspace.getLowestExistingPath(parent);
+ request.setError(new PathNotFoundException(request.under(), lowestExisting, GraphI18n.nodeDoesNotExist.text(parent)));
+ return;
+ }
+
+ if (!(workspace instanceof WritablePathWorkspace)) {
+ I18n msg = GraphI18n.workspaceIsReadOnly;
+ request.setError(new InvalidRequestException(msg.text(repository.getSourceName(), workspace.getName())));
+ return;
+ }
+
+ WritablePathWorkspace newWorkspace = (WritablePathWorkspace)workspace;
+
+ // Make a list of the properties that we will store: all props except dna:uuid and jcr:uuid
+ Map<Name, Property> propsToStore = new HashMap<Name, Property>(request.properties().size());
+ for (Property property : request.properties()) {
+ if (property.size() > 0) propsToStore.put(property.getName(), property);
+ }
+
+ NodeConflictBehavior conflictBehavior = request.conflictBehavior();
+ switch (conflictBehavior) {
+ case APPEND:
+ node = newWorkspace.createNode(getExecutionContext(), parentNode, request.named(), propsToStore, conflictBehavior);
+ break;
+ case DO_NOT_REPLACE:
+ for (Segment childSegment : parentNode.getChildSegments()) {
+ if (request.named().equals(childSegment.getName())) {
+ Path childPath = pathFactory.create(parent, childSegment);
+ node = newWorkspace.getNode(childPath);
+ break;
+ }
+ }
+ if (node == null) {
+ node = newWorkspace.createNode(getExecutionContext(),
+ parentNode,
+ request.named(),
+ propsToStore,
+ conflictBehavior);
+ }
+ break;
+ case REPLACE:
+ // See if the node already exists (this doesn't record an error on the request) ...
+ node = workspace.getNode(pathFactory.create(parent, request.named()));
+ if (node != null) {
+ newWorkspace.removeNode(getExecutionContext(), node.getPath());
+ }
+ node = newWorkspace.createNode(getExecutionContext(), parentNode, request.named(), propsToStore, conflictBehavior);
+ break;
+ case UPDATE:
+ // See if the node already exists (this doesn't record an error on the request) ...
+ node = newWorkspace.getNode(pathFactory.create(parent, request.named()));
+ if (node == null) {
+ node = newWorkspace.createNode(getExecutionContext(),
+ parentNode,
+ request.named(),
+ propsToStore,
+ conflictBehavior);
+ } // otherwise, we found it and we're setting any properties below
+ break;
+ }
+ assert node != null;
+
+ Location actualLocation = Location.create(node.getPath(), node.getUuid());
+ request.setActualLocationOfNode(actualLocation);
+ recordChange(request);
+
}
@Override
public void process( DeleteBranchRequest request ) {
- updatesNotSupported(request);
+ if (!updatesAllowed(request)) return;
+
+ PathWorkspace workspace = getWorkspace(request, request.inWorkspace());
+ if (workspace == null) return;
+ PathNode node = getTargetNode(workspace, request, request.at());
+ if (node == null) return;
+
+ if (!(workspace instanceof WritablePathWorkspace)) {
+ I18n msg = GraphI18n.workspaceIsReadOnly;
+ request.setError(new InvalidRequestException(msg.text(repository.getSourceName(), workspace.getName())));
+ return;
+ }
+
+ WritablePathWorkspace newWorkspace = (WritablePathWorkspace)workspace;
+ newWorkspace.removeNode(getExecutionContext(), node.getPath());
+
+ request.setActualLocationOfNode(Location.create(node.getPath(), node.getUuid()));
+ recordChange(request);
}
@Override
public void process( MoveBranchRequest request ) {
- updatesNotSupported(request);
+ if (!updatesAllowed(request)) return;
+
+ PathWorkspace workspace = getWorkspace(request, request.inWorkspace());
+ if (workspace == null) return;
+
+ PathNode beforeNode = request.before() != null ? getTargetNode(workspace, request, request.before()) : null;
+ PathNode node = getTargetNode(workspace, request, request.from());
+ if (node == null) return;
+ if (request.hasError()) return; // if beforeNode could not be found
+ // Look up the new parent, which must exist ...
+ Path newParentPath;
+
+ if (request.into() != null) {
+ newParentPath = request.into().getPath();
+ } else {
+ // into or before cannot both be null
+ assert beforeNode != null;
+ newParentPath = beforeNode.getPath().getParent();
+ }
+
+ PathNode newParent = workspace.getNode(newParentPath);
+ if (newParent == null) {
+ Path lowestExisting = workspace.getLowestExistingPath(newParentPath);
+ request.setError(new PathNotFoundException(request.into(), lowestExisting,
+ GraphI18n.nodeDoesNotExist.text(newParentPath)));
+ return;
+ }
+
+ if (!(workspace instanceof WritablePathWorkspace)) {
+ I18n msg = GraphI18n.workspaceIsReadOnly;
+ request.setError(new InvalidRequestException(msg.text(repository.getSourceName(), workspace.getName())));
+ return;
+ }
+
+ WritablePathWorkspace newWorkspace = (WritablePathWorkspace)workspace;
+
+ node = newWorkspace.moveNode(getExecutionContext(), node, request.desiredName(), newWorkspace, newParent, beforeNode);
+ assert node.getPath().getParent().equals(newParent.getPath());
+
+ Location oldLocation = Location.create(request.from().getPath());
+ Location newLocation = Location.create(node.getPath(), node.getUuid());
+ request.setActualLocations(oldLocation, newLocation);
+ recordChange(request);
+
}
@Override
public void process( ReadNodeRequest request ) {
PathWorkspace workspace = getWorkspace(request, request.inWorkspace());
+ if (workspace == null) return;
+
PathNode node = getTargetNode(workspace, request, request.at());
- if (node == null) return;
+ if (node == null) {
+ request.setError(new PathNotFoundException(request.at(), workspace.getLowestExistingPath(request.at().getPath())));
+ return;
+ }
// Get the names of the children ...
for (Path.Segment childSegment : node.getChildSegments()) {
@@ -121,41 +412,119 @@
// Get the properties of the node ...
request.addProperties(node.getProperties().values());
- request.setActualLocationOfNode(Location.create(node.getPath()));
+ request.setActualLocationOfNode(Location.create(node.getPath(), node.getUuid()));
setCacheableInfo(request);
}
@Override
public void process( ReadAllChildrenRequest request ) {
PathWorkspace workspace = getWorkspace(request, request.inWorkspace());
+ if (workspace == null) return;
+
PathNode node = getTargetNode(workspace, request, request.of());
- if (node == null) return;
+ if (node == null) {
+ request.setError(new PathNotFoundException(request.of(), workspace.getLowestExistingPath(request.of().getPath())));
+ return;
+ }
List<Path.Segment> childSegments = node.getChildSegments();
for (Path.Segment childSegment : childSegments) {
request.addChild(Location.create(pathFactory.create(node.getPath(), childSegment)));
}
- request.setActualLocationOfNode(Location.create(node.getPath()));
+ request.setActualLocationOfNode(Location.create(node.getPath(), node.getUuid()));
setCacheableInfo(request);
}
@Override
public void process( ReadAllPropertiesRequest request ) {
PathWorkspace workspace = getWorkspace(request, request.inWorkspace());
+ if (workspace == null) return;
+
PathNode node = getTargetNode(workspace, request, request.at());
- if (node == null) return;
+ if (node == null) {
+ request.setError(new PathNotFoundException(request.at(), workspace.getLowestExistingPath(request.at().getPath())));
+ return;
+ }
// Get the properties of the node ...
request.addProperties(node.getProperties().values());
- request.setActualLocationOfNode(Location.create(node.getPath()));
+ request.setActualLocationOfNode(Location.create(node.getPath(), node.getUuid()));
setCacheableInfo(request);
}
@Override
+ public void process( AccessQueryRequest request ) {
+ PathWorkspace workspace = getWorkspace(request, request.workspace());
+ if (workspace == null) return;
+ final ExecutionContext context = getExecutionContext();
+ QueryResults results = workspace.query(context, request);
+ if (results != null) {
+ request.setResults(results.getTuples(), results.getStatistics());
+ } else {
+ super.processUnknownRequest(request);
+ }
+ }
+
+ @Override
+ public void process( FullTextSearchRequest request ) {
+ PathWorkspace workspace = getWorkspace(request, request.workspace());
+ if (workspace == null) return;
+ final ExecutionContext context = getExecutionContext();
+ QueryResults results = workspace.search(context, request.expression());
+ if (results != null) {
+ request.setResults(results.getColumns(), results.getTuples(), results.getStatistics());
+ } else {
+ super.processUnknownRequest(request);
+ }
+ }
+
+ @Override
public void process( UpdatePropertiesRequest request ) {
- updatesNotSupported(request);
+ if (!updatesAllowed(request)) return;
+
+ PathWorkspace workspace = getWorkspace(request, request.inWorkspace());
+ PathNode node = getTargetNode(workspace, request, request.on());
+ if (node == null) return;
+
+ if (!(workspace instanceof WritablePathWorkspace)) {
+ I18n msg = GraphI18n.workspaceIsReadOnly;
+ request.setError(new InvalidRequestException(msg.text(repository.getSourceName(), workspace.getName())));
+ return;
+ }
+
+ WritablePathWorkspace newWorkspace = (WritablePathWorkspace)workspace;
+
+ // Now set (or remove) the properties to the supplied node ...
+ newWorkspace.setProperties(getExecutionContext(), node.getPath(), request.properties().values());
+
+ request.setActualLocationOfNode(Location.create(node.getPath(), node.getUuid()));
+ recordChange(request);
}
+ @Override
+ public void process( LockBranchRequest request ) {
+ PathWorkspace workspace = getWorkspace(request, request.inWorkspace());
+ PathNode node = getTargetNode(workspace, request, request.at());
+ if (node == null) return;
+
+ workspace.lockNode(node, request.lockScope(), request.lockTimeoutInMillis());
+
+ request.setActualLocation(Location.create(node.getPath(), node.getUuid()));
+ recordChange(request);
+ }
+
+ @Override
+ public void process( UnlockBranchRequest request ) {
+ PathWorkspace workspace = getWorkspace(request, request.inWorkspace());
+ PathNode node = getTargetNode(workspace, request, request.at());
+ if (node == null) return;
+
+ workspace.unlockNode(node);
+
+ request.setActualLocation(Location.create(node.getPath(), node.getUuid()));
+ recordChange(request);
+ }
+
protected PathWorkspace getWorkspace( Request request,
String workspaceName ) {
// Get the workspace for this request ...
@@ -173,6 +542,13 @@
if (workspace == null) return null;
PathNode node = null;
+ if (location.getUuid() != null) {
+ if (repository.getRootNodeUuid().equals(location.getUuid())) {
+ PathFactory pathFactory = new ExecutionContext().getValueFactories().getPathFactory();
+ return workspace.getNode(pathFactory.createRootPath());
+ }
+ }
+
if (!location.hasPath()) {
I18n msg = GraphI18n.pathConnectorRequestsMustHavePath;
request.setError(new IllegalArgumentException(msg.text()));
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/path/PathWorkspace.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/path/PathWorkspace.java 2009-12-27 20:45:58 UTC (rev 1483)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/path/PathWorkspace.java 2009-12-29 04:25:02 UTC (rev 1484)
@@ -16,14 +16,6 @@
String getName();
/**
- * Returns the root node in the workspace. This returns a {@link PathNode map node} where {@code node.getParent() == null} and
- * {@code node.getPath().isRoot() == true}.
- *
- * @return the root node in the workspace
- */
- PathNode getRoot();
-
- /**
* Returns the node at the given path, if one exists of {@code null} if no {@PathNode node} exists at the given
* path.
*
@@ -81,5 +73,4 @@
*/
QueryResults search( ExecutionContext context,
String fullTextSearchExpression );
-
}
Added: trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/path/WritablePathRepository.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/path/WritablePathRepository.java (rev 0)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/path/WritablePathRepository.java 2009-12-29 04:25:02 UTC (rev 1484)
@@ -0,0 +1,174 @@
+/*
+ * JBoss DNA (http://www.jboss.org/dna)
+ * 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.
+ *
+ * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
+ * 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.
+ *
+ * JBoss DNA 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 software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.dna.graph.connector.path;
+
+import java.util.UUID;
+import net.jcip.annotations.ThreadSafe;
+import org.jboss.dna.graph.ExecutionContext;
+import org.jboss.dna.graph.property.Path;
+import org.jboss.dna.graph.property.PathFactory;
+import org.jboss.dna.graph.property.Path.Segment;
+import org.jboss.dna.graph.request.CreateWorkspaceRequest.CreateConflictBehavior;
+
+/**
+ * Extension of {@link PathRepository} for repositories that support modification of nodes as well as access to the nodes.
+ */
+@ThreadSafe
+public abstract class WritablePathRepository extends PathRepository {
+
+ public WritablePathRepository( String sourceName,
+ UUID rootNodeUuid,
+ String defaultWorkspaceName ) {
+ super(sourceName, rootNodeUuid, defaultWorkspaceName);
+ }
+
+ public WritablePathRepository( String sourceName,
+ UUID rootNodeUuid ) {
+ super(sourceName, rootNodeUuid);
+ }
+
+ /**
+ * Creates a new workspace with the given name containing only a root node.
+ * <p>
+ * <b>This method does NOT automatically add the newly created workspace to the {@link #workspaces workspace map} or check to
+ * see if a workspace already exists in this repository with the same name.</b>
+ * </p>
+ *
+ * @param context the context in which the workspace is to be created
+ * @param name the name of the workspace
+ * @return the newly created workspace; may not be null
+ */
+ protected abstract WritablePathWorkspace createWorkspace( ExecutionContext context,
+ String name );
+
+ /**
+ * Attempts to create a workspace with the given name with name-collision behavior determined by the behavior parameter.
+ * <p>
+ * This method will first check to see if a workspace already exists with the given name. If no such workspace exists, the
+ * method will create a new workspace with the given name, add it to the {@code #workspaces workspaces map}, and return it. If
+ * a workspace with the requested name already exists and the {@code behavior} is {@link CreateConflictBehavior#DO_NOT_CREATE}
+ * , this method will return {@code null} without modifying the state of the repository. If a workspace with the requested
+ * name already exists and the {@code behavior} is {@link CreateConflictBehavior#CREATE_WITH_ADJUSTED_NAME}, this method will
+ * generate a unique new name for the workspace, create a new workspace with the given name, added it to the {@code
+ * #workspaces workspaces map}, and return it.
+ *
+ * @param context the context in which the workspace is to be created; may not be null
+ * @param name the requested name of the workspace. The name of the workspace that is returned from this method may not be the
+ * same as the requested name; may not be null
+ * @param behavior the behavior to use in case a workspace with the requested name already exists in the repository
+ * @return the newly created workspace or {@code null} if a workspace with the requested name already exists in the repository
+ * and {@code behavior == CreateConflictBehavior#DO_NOT_CREATE}.
+ */
+ public WritablePathWorkspace createWorkspace( ExecutionContext context,
+ String name,
+ CreateConflictBehavior behavior ) {
+ String newName = name;
+ boolean conflictingName = workspaces.containsKey(newName);
+ if (conflictingName) {
+ switch (behavior) {
+ case DO_NOT_CREATE:
+ return null;
+ case CREATE_WITH_ADJUSTED_NAME:
+ int counter = 0;
+ do {
+ newName = name + (++counter);
+ } while (workspaces.containsKey(newName));
+ break;
+ }
+ }
+ assert workspaces.containsKey(newName) == false;
+
+ WritablePathWorkspace workspace = createWorkspace(context, name);
+ workspaces.put(name, workspace);
+ return workspace;
+ }
+
+ /**
+ * Attempts to create a workspace with the requested name as in the
+ * {@link #createWorkspace(ExecutionContext, String, CreateConflictBehavior)} method and then clones the content from the
+ * given source workspace into the new workspace if the creation was successful.
+ * <p>
+ * If no workspace with the name {@code nameOfWorkspaceToClone} exists, the method will return an empty workspace.
+ * </p>
+ *
+ * @param context the context in which the workspace is to be created; may not be null
+ * @param name the requested name of the workspace. The name of the workspace that is returned from this method may not be the
+ * same as the requested name; may not be null
+ * @param existingWorkspaceBehavior the behavior to use in case a workspace with the requested name already exists in the
+ * repository
+ * @param nameOfWorkspaceToClone the name of the workspace from which the content should be cloned; may not be null
+ * @return the newly created workspace with an exact copy of the contents from the workspace named {@code
+ * nameOfWorkspaceToClone} or {@code null} if a workspace with the requested name already exists in the repository and
+ * {@code behavior == CreateConflictBehavior#DO_NOT_CREATE}.
+ */
+ public WritablePathWorkspace createWorkspace( ExecutionContext context,
+ String name,
+ CreateConflictBehavior existingWorkspaceBehavior,
+ String nameOfWorkspaceToClone ) {
+ WritablePathWorkspace workspace = createWorkspace(context, name, existingWorkspaceBehavior);
+ if (workspace == null) {
+ // Unable to create because of a duplicate name ...
+ return null;
+ }
+ PathWorkspace original = getWorkspace(nameOfWorkspaceToClone);
+
+ PathFactory pathFactory = context.getValueFactories().getPathFactory();
+ Path rootPath = pathFactory.createRootPath();
+
+ if (original != null) {
+ // Copy the properties of the root node ...
+ PathNode root = workspace.getNode(rootPath);
+ PathNode origRoot = original.getNode(rootPath);
+ workspace.removeProperties(context, rootPath, root.getProperties().keySet());
+ workspace.setProperties(context, rootPath, origRoot.getProperties().values());
+
+ // Loop over each child and call this method to copy the immediate children (and below).
+ for (Segment childSegment : origRoot.getChildSegments()) {
+ Path childPath = pathFactory.create(origRoot.getPath(), childSegment);
+ PathNode originalNode = original.getNode(childPath);
+
+ workspace.copyNode(context, originalNode, original, root, childSegment.getName(), true);
+ }
+ }
+
+ workspaces.put(name, workspace);
+ return workspace;
+ }
+
+ /**
+ * Removes the named workspace from the {@code #workspaces workspaces map}.
+ *
+ * @param name the name of the workspace to remove
+ * @return {@code true} if a workspace with that name previously existed in the map
+ */
+ public boolean destroyWorkspace( String name ) {
+ return workspaces.remove(name) != null;
+ }
+
+ @Override
+ public boolean isWritable() {
+ return true;
+ }
+
+}
Property changes on: trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/path/WritablePathRepository.java
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Added: trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/path/WritablePathWorkspace.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/path/WritablePathWorkspace.java (rev 0)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/path/WritablePathWorkspace.java 2009-12-29 04:25:02 UTC (rev 1484)
@@ -0,0 +1,152 @@
+/*
+ * JBoss DNA (http://www.jboss.org/dna)
+ * 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.
+ *
+ * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
+ * 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.
+ *
+ * JBoss DNA 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 software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.dna.graph.connector.path;
+
+import java.util.Map;
+import org.jboss.dna.graph.ExecutionContext;
+import org.jboss.dna.graph.NodeConflictBehavior;
+import org.jboss.dna.graph.property.Name;
+import org.jboss.dna.graph.property.Path;
+import org.jboss.dna.graph.property.Property;
+
+/**
+ * Extension of {@link PathWorkspace} for repositories that support modification of nodes as well as access to the nodes.
+ */
+public interface WritablePathWorkspace extends PathWorkspace {
+
+ /**
+ * Create a node at the supplied path. The parent of the new node must already exist.
+ *
+ * @param context the environment; may not be null
+ * @param pathToNewNode the path to the new node; may not be null
+ * @param properties the properties for the new node
+ * @param conflictBehavior the expected behavior if an equivalently-named child already exists at the location
+ * @return the new node (or root if the path specified the root)
+ */
+ PathNode createNode( ExecutionContext context,
+ String pathToNewNode,
+ Map<Name, Property> properties,
+ NodeConflictBehavior conflictBehavior );
+
+ /**
+ * Create a new node with the supplied name, as a child of the supplied parent.
+ *
+ * @param context the execution context
+ * @param parentNode the parent node; may not be null
+ * @param name the name; may not be null
+ * @param properties the properties for the new node
+ * @param conflictBehavior the expected behavior if an equivalently-named child already exists at the location
+ * @return the new node
+ */
+ PathNode createNode( ExecutionContext context,
+ PathNode parentNode,
+ Name name,
+ Map<Name, Property> properties,
+ NodeConflictBehavior conflictBehavior );
+
+ /**
+ * Move the supplied node to the new parent within this workspace. This method automatically removes the node from its
+ * existing parent, and also correctly adjusts the {@link Path.Segment#getIndex() index} to be correct in the new parent.
+ *
+ * @param context
+ * @param node the node to be moved; may not be the workspace root node
+ * @param desiredNewName the new name for the node, if it is to be changed; may be null
+ * @param originalWorkspace the workspace containing the node to be moved
+ * @param newParent the new parent; may not be the workspace root node
+ * @param beforeNode the node before which this new node should be placed
+ * @return a new copy of {@code node} that reflects the new location
+ */
+ public PathNode moveNode( ExecutionContext context,
+ PathNode node,
+ Name desiredNewName,
+ WritablePathWorkspace originalWorkspace,
+ PathNode newParent,
+ PathNode beforeNode );
+
+ /**
+ * Copy the subgraph given by the original node and place the new copy under the supplied new parent. Note that internal
+ * references between nodes within the original subgraph must be reflected as internal nodes within the new subgraph.
+ *
+ * @param context the context; may not be null
+ * @param original the node to be copied; may not be null
+ * @param originalWorkspace the workspace containing the original parent node; may not be null
+ * @param newParent the parent where the copy is to be placed; may not be null
+ * @param desiredName the desired name for the node; if null, the name will be obtained from the original node
+ * @param recursive true if the copy should be recursive
+ * @return the new node, which is the top of the new subgraph
+ */
+ PathNode copyNode( ExecutionContext context,
+ PathNode original,
+ PathWorkspace originalWorkspace,
+ PathNode newParent,
+ Name desiredName,
+ boolean recursive );
+
+ /**
+ * Inserts the specified child at the specified position in the list of children. Shifts the child currently at that position
+ * (if any) and any subsequent children to the right (adds one to their indices).
+ *
+ * @param index index at which the specified child is to be inserted
+ * @param child the child to be inserted
+ */
+ // public void addChild( int index,
+ // PathNode child );
+
+ /**
+ * Removes the node at the given path
+ *
+ * @param context the context; may not be null
+ * @param nodePath the path of the node to be removed
+ * @return true if the node existed (and was removed); false otherwise
+ */
+ public boolean removeNode( ExecutionContext context,
+ Path nodePath );
+
+ /**
+ * Sets the given properties in a single operation, overwriting any previous properties for the same name. This bulk mutator
+ * should be used when multiple properties are being set in order to allow underlying implementations to optimize their access
+ * to their respective persistent storage mechanism.
+ *
+ * @param context the context; may not be null
+ * @param nodePath the path to the node on which the properties should be set
+ * @param properties the properties to set
+ * @return this map node
+ */
+ public PathNode setProperties( ExecutionContext context,
+ Path nodePath,
+ Iterable<Property> properties );
+
+ /**
+ * Removes the properties with the given names
+ *
+ * @param context the context; may not be null
+ * @param nodePath the path to the node from which the properties should be removed
+ * @param propertyNames the name of the properties to remove
+ * @return this map node
+ */
+ public PathNode removeProperties( ExecutionContext context,
+ Path nodePath,
+ Iterable<Name> propertyNames );
+
+}
Property changes on: trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/path/WritablePathWorkspace.java
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Modified: trunk/dna-graph/src/main/resources/org/jboss/dna/graph/GraphI18n.properties
===================================================================
--- trunk/dna-graph/src/main/resources/org/jboss/dna/graph/GraphI18n.properties 2009-12-27 20:45:58 UTC (rev 1483)
+++ trunk/dna-graph/src/main/resources/org/jboss/dna/graph/GraphI18n.properties 2009-12-29 04:25:02 UTC (rev 1484)
@@ -89,9 +89,10 @@
inMemoryConnectorRequestsMustHavePathOrUuid = In-Memory connector can only process requests with a path and/or UUID
inMemoryConnectorMustAllowUpdates = In-Memory connector "{0}" must allow updates.
pathConnectorRequestsMustHavePath = Path connectors can only process requests with a path
-workspaceDoesNotExistInRepository = The workspace "{0}" does not exist in the "{1}" in-memory repository
-workspaceAlreadyExistsInRepository = The workspace "{0}" already exists in the "{1}" in-memory repository
+workspaceDoesNotExistInRepository = The workspace "{0}" does not exist in the "{1}" repository
+workspaceAlreadyExistsInRepository = The workspace "{0}" already exists in the "{1}" repository
sourceIsReadOnly = The repository source "{0}" does not allow updates. Set the "updatesAllowed" property to "true" on the repository source to allow updates.
+workspaceIsReadOnly = The workspace "{1}" in repository source "{0}" does not allow updates. Setting the "updatesAllowed" property to "true" on the repository source may allow this workspace to support updates.
# Federation connector
namePropertyIsRequiredForFederatedRepositorySource = The "{0}" property is required on each federated repository source
Deleted: trunk/extensions/dna-connector-filesystem/src/main/java/org/jboss/dna/connector/filesystem/FileSystemConnection.java
===================================================================
--- trunk/extensions/dna-connector-filesystem/src/main/java/org/jboss/dna/connector/filesystem/FileSystemConnection.java 2009-12-27 20:45:58 UTC (rev 1483)
+++ trunk/extensions/dna-connector-filesystem/src/main/java/org/jboss/dna/connector/filesystem/FileSystemConnection.java 2009-12-29 04:25:02 UTC (rev 1484)
@@ -1,195 +0,0 @@
-/*
- * JBoss DNA (http://www.jboss.org/dna)
- * 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.
- *
- * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
- * 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.
- *
- * JBoss DNA 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 software; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
- */
-package org.jboss.dna.connector.filesystem;
-
-import java.io.File;
-import java.io.FilenameFilter;
-import java.util.Map;
-import java.util.UUID;
-import java.util.concurrent.TimeUnit;
-import javax.transaction.xa.XAResource;
-import org.jboss.dna.graph.ExecutionContext;
-import org.jboss.dna.graph.cache.CachePolicy;
-import org.jboss.dna.graph.connector.RepositoryConnection;
-import org.jboss.dna.graph.connector.RepositorySourceException;
-import org.jboss.dna.graph.connector.map.MapRepositoryTransaction;
-import org.jboss.dna.graph.request.Request;
-import org.jboss.dna.graph.request.processor.RequestProcessor;
-
-/**
- * The {@link RepositoryConnection} implementation for the file system connector. The bulk of the work is performed by the
- * {@link FileSystemRequestProcessor}.
- */
-public class FileSystemConnection implements RepositoryConnection {
-
- private final String sourceName;
- private final String defaultWorkspaceName;
- private final CachePolicy cachePolicy;
- private final Map<String, File> availableWorkspaces;
- private final boolean creatingWorkspacesAllowed;
- private final FilenameFilter filenameFilter;
- private final UUID rootNodeUuid;
- private final int maxPathLength;
- private final String workspaceRootPath;
- private final boolean updatesAllowed;
- private final CustomPropertiesFactory customPropertiesFactory;
-
- FileSystemConnection( String sourceName,
- String defaultWorkspaceName,
- Map<String, File> availableWorkspaces,
- boolean creatingWorkspacesAllowed,
- CachePolicy cachePolicy,
- UUID rootNodeUuid,
- String workspaceRootPath,
- int maxPathLength,
- FilenameFilter filenameFilter,
- boolean updatesAllowed,
- CustomPropertiesFactory customPropertiesFactory ) {
- assert sourceName != null;
- assert sourceName.trim().length() != 0;
- assert availableWorkspaces != null;
- assert rootNodeUuid != null;
- assert customPropertiesFactory != null;
- this.sourceName = sourceName;
- this.defaultWorkspaceName = defaultWorkspaceName;
- this.availableWorkspaces = availableWorkspaces;
- this.creatingWorkspacesAllowed = creatingWorkspacesAllowed;
- this.cachePolicy = cachePolicy;
- this.rootNodeUuid = rootNodeUuid;
- this.workspaceRootPath = workspaceRootPath;
- this.maxPathLength = maxPathLength;
- this.filenameFilter = filenameFilter;
- this.updatesAllowed = updatesAllowed;
- this.customPropertiesFactory = customPropertiesFactory;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.graph.connector.RepositoryConnection#getSourceName()
- */
- public String getSourceName() {
- return sourceName;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.graph.connector.RepositoryConnection#getDefaultCachePolicy()
- */
- public CachePolicy getDefaultCachePolicy() {
- return cachePolicy;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.graph.connector.RepositoryConnection#getXAResource()
- */
- public XAResource getXAResource() {
- return null;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.graph.connector.RepositoryConnection#ping(long, java.util.concurrent.TimeUnit)
- */
- public boolean ping( long time,
- TimeUnit unit ) {
- return true;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.graph.connector.RepositoryConnection#execute(org.jboss.dna.graph.ExecutionContext,
- * org.jboss.dna.graph.request.Request)
- */
- public void execute( ExecutionContext context,
- Request request ) throws RepositorySourceException {
- FileSystemTransaction txn = startTransaction(request.isReadOnly());
- RequestProcessor processor = new FileSystemRequestProcessor(sourceName, defaultWorkspaceName, availableWorkspaces,
- creatingWorkspacesAllowed, rootNodeUuid, workspaceRootPath,
- maxPathLength, context, filenameFilter, updatesAllowed,
- customPropertiesFactory, txn);
- boolean commit = true;
- try {
- // Obtain the lock and execute the commands ...
- processor.process(request);
- if (request.hasError() && !request.isReadOnly()) {
- // The changes failed, so we need to rollback so we have 'all-or-nothing' behavior
- commit = false;
- }
- } catch (Throwable error) {
- commit = false;
- } finally {
- try {
- processor.close();
- } finally {
- // Now commit or rollback ...
- try {
- if (commit) {
- txn.commit();
- } else {
- // Need to rollback the changes made to the repository ...
- txn.rollback();
- }
- } catch (Throwable commitOrRollbackError) {
- if (commit && !request.hasError() && !request.isFrozen()) {
- // Record the error on the request ...
- request.setError(commitOrRollbackError);
- }
- commit = false; // couldn't do it
- }
- if (commit) {
- // Now that we've closed our transaction, we can notify the observer of the committed changes ...
- processor.notifyObserverOfChanges();
- }
- }
- }
- }
-
- /**
- * Begin a transaction, hinting whether the transaction will be used only to read the content. If this is called, then the
- * transaction must be either {@link MapRepositoryTransaction#commit() committed} or
- * {@link MapRepositoryTransaction#rollback() rolled back}.
- *
- * @param readonly true if the transaction will not modify any content, or false if changes are to be made
- * @return the transaction; never null
- * @see MapRepositoryTransaction#commit()
- * @see MapRepositoryTransaction#rollback()
- */
- protected FileSystemTransaction startTransaction( boolean readonly ) {
- return new FileSystemTransaction();
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.graph.connector.RepositoryConnection#close()
- */
- public void close() {
- }
-}
Modified: trunk/extensions/dna-connector-filesystem/src/main/java/org/jboss/dna/connector/filesystem/FileSystemI18n.java
===================================================================
--- trunk/extensions/dna-connector-filesystem/src/main/java/org/jboss/dna/connector/filesystem/FileSystemI18n.java 2009-12-27 20:45:58 UTC (rev 1483)
+++ trunk/extensions/dna-connector-filesystem/src/main/java/org/jboss/dna/connector/filesystem/FileSystemI18n.java 2009-12-29 04:25:02 UTC (rev 1484)
@@ -61,6 +61,7 @@
public static I18n invalidNameForResource;
public static I18n invalidPathForResource;
public static I18n invalidPropertyNames;
+ public static I18n couldNotReadData;
public static I18n couldNotWriteData;
public static I18n couldNotUpdateData;
public static I18n missingRequiredProperty;
Added: trunk/extensions/dna-connector-filesystem/src/main/java/org/jboss/dna/connector/filesystem/FileSystemRepository.java
===================================================================
--- trunk/extensions/dna-connector-filesystem/src/main/java/org/jboss/dna/connector/filesystem/FileSystemRepository.java (rev 0)
+++ trunk/extensions/dna-connector-filesystem/src/main/java/org/jboss/dna/connector/filesystem/FileSystemRepository.java 2009-12-29 04:25:02 UTC (rev 1484)
@@ -0,0 +1,728 @@
+/*
+ * JBoss DNA (http://www.jboss.org/dna)
+ * 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.
+ *
+ * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
+ * 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.
+ *
+ * JBoss DNA 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 software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.dna.connector.filesystem;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.jboss.dna.common.i18n.I18n;
+import org.jboss.dna.common.util.FileUtil;
+import org.jboss.dna.common.util.IoUtil;
+import org.jboss.dna.graph.DnaLexicon;
+import org.jboss.dna.graph.ExecutionContext;
+import org.jboss.dna.graph.JcrLexicon;
+import org.jboss.dna.graph.JcrNtLexicon;
+import org.jboss.dna.graph.Location;
+import org.jboss.dna.graph.NodeConflictBehavior;
+import org.jboss.dna.graph.connector.RepositorySourceException;
+import org.jboss.dna.graph.connector.path.AbstractWritablePathWorkspace;
+import org.jboss.dna.graph.connector.path.DefaultPathNode;
+import org.jboss.dna.graph.connector.path.PathNode;
+import org.jboss.dna.graph.connector.path.PathRepositoryTransaction;
+import org.jboss.dna.graph.connector.path.WritablePathRepository;
+import org.jboss.dna.graph.connector.path.WritablePathWorkspace;
+import org.jboss.dna.graph.mimetype.MimeTypeDetector;
+import org.jboss.dna.graph.property.Binary;
+import org.jboss.dna.graph.property.BinaryFactory;
+import org.jboss.dna.graph.property.DateTimeFactory;
+import org.jboss.dna.graph.property.Name;
+import org.jboss.dna.graph.property.NameFactory;
+import org.jboss.dna.graph.property.NamespaceRegistry;
+import org.jboss.dna.graph.property.Path;
+import org.jboss.dna.graph.property.PathFactory;
+import org.jboss.dna.graph.property.PathNotFoundException;
+import org.jboss.dna.graph.property.Property;
+import org.jboss.dna.graph.property.PropertyFactory;
+import org.jboss.dna.graph.property.Path.Segment;
+import org.jboss.dna.graph.request.InvalidRequestException;
+import org.jboss.dna.graph.request.Request;
+
+/**
+ * Implementation of {@code WritablePathRepository} that provides access to an underlying file system. This repository only
+ * natively supports nodes of primary types {@link JcrNtLexicon#FOLDER nt:folder}, {@link JcrNtLexicon#FILE nt:file}, and
+ * {@link DnaLexicon#RESOURCE dna:resource}, although the {@link CustomPropertiesFactory} allows for the addition of mixin types
+ * to any and all primary types.
+ */
+public class FileSystemRepository extends WritablePathRepository {
+ private static final String DEFAULT_MIME_TYPE = "application/octet";
+
+ private final FileSystemSource source;
+ private File repositoryRoot;
+
+ public FileSystemRepository( FileSystemSource source ) {
+ super(source.getName(), source.getRootNodeUuid(), source.getDefaultWorkspaceName());
+
+ this.source = source;
+ initialize();
+ }
+
+ /**
+ * Creates any predefined workspaces, including the default workspace.
+ */
+ @Override
+ protected void initialize() {
+ String repositoryRootPath = source.getWorkspaceRootPath();
+ String sourceName = this.getSourceName();
+
+ if (repositoryRootPath != null) {
+ this.repositoryRoot = new File(repositoryRootPath);
+ if (!this.repositoryRoot.exists()) {
+ throw new IllegalStateException(FileSystemI18n.pathForWorkspaceRootDoesNotExist.text(repositoryRootPath,
+ sourceName));
+ }
+ if (!this.repositoryRoot.isDirectory()) {
+ throw new IllegalStateException(FileSystemI18n.pathForWorkspaceRootIsNotDirectory.text(repositoryRootPath,
+ sourceName));
+ }
+ if (!this.repositoryRoot.canRead()) {
+ throw new IllegalStateException(FileSystemI18n.pathForWorkspaceRootCannotBeRead.text(repositoryRootPath,
+ sourceName));
+ }
+ }
+
+ if (!this.workspaces.isEmpty()) return;
+
+ String defaultWorkspaceName = getDefaultWorkspaceName();
+ ExecutionContext context = source.getRepositoryContext().getExecutionContext();
+
+ for (String workspaceName : source.getPredefinedWorkspaceNames()) {
+ doCreateWorkspace(context, workspaceName);
+
+ }
+
+ if (!workspaces.containsKey(defaultWorkspaceName)) {
+ doCreateWorkspace(context, defaultWorkspaceName);
+ }
+ }
+
+ /**
+ * Internal method that creates a workspace and adds it to the map of active workspaces without checking to see if
+ * {@link FileSystemSource#isCreatingWorkspacesAllowed() the source allows creating workspaces}. This is useful when setting
+ * up predefined workspaces.
+ *
+ * @param context the current execution context; may not be null
+ * @param name the name of the workspace to create; may not be null
+ * @return the newly created workspace; never null
+ */
+ private WritablePathWorkspace doCreateWorkspace( ExecutionContext context,
+ String name ) {
+ // This doesn't create the directory representing the workspace (it must already exist), but it will add
+ // the workspace name to the available names ...
+ File directory = getWorkspaceDirectory(name);
+ FileSystemWorkspace workspace = new FileSystemWorkspace(name, context, directory);
+
+ workspaces.putIfAbsent(name, workspace);
+ return (WritablePathWorkspace)workspaces.get(name);
+
+ }
+
+ @Override
+ protected WritablePathWorkspace createWorkspace( ExecutionContext context,
+ String name ) {
+ if (!source.isCreatingWorkspacesAllowed()) {
+ String msg = FileSystemI18n.unableToCreateWorkspaces.text(getSourceName(), name);
+ throw new InvalidRequestException(msg);
+ }
+
+ return doCreateWorkspace(context, name);
+ }
+
+ /**
+ * @param workspaceName the name of the workspace for which the root directory should be returned
+ * @return the directory that maps to the root node in the named workspace; may be null if the directory does not exist, is a
+ * file, or cannot be read.
+ */
+ protected File getWorkspaceDirectory( String workspaceName ) {
+ if (workspaceName == null) workspaceName = source.getDefaultWorkspaceName();
+
+ File directory = this.repositoryRoot == null ? new File(workspaceName) : new File(repositoryRoot, workspaceName);
+ if (directory.exists() && directory.isDirectory() && directory.canRead()) return directory;
+ return null;
+ }
+
+ @Override
+ public PathRepositoryTransaction startTransaction( boolean readonly ) {
+ return new FileSystemTransaction();
+ }
+
+ /**
+ * Writable workspace implementation for file system-backed workspaces
+ */
+ public class FileSystemWorkspace extends AbstractWritablePathWorkspace {
+
+ private final ExecutionContext context;
+ private final File workspaceRoot;
+
+ public FileSystemWorkspace( String name,
+ ExecutionContext context,
+ File workspaceRoot ) {
+ super(name, source.getRootNodeUuid());
+ this.workspaceRoot = workspaceRoot;
+ this.context = context;
+ }
+
+ @Override
+ public PathNode createNode( ExecutionContext context,
+ PathNode parentNode,
+ Name name,
+ Map<Name, Property> properties,
+ NodeConflictBehavior conflictBehavior ) {
+ NameFactory nameFactory = context.getValueFactories().getNameFactory();
+ PathFactory pathFactory = context.getValueFactories().getPathFactory();
+ NamespaceRegistry registry = context.getNamespaceRegistry();
+ /*
+ * Get references to java.io.Files
+ */
+
+ Path parentPath = parentNode.getPath();
+ File parentFile = fileFor(parentPath);
+
+ Path newPath = pathFactory.create(parentPath, name);
+ String newName = name.getString(registry);
+ File newFile = new File(parentFile, newName);
+
+ /*
+ * Determine the node primary type
+ */
+ Property primaryTypeProp = properties.get(JcrLexicon.PRIMARY_TYPE);
+
+ // Default primary type to nt:folder
+ Name primaryType = primaryTypeProp == null ? JcrNtLexicon.FOLDER : nameFactory.create(primaryTypeProp.getFirstValue());
+ CustomPropertiesFactory customPropertiesFactory = source.customPropertiesFactory();
+
+ if (JcrNtLexicon.FILE.equals(primaryType)) {
+
+ // The FILE node is represented by the existence of the file
+ if (!parentFile.canWrite()) {
+ I18n msg = FileSystemI18n.parentIsReadOnly;
+ throw new RepositorySourceException(getSourceName(), msg.text(parentPath, this.getName(), getSourceName()));
+ }
+
+ try {
+ ensureValidPathLength(newFile);
+ boolean skipWrite = false;
+
+ if (newFile.exists()) {
+ if (conflictBehavior.equals(NodeConflictBehavior.APPEND)) {
+ I18n msg = FileSystemI18n.sameNameSiblingsAreNotAllowed;
+ throw new InvalidRequestException(msg.text(getSourceName(), newName));
+ } else if (conflictBehavior.equals(NodeConflictBehavior.DO_NOT_REPLACE)) {
+ skipWrite = true;
+ }
+ }
+
+ // Don't try to write if the node conflict behavior is DO_NOT_REPLACE
+ if (!skipWrite) {
+ if (!newFile.createNewFile()) {
+ I18n msg = FileSystemI18n.fileAlreadyExists;
+ throw new RepositorySourceException(getSourceName(), msg.text(parentPath, getName(), getSourceName()));
+ }
+ }
+ } catch (IOException ioe) {
+ I18n msg = FileSystemI18n.couldNotCreateFile;
+ throw new RepositorySourceException(getSourceName(), msg.text(parentPath,
+ getName(),
+ getSourceName(),
+ ioe.getMessage()), ioe);
+ }
+
+ customPropertiesFactory.recordFileProperties(context,
+ getSourceName(),
+ Location.create(newPath),
+ newFile,
+ properties);
+ } else if (JcrNtLexicon.RESOURCE.equals(primaryType) || DnaLexicon.RESOURCE.equals(primaryType)) {
+ if (!JcrLexicon.CONTENT.equals(name)) {
+ I18n msg = FileSystemI18n.invalidNameForResource;
+ String nodeName = name.getString();
+ throw new RepositorySourceException(getSourceName(), msg.text(parentPath,
+ getName(),
+ getSourceName(),
+ nodeName));
+ }
+
+ if (!parentFile.isFile()) {
+ I18n msg = FileSystemI18n.invalidPathForResource;
+ throw new RepositorySourceException(getSourceName(), msg.text(parentPath, getName(), getSourceName()));
+ }
+
+ if (!parentFile.canWrite()) {
+ I18n msg = FileSystemI18n.parentIsReadOnly;
+ throw new RepositorySourceException(getSourceName(), msg.text(parentPath, getName(), getSourceName()));
+ }
+
+ boolean skipWrite = false;
+
+ if (parentFile.exists()) {
+ if (conflictBehavior.equals(NodeConflictBehavior.APPEND)) {
+ I18n msg = FileSystemI18n.sameNameSiblingsAreNotAllowed;
+ throw new InvalidRequestException(msg.text(getSourceName(), newName));
+ } else if (conflictBehavior.equals(NodeConflictBehavior.DO_NOT_REPLACE)) {
+ // The content node logically maps to the file contents. If there are file contents, don't replace them.
+ FileInputStream checkForContents = null;
+ try {
+ checkForContents = new FileInputStream(parentFile);
+ if (-1 != checkForContents.read()) skipWrite = true;
+
+ } catch (IOException ignore) {
+
+ } finally {
+ try {
+ if (checkForContents != null) checkForContents.close();
+ } catch (Exception ignore) {
+ }
+ }
+ skipWrite = true;
+ }
+ }
+
+ if (!skipWrite) {
+ // Copy over data into a temp file, then move it to the correct location
+ FileOutputStream fos = null;
+ try {
+ File temp = File.createTempFile("dna", null);
+ fos = new FileOutputStream(temp);
+
+ Property dataProp = properties.get(JcrLexicon.DATA);
+ if (dataProp == null) {
+ I18n msg = FileSystemI18n.missingRequiredProperty;
+ String dataPropName = JcrLexicon.DATA.getString();
+ throw new RepositorySourceException(getSourceName(), msg.text(parentPath,
+ getName(),
+ getSourceName(),
+ dataPropName));
+ }
+
+ BinaryFactory binaryFactory = context.getValueFactories().getBinaryFactory();
+ Binary binary = binaryFactory.create(properties.get(JcrLexicon.DATA).getFirstValue());
+
+ IoUtil.write(binary.getStream(), fos);
+
+ if (!FileUtil.delete(parentFile)) {
+ I18n msg = FileSystemI18n.deleteFailed;
+ throw new RepositorySourceException(getSourceName(), msg.text(parentPath, getName(), getSourceName()));
+ }
+
+ if (!temp.renameTo(parentFile)) {
+ I18n msg = FileSystemI18n.couldNotUpdateData;
+ throw new RepositorySourceException(getSourceName(), msg.text(parentPath, getName(), getSourceName()));
+ }
+ } catch (IOException ioe) {
+ I18n msg = FileSystemI18n.couldNotWriteData;
+ throw new RepositorySourceException(getSourceName(), msg.text(parentPath,
+ getName(),
+ getSourceName(),
+ ioe.getMessage()), ioe);
+
+ } finally {
+ try {
+ if (fos != null) fos.close();
+ } catch (Exception ex) {
+ }
+ }
+ }
+ customPropertiesFactory.recordResourceProperties(context,
+ getSourceName(),
+ Location.create(parentPath),
+ newFile,
+ properties);
+
+ } else if (JcrNtLexicon.FOLDER.equals(primaryType) || primaryType == null) {
+ ensureValidPathLength(newFile);
+
+ if (!newFile.mkdir()) {
+ I18n msg = FileSystemI18n.couldNotCreateFile;
+ throw new RepositorySourceException(getSourceName(),
+ msg.text(parentPath,
+ getName(),
+ getSourceName(),
+ primaryType == null ? "null" : primaryType.getString(registry)));
+ }
+ customPropertiesFactory.recordDirectoryProperties(context,
+ getSourceName(),
+ Location.create(newPath),
+ newFile,
+ properties);
+
+ } else {
+ // Set error and return
+ I18n msg = FileSystemI18n.unsupportedPrimaryType;
+ throw new RepositorySourceException(getSourceName(), msg.text(primaryType.getString(registry),
+ parentPath,
+ getName(),
+ getSourceName()));
+ }
+ return getNode(newPath);
+ }
+
+ @Override
+ public boolean removeNode( ExecutionContext context,
+ Path nodePath ) {
+ File nodeFile;
+
+ if (!nodePath.isRoot() && JcrLexicon.CONTENT.equals(nodePath.getLastSegment().getName())) {
+ nodeFile = fileFor(nodePath.getParent());
+ if (!nodeFile.exists()) return false;
+
+ FileOutputStream fos = null;
+ try {
+ fos = new FileOutputStream(nodeFile);
+ IoUtil.write("", fos);
+ } catch (IOException ioe) {
+ throw new RepositorySourceException(getSourceName(), FileSystemI18n.deleteFailed.text(nodePath,
+ getName(),
+ getSourceName()));
+ } finally {
+ if (fos != null) try {
+ fos.close();
+ } catch (IOException ioe) {
+ }
+ }
+ } else {
+ nodeFile = fileFor(nodePath);
+ if (!nodeFile.exists()) return false;
+
+ FileUtil.delete(nodeFile);
+ }
+
+ return true;
+ }
+
+ @Override
+ public PathNode removeProperties( ExecutionContext context,
+ Path nodePath,
+ Iterable<Name> propertyNames ) {
+
+ PathNode targetNode = getNode(nodePath);
+ if (targetNode == null) return null;
+ if (source.getCustomPropertiesFactory() == null) return targetNode;
+
+ Property primaryTypeProp = targetNode.getProperty(JcrLexicon.PRIMARY_TYPE);
+ Name primaryTypeName = (Name)primaryTypeProp.getFirstValue();
+ Map<Name, Property> properties = new HashMap<Name, Property>(targetNode.getProperties());
+
+ for (Name propertyName : propertyNames) {
+ properties.remove(propertyName);
+ }
+
+ CustomPropertiesFactory customPropertiesFactory = source.customPropertiesFactory();
+ Location location = Location.create(nodePath, targetNode.getUuid());
+
+ /*
+ * You can't remove any of the protected properties that the repository provides by default, but you could
+ * remove custom properties.
+ */
+ if (JcrNtLexicon.FILE.equals(primaryTypeName)) {
+ customPropertiesFactory.recordFileProperties(context, getSourceName(), location, fileFor(nodePath), properties);
+ } else if (DnaLexicon.RESOURCE.equals(primaryTypeName)) {
+ File file = fileFor(nodePath.getParent());
+ customPropertiesFactory.recordResourceProperties(context, getSourceName(), location, file, properties);
+ } else {
+ File file = fileFor(nodePath);
+ customPropertiesFactory.recordDirectoryProperties(context, getSourceName(), location, file, properties);
+ }
+
+ return getNode(nodePath);
+ }
+
+ @Override
+ public PathNode setProperties( ExecutionContext context,
+ Path nodePath,
+ Iterable<Property> newProperties ) {
+ PathNode targetNode = getNode(nodePath);
+ if (targetNode == null) return null;
+ if (source.getCustomPropertiesFactory() == null) return targetNode;
+
+ Property primaryTypeProp = targetNode.getProperty(JcrLexicon.PRIMARY_TYPE);
+ Name primaryTypeName = (Name)primaryTypeProp.getFirstValue();
+ Map<Name, Property> properties = new HashMap<Name, Property>(targetNode.getProperties());
+
+ for (Property newProperty : newProperties) {
+ properties.put(newProperty.getName(), newProperty);
+ }
+
+ CustomPropertiesFactory customPropertiesFactory = source.customPropertiesFactory();
+ Location location = Location.create(nodePath, targetNode.getUuid());
+
+ /*
+ * You can't remove any of the protected properties that the repository provides by default, but you could
+ * remove custom properties.
+ */
+ if (JcrNtLexicon.FILE.equals(primaryTypeName)) {
+ customPropertiesFactory.recordFileProperties(context, getSourceName(), location, fileFor(nodePath), properties);
+ } else if (DnaLexicon.RESOURCE.equals(primaryTypeName)) {
+ File file = fileFor(nodePath.getParent());
+ customPropertiesFactory.recordResourceProperties(context, getSourceName(), location, file, properties);
+ } else {
+ File file = fileFor(nodePath);
+ customPropertiesFactory.recordDirectoryProperties(context, getSourceName(), location, file, properties);
+ }
+
+ return getNode(nodePath);
+ }
+
+ @Override
+ public PathNode moveNode( ExecutionContext context,
+ PathNode node,
+ Name desiredNewName,
+ WritablePathWorkspace originalWorkspace,
+ PathNode newParent,
+ PathNode beforeNode ) {
+ if (beforeNode != null) {
+ throw new InvalidRequestException(FileSystemI18n.nodeOrderingNotSupported.text(getSourceName()));
+ }
+ return super.moveNode(context, node, desiredNewName, originalWorkspace, newParent, beforeNode);
+ }
+
+ @Override
+ public Path getLowestExistingPath( Path path ) {
+ File file = workspaceRoot;
+ for (Path.Segment segment : path) {
+ String localName = segment.getName().getLocalName();
+ // Verify the segment is valid ...
+ if (segment.getIndex() > 1) {
+ break;
+ }
+
+ String defaultNamespaceUri = context.getNamespaceRegistry().getDefaultNamespaceUri();
+ if (!segment.getName().getNamespaceUri().equals(defaultNamespaceUri)) {
+ break;
+ }
+
+ // The segment should exist as a child of the file ...
+ file = new File(file, localName);
+ if (!file.exists() || !file.canRead()) {
+ // Unable to complete the path, so prepare the exception by determining the lowest path that exists ...
+ Path lowest = path;
+ while (lowest.getLastSegment() != segment) {
+ lowest = lowest.getParent();
+ }
+ return lowest.getParent();
+ }
+ }
+ // Shouldn't be able to get this far is path is truly invalid
+ return path;
+ }
+
+ @Override
+ public PathNode getNode( Path path ) {
+ Map<Name, Property> properties = new HashMap<Name, Property>();
+
+ PropertyFactory factory = context.getPropertyFactory();
+ PathFactory pathFactory = context.getValueFactories().getPathFactory();
+ DateTimeFactory dateFactory = context.getValueFactories().getDateFactory();
+ MimeTypeDetector mimeTypeDetector = context.getMimeTypeDetector();
+ CustomPropertiesFactory customPropertiesFactory = source.customPropertiesFactory();
+ NamespaceRegistry registry = context.getNamespaceRegistry();
+ Location location = Location.create(path);
+
+ if (!path.isRoot() && JcrLexicon.CONTENT.equals(path.getLastSegment().getName())) {
+ File file = fileFor(path.getParent());
+ if (file == null) return null;
+ // Discover the mime type ...
+ String mimeType = null;
+ InputStream contents = null;
+ try {
+ contents = new BufferedInputStream(new FileInputStream(file));
+ mimeType = mimeTypeDetector.mimeTypeOf(file.getName(), contents);
+ if (mimeType == null) mimeType = DEFAULT_MIME_TYPE;
+ properties.put(JcrLexicon.MIMETYPE, factory.create(JcrLexicon.MIMETYPE, mimeType));
+ } catch (IOException e) {
+ I18n msg = FileSystemI18n.couldNotReadData;
+ throw new RepositorySourceException(getSourceName(), msg.text(getSourceName(),
+ getName(),
+ path.getString(registry)));
+ } finally {
+ if (contents != null) {
+ try {
+ contents.close();
+ } catch (IOException e) {
+ }
+ }
+ }
+
+ // First add any custom properties ...
+ Collection<Property> customProps = customPropertiesFactory.getResourceProperties(context,
+ location,
+ file,
+ mimeType);
+ for (Property customProp : customProps) {
+ properties.put(customProp.getName(), customProp);
+ }
+
+ // The request is to get properties of the "jcr:content" child node ...
+ // ... use the dna:resource node type. This is the same as nt:resource, but is not referenceable
+ // since we cannot assume that we control all access to this file and can track its movements
+ properties.put(JcrLexicon.PRIMARY_TYPE, factory.create(JcrLexicon.PRIMARY_TYPE, DnaLexicon.RESOURCE));
+ properties.put(JcrLexicon.LAST_MODIFIED, factory.create(JcrLexicon.LAST_MODIFIED,
+ dateFactory.create(file.lastModified())));
+ // Don't really know the encoding, either ...
+ // request.addProperty(factory.create(JcrLexicon.ENCODED, stringFactory.create("UTF-8")));
+
+ // Now put the file's content into the "jcr:data" property ...
+ BinaryFactory binaryFactory = context.getValueFactories().getBinaryFactory();
+ properties.put(JcrLexicon.DATA, factory.create(JcrLexicon.DATA, binaryFactory.create(file)));
+ return new DefaultPathNode(path, null, properties, Collections.<Segment>emptyList());
+ }
+
+ File file = fileFor(path);
+ if (file == null) return null;
+
+ if (file.isDirectory()) {
+ String[] childNames = file.list(source.filenameFilter());
+ Arrays.sort(childNames);
+
+ List<Segment> childSegments = new ArrayList<Segment>(childNames.length);
+ for (String childName : childNames) {
+ childSegments.add(pathFactory.createSegment(childName));
+ }
+
+ Collection<Property> customProps = customPropertiesFactory.getDirectoryProperties(context, location, file);
+ for (Property customProp : customProps) {
+ properties.put(customProp.getName(), customProp);
+ }
+
+ if (path.isRoot()) {
+ properties.put(JcrLexicon.PRIMARY_TYPE, factory.create(JcrLexicon.PRIMARY_TYPE, DnaLexicon.ROOT));
+ return new DefaultPathNode(path, source.getRootNodeUuid(), properties, childSegments);
+ }
+ properties.put(JcrLexicon.PRIMARY_TYPE, factory.create(JcrLexicon.PRIMARY_TYPE, JcrNtLexicon.FOLDER));
+ return new DefaultPathNode(path, source.getRootNodeUuid(), properties, childSegments);
+ }
+
+ Collection<Property> customProps = customPropertiesFactory.getFileProperties(context, location, file);
+ for (Property customProp : customProps) {
+ properties.put(customProp.getName(), customProp);
+ }
+ properties.put(JcrLexicon.PRIMARY_TYPE, factory.create(JcrLexicon.PRIMARY_TYPE, JcrNtLexicon.FILE));
+ properties.put(JcrLexicon.CREATED, factory.create(JcrLexicon.CREATED, dateFactory.create(file.lastModified())));
+ return new DefaultPathNode(path, null, properties,
+ Collections.singletonList(pathFactory.createSegment(JcrLexicon.CONTENT)));
+
+ }
+
+ /**
+ * This utility files the existing {@link File} at the supplied path, and in the process will verify that the path is
+ * actually valid.
+ * <p>
+ * Note that this connector represents a file as two nodes: a parent node with a name that matches the file and a "
+ * <code>jcr:primaryType</code>" of "<code>nt:file</code>"; and a child node with the name "<code>jcr:content</code>
+ * " and a " <code>jcr:primaryType</code>" of "<code>nt:resource</code>". The parent "<code>nt:file</code>" node and its
+ * properties represents the file itself, whereas the child "<code>nt:resource</code>" node and its properties represent
+ * the content of the file.
+ * </p>
+ * <p>
+ * As such, this method will return the File object for paths representing both the parent "<code>nt:file</code>
+ * " and child " <code>nt:resource</code>" node.
+ * </p>
+ *
+ * @param path
+ * @return the existing {@link File file} for the path; or null if the path does not represent an existing file and a
+ * {@link PathNotFoundException} was set as the {@link Request#setError(Throwable) error} on the request
+ */
+ protected File fileFor( Path path ) {
+ assert path != null;
+ if (path.isRoot()) {
+ return workspaceRoot;
+ }
+ // See if the path is a "jcr:content" node ...
+ if (path.getLastSegment().getName().equals(JcrLexicon.CONTENT)) {
+ // We only want to use the parent path to find the actual file ...
+ path = path.getParent();
+ }
+ File file = workspaceRoot;
+ for (Path.Segment segment : path) {
+ String localName = segment.getName().getLocalName();
+ // Verify the segment is valid ...
+ if (segment.getIndex() > 1) {
+ I18n msg = FileSystemI18n.sameNameSiblingsAreNotAllowed;
+ throw new RepositorySourceException(getSourceName(), msg.text(getSourceName()));
+ }
+
+ String defaultNamespaceUri = context.getNamespaceRegistry().getDefaultNamespaceUri();
+ if (!segment.getName().getNamespaceUri().equals(defaultNamespaceUri)) {
+ I18n msg = FileSystemI18n.onlyTheDefaultNamespaceIsAllowed;
+ throw new RepositorySourceException(getSourceName(), msg.text(getSourceName()));
+ }
+
+ // The segment should exist as a child of the file ...
+ file = new File(file, localName);
+ if (!file.exists() || !file.canRead()) {
+ return null;
+ }
+ }
+ assert file != null;
+ return file;
+ }
+
+ protected void ensureValidPathLength( File root ) {
+ ensureValidPathLength(root, 0);
+ }
+
+ /**
+ * Recursively checks if any of the files in the tree rooted at {@code root} would exceed the {@link #maxPathLength
+ * maximum path length for the processor} if their paths were {@code delta} characters longer. If any files would exceed
+ * this length, a {@link RepositorySourceException} is thrown.
+ *
+ * @param root the root of the tree to check; may be a file or directory but may not be null
+ * @param delta the change in the length of the path to check. Used to preemptively check whether moving a file or
+ * directory to a new path would violate path length rules
+ * @throws RepositorySourceException if any files in the tree rooted at {@code root} would exceed this
+ * {@link #maxPathLength the maximum path length for this processor}
+ */
+ protected void ensureValidPathLength( File root,
+ int delta ) {
+ try {
+ int len = root.getCanonicalPath().length();
+ if (len > source.getMaxPathLength() - delta) {
+ String msg = FileSystemI18n.maxPathLengthExceeded.text(source.getMaxPathLength(),
+ getSourceName(),
+ root.getCanonicalPath(),
+ delta);
+ throw new RepositorySourceException(getSourceName(), msg);
+ }
+
+ if (root.isDirectory()) {
+ for (File child : root.listFiles(source.filenameFilter())) {
+ ensureValidPathLength(child, delta);
+ }
+
+ }
+ } catch (IOException ioe) {
+ throw new RepositorySourceException(getSourceName(), FileSystemI18n.getCanonicalPathFailed.text(), ioe);
+ }
+ }
+
+ }
+}
Property changes on: trunk/extensions/dna-connector-filesystem/src/main/java/org/jboss/dna/connector/filesystem/FileSystemRepository.java
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Deleted: trunk/extensions/dna-connector-filesystem/src/main/java/org/jboss/dna/connector/filesystem/FileSystemRequestProcessor.java
===================================================================
--- trunk/extensions/dna-connector-filesystem/src/main/java/org/jboss/dna/connector/filesystem/FileSystemRequestProcessor.java 2009-12-27 20:45:58 UTC (rev 1483)
+++ trunk/extensions/dna-connector-filesystem/src/main/java/org/jboss/dna/connector/filesystem/FileSystemRequestProcessor.java 2009-12-29 04:25:02 UTC (rev 1484)
@@ -1,1170 +0,0 @@
-/*
- * JBoss DNA (http://www.jboss.org/dna)
- * 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.
- *
- * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
- * 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.
- *
- * JBoss DNA 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 software; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
- */
-package org.jboss.dna.connector.filesystem;
-
-import java.io.BufferedInputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.FilenameFilter;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.UUID;
-import org.jboss.dna.common.i18n.I18n;
-import org.jboss.dna.common.util.FileUtil;
-import org.jboss.dna.graph.DnaLexicon;
-import org.jboss.dna.graph.ExecutionContext;
-import org.jboss.dna.graph.JcrLexicon;
-import org.jboss.dna.graph.JcrNtLexicon;
-import org.jboss.dna.graph.Location;
-import org.jboss.dna.graph.NodeConflictBehavior;
-import org.jboss.dna.graph.connector.RepositorySourceException;
-import org.jboss.dna.graph.mimetype.MimeTypeDetector;
-import org.jboss.dna.graph.property.Binary;
-import org.jboss.dna.graph.property.BinaryFactory;
-import org.jboss.dna.graph.property.DateTimeFactory;
-import org.jboss.dna.graph.property.Name;
-import org.jboss.dna.graph.property.NameFactory;
-import org.jboss.dna.graph.property.NamespaceRegistry;
-import org.jboss.dna.graph.property.Path;
-import org.jboss.dna.graph.property.PathFactory;
-import org.jboss.dna.graph.property.PathNotFoundException;
-import org.jboss.dna.graph.property.Property;
-import org.jboss.dna.graph.property.PropertyFactory;
-import org.jboss.dna.graph.property.UuidFactory;
-import org.jboss.dna.graph.property.Path.Segment;
-import org.jboss.dna.graph.request.CloneBranchRequest;
-import org.jboss.dna.graph.request.CloneWorkspaceRequest;
-import org.jboss.dna.graph.request.CopyBranchRequest;
-import org.jboss.dna.graph.request.CreateNodeRequest;
-import org.jboss.dna.graph.request.CreateWorkspaceRequest;
-import org.jboss.dna.graph.request.DeleteBranchRequest;
-import org.jboss.dna.graph.request.DestroyWorkspaceRequest;
-import org.jboss.dna.graph.request.GetWorkspacesRequest;
-import org.jboss.dna.graph.request.InvalidRequestException;
-import org.jboss.dna.graph.request.InvalidWorkspaceException;
-import org.jboss.dna.graph.request.MoveBranchRequest;
-import org.jboss.dna.graph.request.ReadAllChildrenRequest;
-import org.jboss.dna.graph.request.ReadAllPropertiesRequest;
-import org.jboss.dna.graph.request.RenameNodeRequest;
-import org.jboss.dna.graph.request.Request;
-import org.jboss.dna.graph.request.UpdatePropertiesRequest;
-import org.jboss.dna.graph.request.VerifyWorkspaceRequest;
-import org.jboss.dna.graph.request.processor.RequestProcessor;
-
-/**
- * The {@link RequestProcessor} implementation for the file systme connector. This is the class that does the bulk of the work in
- * the file system connector, since it processes all requests.
- */
-public class FileSystemRequestProcessor extends RequestProcessor {
-
- private static final String DEFAULT_MIME_TYPE = "application/octet";
-
- private final String defaultNamespaceUri;
- private final Map<String, File> availableWorkspaces;
- private final boolean creatingWorkspacesAllowed;
- private final String defaultWorkspaceName;
- private final File workspaceRootPath;
- private final int maxPathLength;
- private final FilenameFilter filenameFilter;
- private final boolean updatesAllowed;
- private final MimeTypeDetector mimeTypeDetector;
- private final UUID rootNodeUuid;
- private final CustomPropertiesFactory customPropertiesFactory;
- private final FileSystemTransaction txn;
-
- /**
- * @param sourceName
- * @param defaultWorkspaceName
- * @param availableWorkspaces
- * @param creatingWorkspacesAllowed
- * @param context
- * @param rootNodeUuid the UUID for the root node in this workspace; may be null. If not specified, a random UUID will be
- * generated each time that the repository is started.
- * @param workspaceRootPath the path to the workspace root directory; may be null. If specified, all workspace names will be
- * treated as relative paths from this directory.
- * @param maxPathLength the maximum absolute path length supported by this processor
- * @param filenameFilter the filename filter to use to restrict the allowable nodes, or null if all files/directories are to
- * be exposed by this connector
- * @param updatesAllowed true if this connector supports updating the file system, or false if the connector is readonly
- * @param customPropertiesFactory the factory that should be used to create custom properties for "nt:folder", "nt:file", and
- * "nt:resource" nodes
- * @param txn the file system transaction that is used to record the changes and perform any rollback
- */
- protected FileSystemRequestProcessor( String sourceName,
- String defaultWorkspaceName,
- Map<String, File> availableWorkspaces,
- boolean creatingWorkspacesAllowed,
- UUID rootNodeUuid,
- String workspaceRootPath,
- int maxPathLength,
- ExecutionContext context,
- FilenameFilter filenameFilter,
- boolean updatesAllowed,
- CustomPropertiesFactory customPropertiesFactory,
- FileSystemTransaction txn ) {
- super(sourceName, context, null);
- assert defaultWorkspaceName != null;
- assert availableWorkspaces != null;
- assert rootNodeUuid != null;
- assert customPropertiesFactory != null;
- this.availableWorkspaces = availableWorkspaces;
- this.creatingWorkspacesAllowed = creatingWorkspacesAllowed;
- this.defaultNamespaceUri = getExecutionContext().getNamespaceRegistry().getDefaultNamespaceUri();
- this.rootNodeUuid = rootNodeUuid;
- this.maxPathLength = maxPathLength;
- this.filenameFilter = filenameFilter;
- this.defaultWorkspaceName = defaultWorkspaceName;
- this.updatesAllowed = updatesAllowed;
- this.mimeTypeDetector = context.getMimeTypeDetector();
- this.customPropertiesFactory = customPropertiesFactory;
- this.txn = txn;
- assert this.txn != null;
-
- if (workspaceRootPath != null) {
- this.workspaceRootPath = new File(workspaceRootPath);
- if (!this.workspaceRootPath.exists()) {
- throw new IllegalStateException(FileSystemI18n.pathForWorkspaceRootDoesNotExist.text(workspaceRootPath,
- sourceName));
- }
- if (!this.workspaceRootPath.isDirectory()) {
- throw new IllegalStateException(FileSystemI18n.pathForWorkspaceRootIsNotDirectory.text(workspaceRootPath,
- sourceName));
- }
- if (!this.workspaceRootPath.canRead()) {
- throw new IllegalStateException(FileSystemI18n.pathForWorkspaceRootCannotBeRead.text(workspaceRootPath,
- sourceName));
- }
- } else {
- this.workspaceRootPath = null;
- }
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.graph.request.processor.RequestProcessor#process(org.jboss.dna.graph.request.ReadAllChildrenRequest)
- */
- @Override
- public void process( ReadAllChildrenRequest request ) {
-
- // Get the java.io.File object that represents the workspace ...
- File workspaceRoot = getWorkspaceDirectory(request.inWorkspace());
- if (workspaceRoot == null) {
- request.setError(new InvalidWorkspaceException(FileSystemI18n.workspaceDoesNotExist.text(request.inWorkspace())));
- return;
- }
-
- // Find the existing file for the parent ...
- Location location = request.of();
- Path parentPath = getPathFor(location, request);
-
- if (parentPath.isRoot()) {
- if (!location.hasPath()) location = location.with(parentPath);
- }
-
- File parent = getExistingFileFor(workspaceRoot, parentPath, location, request);
- if (parent == null) {
- // An error was set on the request
- assert request.hasError();
- return;
- }
- // Decide how to represent the children ...
- if (parent.isDirectory()) {
- // Create a Location for each file and directory contained by the parent directory ...
- PathFactory pathFactory = pathFactory();
- NameFactory nameFactory = nameFactory();
- for (File child : parent.listFiles(filenameFilter)) {
- if (!child.canRead()) continue;
- Name childName = nameFactory.create(defaultNamespaceUri, child.getName());
- Path childPath = pathFactory.create(parentPath, childName);
- request.addChild(Location.create(childPath));
- }
- } else {
- // The parent is a java.io.File, and the path may refer to the node that is either the "nt:file" parent
- // node, or the child "jcr:content" node...
- if (!parentPath.getLastSegment().getName().equals(JcrLexicon.CONTENT)) {
- // This node represents the "nt:file" parent node, so the only child is the "jcr:content" node ...
- Path contentPath = pathFactory().create(parentPath, JcrLexicon.CONTENT);
- Location content = Location.create(contentPath);
- request.addChild(content);
- }
- // otherwise, the path ends in "jcr:content", and there are no children
- }
- request.setActualLocationOfNode(location);
- setCacheableInfo(request);
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.graph.request.processor.RequestProcessor#process(org.jboss.dna.graph.request.ReadAllPropertiesRequest)
- */
- @Override
- public void process( ReadAllPropertiesRequest request ) {
-
- // Get the java.io.File object that represents the workspace ...
- File workspaceRoot = getWorkspaceDirectory(request.inWorkspace());
- if (workspaceRoot == null) {
- request.setError(new InvalidWorkspaceException(FileSystemI18n.workspaceDoesNotExist.text(request.inWorkspace())));
- return;
- }
-
- PropertyFactory factory = getExecutionContext().getPropertyFactory();
-
- // Find the existing file for the parent ...
- Location location = request.at();
- Path path = getPathFor(location, request);
- if (path.isRoot()) {
- // Root nodes can be requested by UUID, path, or both
- if (!location.hasPath()) location = location.with(path);
- if (location.getUuid() == null) location = location.with(rootNodeUuid);
-
- request.addProperty(factory.create(JcrLexicon.PRIMARY_TYPE, DnaLexicon.ROOT));
- request.setActualLocationOfNode(location);
- setCacheableInfo(request);
-
- return;
- }
-
- File file = getExistingFileFor(workspaceRoot, path, location, request);
- if (file == null) {
- // An error was set on the request
- assert request.hasError();
- return;
- }
- // Generate the properties for this File object ...
- final ExecutionContext context = getExecutionContext();
- final DateTimeFactory dateFactory = context.getValueFactories().getDateFactory();
- // Note that we don't have 'created' timestamps, just last modified, so we'll have to use them
- if (file.isDirectory()) {
- // Add properties for the directory ...
- request.addProperties(customPropertiesFactory.getDirectoryProperties(context, location, file));
- request.addProperty(factory.create(JcrLexicon.PRIMARY_TYPE, JcrNtLexicon.FOLDER));
- request.addProperty(factory.create(JcrLexicon.CREATED, dateFactory.create(file.lastModified())));
- } else {
- // It is a file, but ...
- if (path.getLastSegment().getName().equals(JcrLexicon.CONTENT)) {
- // Discover the mime type ...
- String mimeType = null;
- InputStream contents = null;
- boolean mimeTypeError = false;
- try {
- contents = new BufferedInputStream(new FileInputStream(file));
- mimeType = mimeTypeDetector.mimeTypeOf(file.getName(), contents);
- if (mimeType == null) mimeType = DEFAULT_MIME_TYPE;
- request.addProperty(factory.create(JcrLexicon.MIMETYPE, mimeType));
- } catch (IOException e) {
- mimeTypeError = true;
- request.setError(e);
- } finally {
- if (contents != null) {
- try {
- contents.close();
- } catch (IOException e) {
- if (!mimeTypeError) request.setError(e);
- }
- }
- }
-
- // First add any custom properties ...
- request.addProperties(customPropertiesFactory.getResourceProperties(context, location, file, mimeType));
-
- // The request is to get properties of the "jcr:content" child node ...
- // ... use the dna:resource node type. This is the same as nt:resource, but is not referenceable
- // since we cannot assume that we control all access to this file and can track its movements
- request.addProperty(factory.create(JcrLexicon.PRIMARY_TYPE, DnaLexicon.RESOURCE));
- request.addProperty(factory.create(JcrLexicon.LAST_MODIFIED, dateFactory.create(file.lastModified())));
- // Don't really know the encoding, either ...
- // request.addProperty(factory.create(JcrLexicon.ENCODED, stringFactory.create("UTF-8")));
-
- // Now put the file's content into the "jcr:data" property ...
- BinaryFactory binaryFactory = context.getValueFactories().getBinaryFactory();
- request.addProperty(factory.create(JcrLexicon.DATA, binaryFactory.create(file)));
-
- } else {
- // First add any custom properties ...
- request.addProperties(customPropertiesFactory.getFileProperties(context, location, file));
-
- // The request is to get properties for the node representing the file
- request.addProperty(factory.create(JcrLexicon.PRIMARY_TYPE, JcrNtLexicon.FILE));
- request.addProperty(factory.create(JcrLexicon.CREATED, dateFactory.create(file.lastModified())));
- }
-
- }
- request.setActualLocationOfNode(location);
- setCacheableInfo(request);
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.graph.request.processor.RequestProcessor#process(org.jboss.dna.graph.request.CreateNodeRequest)
- */
- @Override
- public void process( CreateNodeRequest request ) {
- if (!updatesAllowed(request)) return;
-
- Path parentPath = getPathFor(request.under(), request);
- if (parentPath == null) return;
-
- File workspace = getWorkspaceDirectory(request.inWorkspace());
- assert workspace != null;
-
- File parent = getExistingFileFor(workspace, parentPath, request.under(), request);
- if (parent == null) {
- // Error was already set on request in getExistingFileFor
- return;
- }
-
- NamespaceRegistry registry = getExecutionContext().getNamespaceRegistry();
- String newName = request.named().getString(registry);
- File newFile = new File(parent, newName);
-
- Map<Name, Property> properties = new HashMap<Name, Property>(request.properties().size());
- for (Property property : request.properties()) {
- properties.put(property.getName(), property);
- }
-
- Property primaryTypeProp = properties.get(JcrLexicon.PRIMARY_TYPE);
- Name primaryType = primaryTypeProp == null ? null : nameFactory().create(primaryTypeProp.getFirstValue());
-
- Path newPath = pathFactory().create(parentPath, request.named());
- Location actualLocation = Location.create(newPath);
- if (JcrNtLexicon.FILE.equals(primaryType)) {
-
- // The FILE node is represented by the existence of the file
- if (!parent.canWrite()) {
- I18n msg = FileSystemI18n.parentIsReadOnly;
- request.setError(new RepositorySourceException(getSourceName(), msg.text(parent.getPath(),
- request.inWorkspace(),
- getSourceName())));
- return;
- }
-
- try {
- ensureValidPathLength(newFile);
- boolean skipWrite = false;
-
- if (newFile.exists()) {
- if (request.conflictBehavior().equals(NodeConflictBehavior.APPEND)) {
- I18n msg = FileSystemI18n.sameNameSiblingsAreNotAllowed;
- throw new InvalidRequestException(msg.text(this.getSourceName(), newName));
- } else if (request.conflictBehavior().equals(NodeConflictBehavior.DO_NOT_REPLACE)) {
- skipWrite = true;
- }
- }
-
- // Don't try to write if the node conflict behavior is DO_NOT_REPLACE
- if (!skipWrite) {
- if (!newFile.createNewFile()) {
- I18n msg = FileSystemI18n.fileAlreadyExists;
- request.setError(new RepositorySourceException(getSourceName(), msg.text(parent.getPath(),
- request.inWorkspace(),
- getSourceName())));
- return;
- }
- }
- } catch (IOException ioe) {
- I18n msg = FileSystemI18n.couldNotCreateFile;
- request.setError(new RepositorySourceException(getSourceName(), msg.text(parent.getPath(),
- request.inWorkspace(),
- getSourceName(),
- ioe.getMessage()), ioe));
- return;
- }
- customPropertiesFactory.recordFileProperties(getExecutionContext(),
- getSourceName(),
- actualLocation,
- newFile,
- properties);
- } else if (JcrNtLexicon.RESOURCE.equals(primaryType) || DnaLexicon.RESOURCE.equals(primaryType)) {
- if (!JcrLexicon.CONTENT.equals(request.named())) {
- I18n msg = FileSystemI18n.invalidNameForResource;
- String nodeName = request.named().getString(registry);
- request.setError(new RepositorySourceException(getSourceName(), msg.text(parent.getPath(),
- request.inWorkspace(),
- getSourceName(),
- nodeName)));
- return;
- }
-
- if (!parent.isFile()) {
- I18n msg = FileSystemI18n.invalidPathForResource;
- request.setError(new RepositorySourceException(getSourceName(), msg.text(parent.getPath(),
- request.inWorkspace(),
- getSourceName())));
- return;
- }
-
- if (!parent.canWrite()) {
- I18n msg = FileSystemI18n.parentIsReadOnly;
- request.setError(new RepositorySourceException(getSourceName(), msg.text(parent.getPath(),
- request.inWorkspace(),
- getSourceName())));
- return;
- }
-
- boolean skipWrite = false;
-
- if (parent.exists()) {
- if (request.conflictBehavior().equals(NodeConflictBehavior.APPEND)) {
- I18n msg = FileSystemI18n.sameNameSiblingsAreNotAllowed;
- throw new InvalidRequestException(msg.text(this.getSourceName(), newName));
- } else if (request.conflictBehavior().equals(NodeConflictBehavior.DO_NOT_REPLACE)) {
- // The content node logically maps to the file contents. If there are file contents, don't replace them.
- FileInputStream checkForContents = null;
- try {
- checkForContents = new FileInputStream(parent);
- if (-1 != checkForContents.read()) skipWrite = true;
-
- } catch (IOException ignore) {
-
- } finally {
- try {
- if (checkForContents != null) checkForContents.close();
- } catch (Exception ignore) {
- }
- }
- skipWrite = true;
- }
- }
-
- if (!skipWrite) {
- // Copy over data into a temp file, then move it to the correct location
- FileOutputStream fos = null;
- try {
- File temp = File.createTempFile("dna", null);
- fos = new FileOutputStream(temp);
-
- Property dataProp = properties.get(JcrLexicon.DATA);
- if (dataProp == null) {
- I18n msg = FileSystemI18n.missingRequiredProperty;
- String dataPropName = JcrLexicon.DATA.getString(registry);
- request.setError(new RepositorySourceException(getSourceName(), msg.text(parent.getPath(),
- request.inWorkspace(),
- getSourceName(),
- dataPropName)));
- return;
- }
-
- BinaryFactory binaryFactory = getExecutionContext().getValueFactories().getBinaryFactory();
- Binary binary = binaryFactory.create(properties.get(JcrLexicon.DATA).getFirstValue());
- InputStream is = binary.getStream();
-
- final int BUFF_SIZE = 2 << 15;
- byte[] buff = new byte[BUFF_SIZE];
- int len;
- while (-1 != (len = is.read(buff, 0, BUFF_SIZE))) {
- fos.write(buff, 0, len);
- }
- fos.flush();
- fos.close();
- is.close();
-
- if (!FileUtil.delete(parent)) {
- I18n msg = FileSystemI18n.deleteFailed;
- request.setError(new RepositorySourceException(getSourceName(), msg.text(parent.getPath(),
- request.inWorkspace(),
- getSourceName())));
- return;
- }
-
- if (!temp.renameTo(parent)) {
- I18n msg = FileSystemI18n.couldNotUpdateData;
- request.setError(new RepositorySourceException(getSourceName(), msg.text(parent.getPath(),
- request.inWorkspace(),
- getSourceName())));
- return;
-
- }
- } catch (IOException ioe) {
- I18n msg = FileSystemI18n.couldNotWriteData;
- request.setError(new RepositorySourceException(getSourceName(), msg.text(parent.getPath(),
- request.inWorkspace(),
- getSourceName(),
- ioe.getMessage()), ioe));
- return;
-
- } finally {
- try {
- if (fos != null) fos.close();
- } catch (Exception ex) {
- }
- }
- }
- customPropertiesFactory.recordResourceProperties(getExecutionContext(),
- getSourceName(),
- actualLocation,
- newFile,
- properties);
-
- } else if (JcrNtLexicon.FOLDER.equals(primaryType) || primaryType == null) {
- ensureValidPathLength(newFile);
-
- if (!newFile.mkdir()) {
- I18n msg = FileSystemI18n.couldNotCreateFile;
- request.setError(new RepositorySourceException(
- getSourceName(),
- msg.text(parent.getPath(),
- request.inWorkspace(),
- getSourceName(),
- primaryType == null ? "null" : primaryType.getString(registry))));
- return;
- }
- customPropertiesFactory.recordDirectoryProperties(getExecutionContext(),
- getSourceName(),
- actualLocation,
- newFile,
- properties);
- } else {
- // Set error and return
- I18n msg = FileSystemI18n.unsupportedPrimaryType;
- request.setError(new RepositorySourceException(getSourceName(), msg.text(primaryType.getString(registry),
- parent.getPath(),
- request.inWorkspace(),
- getSourceName())));
- return;
- }
-
- request.setActualLocationOfNode(actualLocation);
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.graph.request.processor.RequestProcessor#process(org.jboss.dna.graph.request.UpdatePropertiesRequest)
- */
- @Override
- public void process( UpdatePropertiesRequest request ) {
- if (!updatesAllowed(request)) return;
-
- Path path = request.on().getPath();
- File workspace = getWorkspaceDirectory(request.inWorkspace());
- File target = getExistingFileFor(workspace, path, request.on(), request);
-
- if (!target.exists()) {
- // getExistingFile fills in the PathNotFoundException for non-existent files
- assert request.hasError();
- return;
- }
-
- Location location = request.on();
- Set<Name> createdProperties = null;
- if (target.isFile()) {
- if (path.endsWith(JcrLexicon.CONTENT)) {
- createdProperties = customPropertiesFactory.recordResourceProperties(getExecutionContext(),
- getSourceName(),
- location,
- target,
- request.properties());
- } else {
- createdProperties = customPropertiesFactory.recordFileProperties(getExecutionContext(),
- getSourceName(),
- location,
- target,
- request.properties());
- }
- } else {
- assert target.isDirectory();
- createdProperties = customPropertiesFactory.recordDirectoryProperties(getExecutionContext(),
- getSourceName(),
- location,
- target,
- request.properties());
- }
-
- request.setActualLocationOfNode(location);
- if (createdProperties != null) {
- request.setNewProperties(createdProperties);
- }
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.graph.request.processor.RequestProcessor#process(org.jboss.dna.graph.request.CopyBranchRequest)
- */
- @Override
- public void process( CopyBranchRequest request ) {
- if (!updatesAllowed(request)) return;
-
- File fromWorkspace = getWorkspaceDirectory(request.fromWorkspace());
- File intoWorkspace = getWorkspaceDirectory(request.intoWorkspace());
- Path fromPath = getPathFor(request.from(), request);
- if (fromPath == null) return;
- File from = getExistingFileFor(fromWorkspace, fromPath, request.from(), request);
-
- Path intoPath = getPathFor(request.into(), request);
- if (intoPath == null) return;
- File into = getExistingFileFor(intoWorkspace, intoPath, request.into(), request);
-
- NamespaceRegistry registry = getExecutionContext().getNamespaceRegistry();
- Name desiredName = request.desiredName();
- String fileName = desiredName != null ? desiredName.getString(registry) : fromPath.getLastSegment().getString(registry);
- File target = new File(into, fileName);
- File tempInto = null;
-
- Location actualFrom = null;
- Location actualTo = null;
- try {
- actualFrom = locationFor(fromWorkspace, from);
- actualTo = locationFor(intoWorkspace, target);
- } catch (IOException ioe) {
- throw new RepositorySourceException(this.getSourceName(), FileSystemI18n.getCanonicalPathFailed.text(), ioe);
- }
-
- try {
- int pathLenDelta = into.getCanonicalPath().length() - from.getCanonicalFile().getParent().length();
- if (pathLenDelta > 0) {
- ensureValidPathLength(from, pathLenDelta);
- }
- } catch (IOException ioe) {
- throw new RepositorySourceException(this.getSourceName(), FileSystemI18n.getCanonicalPathFailed.text(), ioe);
- }
-
- if (target.exists() && from.isFile()) {
- try {
- tempInto = File.createTempFile("dna", null, into);
- } catch (IOException ioe) {
- throw new RepositorySourceException(this.getSourceName(),
- FileSystemI18n.couldNotCreateFile.text("temporary file",
- request.intoWorkspace(),
- getSourceName(),
- ioe.getMessage()), ioe);
- }
-
- try {
- FileUtil.copy(from, tempInto);
- } catch (IOException ioe) {
- FileUtil.delete(tempInto);
- throw new RepositorySourceException(this.getSourceName(), FileSystemI18n.copyFailed.text(from.getPath(),
- request.fromWorkspace(),
- tempInto.getPath(),
- request.intoWorkspace(),
- getSourceName()), ioe);
- }
-
- // If everything worked, delete whatever was there and rename
- if (target.exists()) {
- if (!FileUtil.delete(target)) {
- I18n msg = FileSystemI18n.deleteFailed;
- request.setError(new RepositorySourceException(getSourceName(), msg.text(target.getPath(),
- request.intoWorkspace(),
- getSourceName())));
- FileUtil.delete(tempInto);
- return;
- }
- }
-
- if (!tempInto.renameTo(target)) {
- I18n msg = FileSystemI18n.couldNotUpdateData;
- request.setError(new RepositorySourceException(getSourceName(), msg.text(target.getPath(),
- request.intoWorkspace(),
- getSourceName())));
- FileUtil.delete(tempInto);
- return;
- }
- } else {
- if (!from.renameTo(target)) {
- I18n msg = FileSystemI18n.couldNotUpdateData;
- request.setError(new RepositorySourceException(getSourceName(), msg.text(target.getPath(),
- request.intoWorkspace(),
- getSourceName())));
- return;
- }
-
- }
- request.setActualLocations(actualFrom, actualTo);
-
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.graph.request.processor.RequestProcessor#process(org.jboss.dna.graph.request.CloneBranchRequest)
- */
- @Override
- public void process( CloneBranchRequest request ) {
- if (!updatesAllowed(request)) return;
-
- CopyBranchRequest copy = new CopyBranchRequest(request.from(), request.fromWorkspace(), request.into(),
- request.intoWorkspace(), request.desiredName());
-
- process(copy);
-
- if (copy.hasError()) {
- request.setError(copy.getError());
- return;
- }
-
- request.setActualLocations(copy.getActualLocationBefore(), copy.getActualLocationAfter());
- request.setRemovedNodes(null);
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.graph.request.processor.RequestProcessor#process(org.jboss.dna.graph.request.DeleteBranchRequest)
- */
- @Override
- public void process( DeleteBranchRequest request ) {
- if (!updatesAllowed(request)) return;
-
- File workspace = getWorkspaceDirectory(request.inWorkspace());
- Path targetPath = getPathFor(request.at(), request);
- if (targetPath == null) return;
-
- File target = getExistingFileFor(workspace, targetPath, request.at(), request);
- Location actual = null;
-
- try {
- actual = locationFor(workspace, target);
- } catch (IOException ioe) {
- throw new RepositorySourceException(this.getSourceName(), FileSystemI18n.getCanonicalPathFailed.text(), ioe);
- }
-
- if (!FileUtil.delete(target)) {
- request.setError(new RepositorySourceException(this.getSourceName(),
- FileSystemI18n.deleteFailed.text(target.getPath(),
- request.inWorkspace(),
- getSourceName())));
- return;
- }
-
- request.setActualLocationOfNode(actual);
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.graph.request.processor.RequestProcessor#process(org.jboss.dna.graph.request.MoveBranchRequest)
- */
- @Override
- public void process( MoveBranchRequest request ) {
- if (!updatesAllowed(request)) return;
-
- /* This connector does not support node ordering */
- if (request.before() != null) {
- throw new InvalidRequestException(FileSystemI18n.nodeOrderingNotSupported.text(this.getSourceName()));
- }
-
- File workspace = getWorkspaceDirectory(request.inWorkspace());
- Path fromPath = getPathFor(request.from(), request);
- if (fromPath == null) return;
- File from = getExistingFileFor(workspace, fromPath, request.from(), request);
-
- Path intoPath = getPathFor(request.into(), request);
- if (intoPath == null) return;
- File into = getExistingFileFor(workspace, intoPath, request.into(), request);
-
- NamespaceRegistry registry = getExecutionContext().getNamespaceRegistry();
- Name desiredName = request.desiredName();
- String fileName = desiredName != null ? desiredName.getString(registry) : fromPath.getLastSegment().getString(registry);
- File target = new File(into, fileName);
-
- Location actualFrom = null;
- Location actualTo = null;
- try {
- actualFrom = locationFor(workspace, from);
- actualTo = locationFor(workspace, target);
- } catch (IOException ioe) {
- request.setError(new RepositorySourceException(this.getSourceName(), FileSystemI18n.getCanonicalPathFailed.text()));
- return;
- }
-
- try {
- int pathLenDelta = into.getCanonicalPath().length() - from.getCanonicalFile().getParent().length();
- if (pathLenDelta > 0) {
- ensureValidPathLength(from, pathLenDelta);
- }
- } catch (IOException ioe) {
- request.setError(new RepositorySourceException(this.getSourceName(), FileSystemI18n.getCanonicalPathFailed.text()));
- return;
- }
-
- if (!from.renameTo(target)) {
- I18n msg = FileSystemI18n.couldNotUpdateData;
- request.setError(new RepositorySourceException(getSourceName(),
- msg.text(target.getPath(), workspace, getSourceName())));
- return;
- }
-
- request.setActualLocations(actualFrom, actualTo);
-
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.graph.request.processor.RequestProcessor#process(org.jboss.dna.graph.request.RenameNodeRequest)
- */
- @Override
- public void process( RenameNodeRequest request ) {
- if (!updatesAllowed(request)) return;
-
- super.process(request);
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.graph.request.processor.RequestProcessor#process(org.jboss.dna.graph.request.CloneWorkspaceRequest)
- */
- @Override
- public void process( CloneWorkspaceRequest request ) {
- if (!updatesAllowed(request)) return;
-
- CreateWorkspaceRequest create = new CreateWorkspaceRequest(request.desiredNameOfTargetWorkspace(),
- request.targetConflictBehavior());
- process(create);
-
- if (create.hasError()) {
- request.setError(create.getError());
- return;
- }
-
- File fromWorkspace = getWorkspaceDirectory(request.nameOfWorkspaceToBeCloned());
- assert fromWorkspace != null;
- File toWorkspace = getWorkspaceDirectory(create.getActualWorkspaceName());
- assert toWorkspace != null;
-
- try {
- FileUtil.copy(fromWorkspace, toWorkspace);
- request.setActualWorkspaceName(create.getActualWorkspaceName());
- request.setActualRootLocation(Location.create(pathFactory().createRootPath(), this.rootNodeUuid));
- } catch (IOException ioe) {
- throw new RepositorySourceException(this.getSourceName(), ioe.getMessage());
- }
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.graph.request.processor.RequestProcessor#process(org.jboss.dna.graph.request.VerifyWorkspaceRequest)
- */
- @Override
- public void process( VerifyWorkspaceRequest request ) {
- // If the request contains a null name, then we use the default ...
- String workspaceName = request.workspaceName();
- if (workspaceName == null) workspaceName = defaultWorkspaceName;
-
- if (!this.creatingWorkspacesAllowed) {
- // Then the workspace name must be one of the available names ...
-
- boolean found = false;
- for (String available : this.availableWorkspaces.keySet()) {
- if (workspaceName.equals(available)) {
- found = true;
- break;
- }
- }
-
- if (!found) {
- request.setError(new InvalidWorkspaceException(FileSystemI18n.workspaceDoesNotExist.text(workspaceName)));
- return;
- }
- // We know it is an available workspace, so just continue ...
- }
- // Verify that there is a directory at the path given by the workspace name ...
- File directory = availableWorkspaces.get(workspaceName);
- if (directory.exists() && directory.isDirectory() && directory.canRead()) {
- request.setActualWorkspaceName(workspaceName);
- request.setActualRootLocation(Location.create(pathFactory().createRootPath()));
- } else {
- request.setError(new InvalidWorkspaceException(FileSystemI18n.workspaceDoesNotExist.text(workspaceName)));
- }
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.graph.request.processor.RequestProcessor#process(org.jboss.dna.graph.request.GetWorkspacesRequest)
- */
- @Override
- public void process( GetWorkspacesRequest request ) {
- // Return the set of available workspace names, even if new workspaces can be created ...
- Set<String> names = new HashSet<String>();
- for (Map.Entry<String, File> entry : this.availableWorkspaces.entrySet()) {
- File directory = entry.getValue();
- if (directory.exists() && directory.isDirectory() && directory.canRead()) {
- names.add(entry.getKey());
- }
- }
-
- request.setAvailableWorkspaceNames(Collections.unmodifiableSet(names));
- }
-
- /**
- * Utility method to return the canonical path (without "." and ".." segments) for a file.
- *
- * @param directory the directory; may not be null
- * @return the canonical path, or if there is an error the absolute path
- */
- protected String getCanonicalWorkspaceName( File directory ) {
- try {
- if (this.workspaceRootPath != null) {
- String directoryCanonicalPath = directory.getCanonicalPath();
- String rootCanonicalPath = workspaceRootPath.getCanonicalPath();
- assert directoryCanonicalPath.startsWith(rootCanonicalPath);
- return directoryCanonicalPath.substring(rootCanonicalPath.length() + 1);
- }
- return directory.getCanonicalPath();
- } catch (IOException e) {
- return directory.getAbsolutePath();
- }
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.graph.request.processor.RequestProcessor#process(org.jboss.dna.graph.request.CreateWorkspaceRequest)
- */
- @Override
- public void process( CreateWorkspaceRequest request ) {
- final String workspaceName = request.desiredNameOfNewWorkspace();
- if (!creatingWorkspacesAllowed) {
- String msg = FileSystemI18n.unableToCreateWorkspaces.text(getSourceName(), workspaceName);
- request.setError(new InvalidRequestException(msg));
- return;
- }
- // This doesn't create the directory representing the workspace (it must already exist), but it will add
- // the workspace name to the available names ...
- File directory = getWorkspaceDirectory(workspaceName);
- if (directory.exists() && directory.isDirectory() && directory.canRead()) {
- request.setActualWorkspaceName(getCanonicalWorkspaceName(directory));
- request.setActualRootLocation(Location.create(pathFactory().createRootPath()));
- availableWorkspaces.put(workspaceName, directory);
- recordChange(request);
- } else {
- request.setError(new InvalidWorkspaceException(FileSystemI18n.workspaceDoesNotExist.text(workspaceName)));
- }
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.graph.request.processor.RequestProcessor#process(org.jboss.dna.graph.request.DestroyWorkspaceRequest)
- */
- @Override
- public void process( DestroyWorkspaceRequest request ) {
- final String workspaceName = request.workspaceName();
- if (!creatingWorkspacesAllowed) {
- String msg = FileSystemI18n.unableToCreateWorkspaces.text(getSourceName(), workspaceName);
- request.setError(new InvalidRequestException(msg));
- }
- // This doesn't delete the file/directory; rather, it just remove the workspace from the available set ...
- if (this.availableWorkspaces.remove(workspaceName) == null) {
- request.setError(new InvalidWorkspaceException(FileSystemI18n.workspaceDoesNotExist.text(workspaceName)));
- } else {
- request.setActualRootLocation(Location.create(pathFactory().createRootPath()));
- recordChange(request);
- }
- }
-
- protected boolean updatesAllowed( Request request ) {
- if (!updatesAllowed) {
- request.setError(new InvalidRequestException(FileSystemI18n.sourceIsReadOnly.text(getSourceName())));
- }
- return !request.hasError();
- }
-
- private UUID uuidFor( Location location ) {
- if (location.getUuid() != null) return location.getUuid();
- if (!location.hasIdProperties()) return null;
-
- for (Property idProperty : location.getIdProperties()) {
- if (JcrLexicon.UUID.equals(idProperty.getName())) {
- return uuidFactory().create(idProperty.getFirstValue());
- }
- }
-
- return null;
- }
-
- protected NameFactory nameFactory() {
- return getExecutionContext().getValueFactories().getNameFactory();
- }
-
- protected PathFactory pathFactory() {
- return getExecutionContext().getValueFactories().getPathFactory();
- }
-
- protected UuidFactory uuidFactory() {
- return getExecutionContext().getValueFactories().getUuidFactory();
- }
-
- protected void ensureValidPathLength( File root ) {
- ensureValidPathLength(root, 0);
- }
-
- /**
- * Recursively checks if any of the files in the tree rooted at {@code root} would exceed the {@link #maxPathLength maximum
- * path length for the processor} if their paths were {@code delta} characters longer. If any files would exceed this length,
- * a {@link RepositorySourceException} is thrown.
- *
- * @param root the root of the tree to check; may be a file or directory but may not be null
- * @param delta the change in the length of the path to check. Used to preemptively check whether moving a file or directory
- * to a new path would violate path length rules
- * @throws RepositorySourceException if any files in the tree rooted at {@code root} would exceed this {@link #maxPathLength
- * the maximum path length for this processor}
- */
- protected void ensureValidPathLength( File root,
- int delta ) {
- try {
- int len = root.getCanonicalPath().length();
- if (len > maxPathLength - delta) {
- String msg = FileSystemI18n.maxPathLengthExceeded.text(this.maxPathLength,
- this.getSourceName(),
- root.getCanonicalPath(),
- delta);
- throw new RepositorySourceException(this.getSourceName(), msg);
- }
-
- if (root.isDirectory()) {
- for (File child : root.listFiles(filenameFilter)) {
- ensureValidPathLength(child, delta);
- }
-
- }
- } catch (IOException ioe) {
- throw new RepositorySourceException(this.getSourceName(), FileSystemI18n.getCanonicalPathFailed.text(), ioe);
- }
- }
-
- protected Location locationFor( File workspaceRoot,
- File path ) throws IOException {
- assert workspaceRoot != null;
- assert path != null;
- assert path.getCanonicalPath().startsWith(workspaceRoot.getCanonicalPath());
-
- String relativePath = path.getCanonicalPath().substring(workspaceRoot.getCanonicalPath().length());
- PathFactory pathFactory = pathFactory();
- List<Segment> segments = new LinkedList<Segment>();
-
- String sepString = File.separator.equals("\\") ? "\\\\" : File.separator;
- assert relativePath.charAt(0) == File.separatorChar;
- for (String segment : relativePath.substring(1).split(sepString)) {
- segments.add(pathFactory.createSegment(segment, 1));
- }
-
- return Location.create(pathFactory().createAbsolutePath(segments));
- }
-
- protected Path getPathFor( Location location,
- Request request ) {
-
- if (location.hasPath()) return location.getPath();
-
- UUID uuid = uuidFor(location);
- if (rootNodeUuid.equals(uuid)) {
- return pathFactory().createRootPath();
- }
-
- I18n msg = FileSystemI18n.locationInRequestMustHavePath;
- request.setError(new RepositorySourceException(getSourceName(), msg.text(getSourceName(), request)));
- return null;
- }
-
- protected File getWorkspaceDirectory( String workspaceName ) {
- if (workspaceName == null) workspaceName = defaultWorkspaceName;
-
- File directory = this.workspaceRootPath == null ? new File(workspaceName) : new File(workspaceRootPath, workspaceName);
- if (directory.exists() && directory.isDirectory() && directory.canRead()) return directory;
- return null;
- }
-
- /**
- * This utility files the existing {@link File} at the supplied path, and in the process will verify that the path is actually
- * valid.
- * <p>
- * Note that this connector represents a file as two nodes: a parent node with a name that matches the file and a "
- * <code>jcr:primaryType</code>" of "<code>nt:file</code>"; and a child node with the name "<code>jcr:content</code>" and a "
- * <code>jcr:primaryType</code>" of "<code>nt:resource</code>". The parent "<code>nt:file</code>" node and its properties
- * represents the file itself, whereas the child "<code>nt:resource</code>" node and its properties represent the content of
- * the file.
- * </p>
- * <p>
- * As such, this method will return the File object for paths representing both the parent "<code>nt:file</code>" and child "
- * <code>nt:resource</code>" node.
- * </p>
- *
- * @param workspaceRoot
- * @param path
- * @param location the location containing the path; may not be null
- * @param request the request containing the path (and the location); may not be null
- * @return the existing {@link File file} for the path; or null if the path does not represent an existing file and a
- * {@link PathNotFoundException} was set as the {@link Request#setError(Throwable) error} on the request
- */
- protected File getExistingFileFor( File workspaceRoot,
- Path path,
- Location location,
- Request request ) {
- assert path != null;
- assert location != null;
- assert request != null;
- if (path.isRoot()) {
- return workspaceRoot;
- }
- // See if the path is a "jcr:content" node ...
- if (path.getLastSegment().getName().equals(JcrLexicon.CONTENT)) {
- // We only want to use the parent path to find the actual file ...
- path = path.getParent();
- }
- File file = workspaceRoot;
- for (Path.Segment segment : path) {
- String localName = segment.getName().getLocalName();
- // Verify the segment is valid ...
- if (segment.getIndex() > 1) {
- I18n msg = FileSystemI18n.sameNameSiblingsAreNotAllowed;
- throw new RepositorySourceException(getSourceName(), msg.text(getSourceName(), request));
- }
- if (!segment.getName().getNamespaceUri().equals(defaultNamespaceUri)) {
- I18n msg = FileSystemI18n.onlyTheDefaultNamespaceIsAllowed;
- throw new RepositorySourceException(getSourceName(), msg.text(getSourceName(), request));
- }
- // The segment should exist as a child of the file ...
- file = new File(file, localName);
- if (!file.exists() || !file.canRead()) {
- // Unable to complete the path, so prepare the exception by determining the lowest path that exists ...
- Path lowest = path;
- while (lowest.getLastSegment() != segment) {
- lowest = lowest.getParent();
- }
- lowest = lowest.getParent();
- request.setError(new PathNotFoundException(location, lowest));
- return null;
- }
- }
- assert file != null;
- return file;
- }
-}
Modified: trunk/extensions/dna-connector-filesystem/src/main/java/org/jboss/dna/connector/filesystem/FileSystemSource.java
===================================================================
--- trunk/extensions/dna-connector-filesystem/src/main/java/org/jboss/dna/connector/filesystem/FileSystemSource.java 2009-12-27 20:45:58 UTC (rev 1483)
+++ trunk/extensions/dna-connector-filesystem/src/main/java/org/jboss/dna/connector/filesystem/FileSystemSource.java 2009-12-29 04:25:02 UTC (rev 1484)
@@ -43,7 +43,6 @@
import java.util.Map;
import java.util.Set;
import java.util.UUID;
-import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Pattern;
import javax.naming.BinaryRefAddr;
import javax.naming.Context;
@@ -55,7 +54,6 @@
import net.jcip.annotations.ThreadSafe;
import org.jboss.dna.common.i18n.I18n;
import org.jboss.dna.common.util.CheckArg;
-import org.jboss.dna.common.util.Logger;
import org.jboss.dna.common.util.StringUtil;
import org.jboss.dna.graph.DnaIntLexicon;
import org.jboss.dna.graph.ExecutionContext;
@@ -67,6 +65,8 @@
import org.jboss.dna.graph.connector.RepositorySource;
import org.jboss.dna.graph.connector.RepositorySourceCapabilities;
import org.jboss.dna.graph.connector.RepositorySourceException;
+import org.jboss.dna.graph.connector.path.PathRepositoryConnection;
+import org.jboss.dna.graph.connector.path.PathRepositorySource;
import org.jboss.dna.graph.property.Name;
import org.jboss.dna.graph.property.NamespaceRegistry;
import org.jboss.dna.graph.property.Property;
@@ -77,7 +77,7 @@
* workspace. New workspaces can be created, as long as the names represent valid paths to existing directories.
*/
@ThreadSafe
-public class FileSystemSource implements RepositorySource, ObjectFactory {
+public class FileSystemSource implements PathRepositorySource, ObjectFactory {
/**
* An immutable {@link CustomPropertiesFactory} implementation that is used by default when none is provided. Note that this
@@ -148,8 +148,9 @@
SUPPORTS_EVENTS,
DEFAULT_SUPPORTS_CREATING_WORKSPACES,
SUPPORTS_REFERENCES);
- private transient CachePolicy cachePolicy;
- private transient Map<String, File> availableWorkspaces;
+ private transient RepositoryContext repositoryContext;
+ private transient CachePolicy defaultCachePolicy;
+ private transient FileSystemRepository repository;
private volatile CustomPropertiesFactory customPropertiesFactory;
/**
@@ -237,6 +238,22 @@
this.exclusionPattern = exclusionPattern;
}
+ FilenameFilter filenameFilter() {
+ FilenameFilter filenameFilter = null;
+ final String filterPattern = exclusionPattern;
+ if (filterPattern != null) {
+ filenameFilter = new FilenameFilter() {
+ Pattern filter = Pattern.compile(filterPattern);
+
+ public boolean accept( File dir,
+ String name ) {
+ return !filter.matcher(name).matches();
+ }
+ };
+ }
+ return filenameFilter;
+ }
+
/**
* Get the UUID that is used for the root node of each workspace
*
@@ -413,7 +430,7 @@
public synchronized void setCacheTimeToLiveInMilliseconds( int cacheTimeToLive ) {
if (cacheTimeToLive < 0) cacheTimeToLive = DEFAULT_CACHE_TIME_TO_LIVE_IN_SECONDS;
this.cacheTimeToLiveInMilliseconds = cacheTimeToLive;
- this.cachePolicy = cacheTimeToLiveInMilliseconds > 0 ? new FileSystemCachePolicy(cacheTimeToLiveInMilliseconds) : null;
+ this.defaultCachePolicy = cacheTimeToLiveInMilliseconds > 0 ? new FileSystemCachePolicy(cacheTimeToLiveInMilliseconds) : null;
}
/**
@@ -425,6 +442,10 @@
return customPropertiesFactory;
}
+ CustomPropertiesFactory customPropertiesFactory() {
+ return customPropertiesFactory != null ? customPropertiesFactory : DEFAULT_PROPERTIES_FACTORY;
+ }
+
/**
* Set the factory that is used to create custom properties on "nt:folder", "nt:file", and "nt:resource" nodes.
*
@@ -440,9 +461,19 @@
* @see org.jboss.dna.graph.connector.RepositorySource#initialize(org.jboss.dna.graph.connector.RepositoryContext)
*/
public synchronized void initialize( RepositoryContext context ) throws RepositorySourceException {
- // No need to do anything
+ this.repositoryContext = context;
}
+ @Override
+ public RepositoryContext getRepositoryContext() {
+ return this.repositoryContext;
+ }
+
+ @Override
+ public CachePolicy getDefaultCachePolicy() {
+ return defaultCachePolicy;
+ }
+
/**
* {@inheritDoc}
*
@@ -542,18 +573,6 @@
return null;
}
- private String pathFor( String workspaceName ) {
- String path = workspaceName;
- if (this.workspaceRootPath != null) {
- if (this.workspaceRootPath.charAt(workspaceRootPath.length() - 1) == File.separatorChar) {
- path = this.workspaceRootPath + workspaceName;
- }
- path = this.workspaceRootPath + File.separatorChar + workspaceName;
- }
-
- return path;
- }
-
/**
* {@inheritDoc}
*
@@ -566,70 +585,17 @@
throw new RepositorySourceException(getName(), msg.text("name"));
}
- if (this.availableWorkspaces == null) {
- // Set up the predefined workspace names ...
- this.availableWorkspaces = new ConcurrentHashMap<String, File>();
- for (String predefined : this.predefinedWorkspaces) {
- // Look for the file at this path ...
- File file = new File(pathFor(predefined));
- if (!file.exists()) {
- Logger.getLogger(getClass()).warn(FileSystemI18n.pathForPredefinedWorkspaceDoesNotExist, predefined, name);
- } else if (!file.isDirectory()) {
- Logger.getLogger(getClass()).warn(FileSystemI18n.pathForPredefinedWorkspaceIsNotDirectory, predefined, name);
- } else if (!file.canRead()) {
- Logger.getLogger(getClass()).warn(FileSystemI18n.pathForPredefinedWorkspaceCannotBeRead, predefined, name);
- }
-
- this.availableWorkspaces.put(predefined, file);
- }
- }
-
- if (defaultWorkspaceName != null) {
- // Look for the file at this path ...
- File file = new File(pathFor(defaultWorkspaceName));
- if (!file.exists()) {
- Logger.getLogger(getClass()).warn(FileSystemI18n.pathForPredefinedWorkspaceDoesNotExist,
- defaultWorkspaceName,
- name);
- } else if (!file.isDirectory()) {
- Logger.getLogger(getClass()).warn(FileSystemI18n.pathForPredefinedWorkspaceIsNotDirectory,
- defaultWorkspaceName,
- name);
- } else if (!file.canRead()) {
- Logger.getLogger(getClass()).warn(FileSystemI18n.pathForPredefinedWorkspaceCannotBeRead,
- defaultWorkspaceName,
- name);
- }
-
- this.availableWorkspaces.put(defaultWorkspaceName, file);
- }
-
- FilenameFilter filenameFilter = null;
- if (exclusionPattern != null) {
- final String filterPattern = exclusionPattern;
- filenameFilter = new FilenameFilter() {
- Pattern filter = Pattern.compile(filterPattern);
-
- public boolean accept( File dir,
- String name ) {
- return !filter.matcher(name).matches();
- }
- };
- }
-
- CustomPropertiesFactory propFactory = customPropertiesFactory != null ? customPropertiesFactory : DEFAULT_PROPERTIES_FACTORY;
- return new FileSystemConnection(name, defaultWorkspaceName, availableWorkspaces, isCreatingWorkspacesAllowed(),
- cachePolicy, rootNodeUuid, workspaceRootPath, maxPathLength, filenameFilter,
- getUpdatesAllowed(), propFactory);
+ if (repository == null) repository = new FileSystemRepository(this);
+ return new PathRepositoryConnection(this, repository);
}
+
/**
* {@inheritDoc}
*
* @see org.jboss.dna.graph.connector.RepositorySource#close()
*/
public synchronized void close() {
- this.availableWorkspaces = null;
}
protected static class StandardPropertiesFactory implements CustomPropertiesFactory {
Modified: trunk/extensions/dna-connector-filesystem/src/main/java/org/jboss/dna/connector/filesystem/FileSystemTransaction.java
===================================================================
--- trunk/extensions/dna-connector-filesystem/src/main/java/org/jboss/dna/connector/filesystem/FileSystemTransaction.java 2009-12-27 20:45:58 UTC (rev 1483)
+++ trunk/extensions/dna-connector-filesystem/src/main/java/org/jboss/dna/connector/filesystem/FileSystemTransaction.java 2009-12-29 04:25:02 UTC (rev 1484)
@@ -23,17 +23,19 @@
*/
package org.jboss.dna.connector.filesystem;
+import org.jboss.dna.graph.connector.path.PathRepositoryTransaction;
+
/**
- * A transaction returned by the {@link FileSystemConnection#startTransaction(boolean)}.
+ * A transaction returned by the {@link FileSystemRepository#startTransaction(boolean)}.
*/
-public class FileSystemTransaction {
+public class FileSystemTransaction implements PathRepositoryTransaction {
/**
* Commit any changes that have been made to the repository. This method may throw runtime exceptions if there are failures
* committing the changes, but the transaction is still expected to be closed.
*
* @see #rollback()
- * @see FileSystemConnection#startTransaction(boolean)
+ * @see FileSystemRepository#startTransaction(boolean)
*/
public void commit() {
}
@@ -43,7 +45,7 @@
* rolling back the changes, but the transaction is still expected to be closed.
*
* @see #commit()
- * @see FileSystemConnection#startTransaction(boolean)
+ * @see FileSystemRepository#startTransaction(boolean)
*/
public void rollback() {
}
Modified: trunk/extensions/dna-connector-filesystem/src/main/java/org/jboss/dna/connector/filesystem/package-info.java
===================================================================
--- trunk/extensions/dna-connector-filesystem/src/main/java/org/jboss/dna/connector/filesystem/package-info.java 2009-12-27 20:45:58 UTC (rev 1483)
+++ trunk/extensions/dna-connector-filesystem/src/main/java/org/jboss/dna/connector/filesystem/package-info.java 2009-12-29 04:25:02 UTC (rev 1484)
@@ -23,6 +23,7 @@
*/
/**
* The classes that make up the connector that accesses the files and directories on a local file system and exposes them as content in a repository.
+ * This connector is based on the {@link WritablePathRepository path repository framework}.
*/
package org.jboss.dna.connector.filesystem;
Modified: trunk/extensions/dna-connector-filesystem/src/main/resources/org/jboss/dna/connector/filesystem/FileSystemI18n.properties
===================================================================
--- trunk/extensions/dna-connector-filesystem/src/main/resources/org/jboss/dna/connector/filesystem/FileSystemI18n.properties 2009-12-27 20:45:58 UTC (rev 1483)
+++ trunk/extensions/dna-connector-filesystem/src/main/resources/org/jboss/dna/connector/filesystem/FileSystemI18n.properties 2009-12-29 04:25:02 UTC (rev 1484)
@@ -34,9 +34,9 @@
pathForWorkspaceRootCannotBeRead = The path "{0}" for the predefined workspace for the file system source "{1}" cannot be read
propertyIsRequired = The {0} property is required but has no value
locationInRequestMustHavePath = {0} requires a path in the request: {1}
-sameNameSiblingsAreNotAllowed = {0} does not allow same name siblings on nodes: {1}
+sameNameSiblingsAreNotAllowed = Repository source "{0}" does not allow same name siblings on nodes: {1}
nodeOrderingNotSupported = {0} does not support node ordering
-onlyTheDefaultNamespaceIsAllowed = {0} requires node names use the default namespace: {1}
+onlyTheDefaultNamespaceIsAllowed = Repository source "{0}" requires that node names use the default namespace
sourceIsReadOnly = The source "{0}" does not allow updates. Set the "updatesAllowed" property to "true" on the repository source (connector) to enable updates.
pathIsReadOnly = The path "{0}" in workspace "{1}" in {2} cannot be written to. See java.io.File\#canWrite().
errorSerializingCustomPropertiesFactory = Error serializing a {0} instance owned by the {1} FileSystemSource
@@ -50,6 +50,7 @@
invalidNameForResource = Invalid node name "{3}" for node at path "{0}" in workspace "{1}" in {2}. The name of nodes with primary type nt:resource or dna:resource must be "jcr:content".
invalidPathForResource = Invalid parent type for node at path "{0}" in workspace "{1}" in {2}. The parent node for nodes with primary type nt:resource or dna:resource must be of type nt:file.
invalidPropertyNames = Attempt to set or update invalid property names: {0}
+couldNotReadData = Error reading data from path "{2}" in workspace "{1}" in repository source "{0}"
couldNotWriteData = Error writing data to path "{0}" in workspace "{1}" in {2}\: {3}
couldNotUpdateData = Error moving temporary data file to path "{0}" in workspace "{1}" in {2}
missingRequiredProperty = Missing required property "{3}" at path "{0}" in workspace "{1}" in {2}
Modified: trunk/extensions/dna-connector-filesystem/src/test/java/org/jboss/dna/connector/filesystem/FileSystemSourceTest.java
===================================================================
--- trunk/extensions/dna-connector-filesystem/src/test/java/org/jboss/dna/connector/filesystem/FileSystemSourceTest.java 2009-12-27 20:45:58 UTC (rev 1483)
+++ trunk/extensions/dna-connector-filesystem/src/test/java/org/jboss/dna/connector/filesystem/FileSystemSourceTest.java 2009-12-29 04:25:02 UTC (rev 1484)
@@ -29,8 +29,13 @@
import static org.junit.Assert.assertThat;
import java.util.ArrayList;
import java.util.List;
+import org.jboss.dna.graph.ExecutionContext;
+import org.jboss.dna.graph.Subgraph;
import org.jboss.dna.graph.connector.RepositoryConnection;
+import org.jboss.dna.graph.connector.RepositoryConnectionFactory;
+import org.jboss.dna.graph.connector.RepositoryContext;
import org.jboss.dna.graph.connector.RepositorySourceException;
+import org.jboss.dna.graph.observe.Observer;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -45,9 +50,41 @@
@Before
public void beforeEach() throws Exception {
+ final ExecutionContext context = new ExecutionContext();
this.source = new FileSystemSource();
// Set the mandatory properties ...
this.source.setName("Test Repository");
+ this.source.initialize(new RepositoryContext() {
+
+ @Override
+ public Subgraph getConfiguration( int depth ) {
+ return null;
+ }
+
+ @Override
+ public ExecutionContext getExecutionContext() {
+ return context;
+ }
+
+ @Override
+ public Observer getObserver() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public RepositoryConnectionFactory getRepositoryConnectionFactory() {
+ return new RepositoryConnectionFactory() {
+
+ @Override
+ public RepositoryConnection createConnection( String sourceName ) throws RepositorySourceException {
+ return source.getConnection();
+ }
+
+ };
+ }
+
+ });
}
@After
Modified: trunk/extensions/dna-connector-jdbc-metadata/src/main/java/org/jboss/dna/connector/meta/jdbc/JdbcMetadataI18n.java
===================================================================
--- trunk/extensions/dna-connector-jdbc-metadata/src/main/java/org/jboss/dna/connector/meta/jdbc/JdbcMetadataI18n.java 2009-12-27 20:45:58 UTC (rev 1483)
+++ trunk/extensions/dna-connector-jdbc-metadata/src/main/java/org/jboss/dna/connector/meta/jdbc/JdbcMetadataI18n.java 2009-12-29 04:25:02 UTC (rev 1484)
@@ -36,6 +36,8 @@
public static I18n errorClosingConnection;
public static I18n errorObtainingConnection;
+ public static I18n sourceIsReadOnly;
+
public static I18n couldNotGetDatabaseMetadata;
public static I18n couldNotGetCatalogNames;
public static I18n couldNotGetSchemaNames;
Modified: trunk/extensions/dna-connector-jdbc-metadata/src/main/java/org/jboss/dna/connector/meta/jdbc/JdbcMetadataRepository.java
===================================================================
--- trunk/extensions/dna-connector-jdbc-metadata/src/main/java/org/jboss/dna/connector/meta/jdbc/JdbcMetadataRepository.java 2009-12-27 20:45:58 UTC (rev 1483)
+++ trunk/extensions/dna-connector-jdbc-metadata/src/main/java/org/jboss/dna/connector/meta/jdbc/JdbcMetadataRepository.java 2009-12-29 04:25:02 UTC (rev 1484)
@@ -35,6 +35,7 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.UUID;
import net.jcip.annotations.ThreadSafe;
import org.jboss.dna.common.util.Logger;
import org.jboss.dna.graph.DnaLexicon;
@@ -260,7 +261,7 @@
properties.put(JcrLexicon.PRIMARY_TYPE, propFactory.create(JcrLexicon.PRIMARY_TYPE, JcrNtLexicon.UNSTRUCTURED));
properties.put(JcrLexicon.MIXIN_TYPES, propFactory.create(JcrLexicon.MIXIN_TYPES, JdbcMetadataLexicon.CATALOG));
- return new DefaultPathNode(nodePath, properties, schemaNames);
+ return new DefaultPathNode(nodePath, null, properties, schemaNames);
} catch (JdbcMetadataException se) {
throw new RepositorySourceException(JdbcMetadataI18n.couldNotGetSchemaNames.text(catalogName), se);
} finally {
@@ -307,7 +308,7 @@
Segment[] children = new Segment[] {pathFactory.createSegment(TABLES_SEGMENT_NAME),
pathFactory.createSegment(PROCEDURES_SEGMENT_NAME)};
- return new DefaultPathNode(nodePath, properties, Arrays.asList(children));
+ return new DefaultPathNode(nodePath, null, properties, Arrays.asList(children));
} catch (JdbcMetadataException se) {
throw new RepositorySourceException(JdbcMetadataI18n.couldNotGetSchemaNames.text(catalogName), se);
} finally {
@@ -359,7 +360,7 @@
children.add(pathFactory.createSegment(table.getName()));
}
- return new DefaultPathNode(nodePath, properties, children);
+ return new DefaultPathNode(nodePath, null, properties, children);
} catch (JdbcMetadataException se) {
throw new RepositorySourceException(JdbcMetadataI18n.couldNotGetTableNames.text(catalogName, schemaName), se);
} finally {
@@ -442,7 +443,7 @@
children.add(pathFactory.createSegment(column.getName()));
}
- return new DefaultPathNode(nodePath, properties, children);
+ return new DefaultPathNode(nodePath, null, properties, children);
} catch (JdbcMetadataException se) {
throw new RepositorySourceException(JdbcMetadataI18n.couldNotGetTable.text(catalogName, schemaName, tableName),
se);
@@ -495,7 +496,7 @@
children.add(pathFactory.createSegment(procedure.getName()));
}
- return new DefaultPathNode(nodePath, properties, children);
+ return new DefaultPathNode(nodePath, null, properties, children);
} catch (JdbcMetadataException se) {
throw new RepositorySourceException(JdbcMetadataI18n.couldNotGetProcedureNames.text(catalogName, schemaName), se);
} finally {
@@ -562,7 +563,7 @@
propName = JdbcMetadataLexicon.PROCEDURE_RETURN_TYPE;
properties.put(propName, propFactory.create(propName, procedure.getType()));
- return new DefaultPathNode(nodePath, properties, Collections.<Segment>emptyList());
+ return new DefaultPathNode(nodePath, null, properties, Collections.<Segment>emptyList());
} catch (JdbcMetadataException se) {
throw new RepositorySourceException(JdbcMetadataI18n.couldNotGetProcedure.text(catalogName,
schemaName,
@@ -656,7 +657,7 @@
propName = JdbcMetadataLexicon.SOURCE_JDBC_DATA_TYPE;
properties.put(propName, propFactory.create(propName, column.getSourceJdbcDataType()));
}
- return new DefaultPathNode(nodePath, properties, Collections.<Segment>emptyList());
+ return new DefaultPathNode(nodePath, null, properties, Collections.<Segment>emptyList());
} catch (JdbcMetadataException se) {
throw new RepositorySourceException(JdbcMetadataI18n.couldNotGetColumn.text(catalogName,
schemaName,
@@ -757,6 +758,10 @@
return context.getValueFactories().getPathFactory().createRootPath();
}
+ public UUID getUuid() {
+ return source.getRootUuid();
+ }
+
public Map<Name, Property> getProperties() {
return rootNodeProperties;
}
Modified: trunk/extensions/dna-connector-jdbc-metadata/src/main/java/org/jboss/dna/connector/meta/jdbc/JdbcMetadataSource.java
===================================================================
--- trunk/extensions/dna-connector-jdbc-metadata/src/main/java/org/jboss/dna/connector/meta/jdbc/JdbcMetadataSource.java 2009-12-27 20:45:58 UTC (rev 1483)
+++ trunk/extensions/dna-connector-jdbc-metadata/src/main/java/org/jboss/dna/connector/meta/jdbc/JdbcMetadataSource.java 2009-12-29 04:25:02 UTC (rev 1484)
@@ -752,4 +752,23 @@
return metadataCollector;
}
+ public boolean areUpdatesAllowed() {
+ return false;
+ }
+
+ /**
+ * In-memory connectors aren't shared and cannot be loaded from external sources if updates are not allowed. Therefore, in
+ * order to avoid setting up an in-memory connector that is permanently empty (presumably, not a desired outcome), all
+ * in-memory connectors must allow updates.
+ *
+ * @param updatesAllowed must be true
+ * @throws RepositorySourceException if {@code updatesAllowed != true}.
+ */
+ public void setUpdatesAllowed( boolean updatesAllowed ) {
+ if (updatesAllowed == false) {
+ throw new RepositorySourceException(JdbcMetadataI18n.sourceIsReadOnly.text(this.name));
+ }
+
+ }
+
}
Modified: trunk/extensions/dna-connector-jdbc-metadata/src/main/resources/org/jboss/dna/connector/meta/jdbc/JdbcMetadataI18n.properties
===================================================================
--- trunk/extensions/dna-connector-jdbc-metadata/src/main/resources/org/jboss/dna/connector/meta/jdbc/JdbcMetadataI18n.properties 2009-12-27 20:45:58 UTC (rev 1483)
+++ trunk/extensions/dna-connector-jdbc-metadata/src/main/resources/org/jboss/dna/connector/meta/jdbc/JdbcMetadataI18n.properties 2009-12-29 04:25:02 UTC (rev 1484)
@@ -25,6 +25,8 @@
errorClosingConnection = Error closing SQL connection
errorObtainingConnection = Error obtaining SQL connection
+sourceIsReadOnly = The JDBC Metadata source "{0}" is read-only and cannot be changed to allow updates
+
couldNotGetDatabaseMetadata = Could not obtain database-level metadata
couldNotGetCatalogNames = Could not obtain catalog names for database
couldNotGetSchemaNames = Could not obtain schema names for catalog "{0}"
14 years, 4 months
DNA SVN: r1483 - trunk/dna-repository/src/main/java/org/jboss/dna/repository/sequencer.
by dna-commits@lists.jboss.org
Author: bcarothers
Date: 2009-12-27 15:45:58 -0500 (Sun, 27 Dec 2009)
New Revision: 1483
Modified:
trunk/dna-repository/src/main/java/org/jboss/dna/repository/sequencer/StreamSequencerAdapter.java
Log:
DNA-602 Can't Set Multi-Valued Property from Object[] through StreamSequencerAdapter
Applied patch that checks for Object[] and forces the correct cast in StreamSequencerAdapter.
Modified: trunk/dna-repository/src/main/java/org/jboss/dna/repository/sequencer/StreamSequencerAdapter.java
===================================================================
--- trunk/dna-repository/src/main/java/org/jboss/dna/repository/sequencer/StreamSequencerAdapter.java 2009-12-27 13:47:57 UTC (rev 1482)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/repository/sequencer/StreamSequencerAdapter.java 2009-12-27 20:45:58 UTC (rev 1483)
@@ -251,7 +251,12 @@
List<Property> properties = new LinkedList<Property>();
// Set all of the properties on this
for (SequencerOutputMap.PropertyValue property : entry.getPropertyValues()) {
- properties.add(propertyFactory.create(property.getName(), property.getValue()));
+ if (property.getValue() instanceof Object[]) {
+ // Have to force this cast or a single-valued property gets created with a value that is an Object[]
+ properties.add(propertyFactory.create(property.getName(), (Object[])property.getValue()));
+ } else {
+ properties.add(propertyFactory.create(property.getName(), property.getValue()));
+ }
// TODO: Handle reference properties - currently passed in as Paths
}
14 years, 4 months
DNA SVN: r1482 - trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory.
by dna-commits@lists.jboss.org
Author: bcarothers
Date: 2009-12-27 08:47:57 -0500 (Sun, 27 Dec 2009)
New Revision: 1482
Modified:
trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory/InMemoryRepositorySource.java
Log:
DNA-578 JPA Connector Simple Model Does Not Support "supportsUpdates" Property
Usual removal of @Override tag to correct usual JDK5 compilation issue
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory/InMemoryRepositorySource.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory/InMemoryRepositorySource.java 2009-12-27 03:18:45 UTC (rev 1481)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory/InMemoryRepositorySource.java 2009-12-27 13:47:57 UTC (rev 1482)
@@ -367,7 +367,6 @@
return CAPABILITIES;
}
- @Override
public boolean areUpdatesAllowed() {
return true;
}
@@ -380,7 +379,6 @@
* @param updatesAllowed must be true
* @throws RepositorySourceException if {@code updatesAllowed != true}.
*/
- @Override
public void setUpdatesAllowed( boolean updatesAllowed ) {
if (updatesAllowed == false) {
throw new RepositorySourceException(GraphI18n.inMemoryConnectorMustAllowUpdates.text(this.name));
14 years, 4 months
DNA SVN: r1481 - in trunk: dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory and 8 other directories.
by dna-commits@lists.jboss.org
Author: bcarothers
Date: 2009-12-26 22:18:45 -0500 (Sat, 26 Dec 2009)
New Revision: 1481
Added:
trunk/extensions/dna-connector-store-jpa/src/test/java/org/jboss/dna/connector/store/jpa/model/simple/SimpleJpaConnectorNotWritableTest.java
Modified:
trunk/dna-graph/src/main/java/org/jboss/dna/graph/GraphI18n.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory/InMemoryRepositorySource.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/map/MapRepositoryConnection.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/map/MapRepositorySource.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/map/MapRequestProcessor.java
trunk/dna-graph/src/main/resources/org/jboss/dna/graph/GraphI18n.properties
trunk/docs/reference/src/main/docbook/en-US/content/connectors/infinispan.xml
trunk/docs/reference/src/main/docbook/en-US/content/connectors/jboss_cache.xml
trunk/docs/reference/src/main/docbook/en-US/content/connectors/jdbc_storage.xml
trunk/extensions/dna-connector-infinispan/src/main/java/org/jboss/dna/connector/infinispan/InfinispanSource.java
trunk/extensions/dna-connector-jbosscache/src/main/java/org/jboss/dna/connector/jbosscache/JBossCacheSource.java
trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/JpaSource.java
trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/model/simple/SimpleJpaConnection.java
trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/model/simple/SimpleRequestProcessor.java
Log:
DNA-578 JPA Connector Simple Model Does Not Support "supportsUpdates" Property
Applied patch that requires support for "allowsUpdates" property in MapRepositorySource implementations and adds a default implementation in MapRequestProcessor. The patch also adds the property to the Infinispan and JBoss Cache connectors and the simple model in the JPA connector. Finally, the patch adds a test case for the JPA source and updates the documentation accordingly.
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/GraphI18n.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/GraphI18n.java 2009-12-23 02:21:59 UTC (rev 1480)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/GraphI18n.java 2009-12-27 03:18:45 UTC (rev 1481)
@@ -99,9 +99,11 @@
public static I18n nodeDoesNotExist;
public static I18n errorSerializingInMemoryCachePolicyInSource;
public static I18n inMemoryConnectorRequestsMustHavePathOrUuid;
+ public static I18n inMemoryConnectorMustAllowUpdates;
public static I18n pathConnectorRequestsMustHavePath;
public static I18n workspaceDoesNotExistInRepository;
public static I18n workspaceAlreadyExistsInRepository;
+ public static I18n sourceIsReadOnly;
/* Federation Connection */
public static I18n namePropertyIsRequiredForFederatedRepositorySource;
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory/InMemoryRepositorySource.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory/InMemoryRepositorySource.java 2009-12-23 02:21:59 UTC (rev 1480)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory/InMemoryRepositorySource.java 2009-12-27 03:18:45 UTC (rev 1481)
@@ -367,7 +367,28 @@
return CAPABILITIES;
}
+ @Override
+ public boolean areUpdatesAllowed() {
+ return true;
+ }
+
/**
+ * In-memory connectors aren't shared and cannot be loaded from external sources if updates are not allowed. Therefore, in
+ * order to avoid setting up an in-memory connector that is permanently empty (presumably, not a desired outcome), all
+ * in-memory connectors must allow updates.
+ *
+ * @param updatesAllowed must be true
+ * @throws RepositorySourceException if {@code updatesAllowed != true}.
+ */
+ @Override
+ public void setUpdatesAllowed( boolean updatesAllowed ) {
+ if (updatesAllowed == false) {
+ throw new RepositorySourceException(GraphI18n.inMemoryConnectorMustAllowUpdates.text(this.name));
+ }
+
+ }
+
+ /**
* {@inheritDoc}
*
* @see java.lang.Object#toString()
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/map/MapRepositoryConnection.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/map/MapRepositoryConnection.java 2009-12-23 02:21:59 UTC (rev 1480)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/map/MapRepositoryConnection.java 2009-12-27 03:18:45 UTC (rev 1481)
@@ -104,7 +104,7 @@
// Do any commands update/write?
RepositoryContext repositoryContext = this.source.getRepositoryContext();
Observer observer = repositoryContext != null ? repositoryContext.getObserver() : null;
- RequestProcessor processor = new MapRequestProcessor(context, this.repository, observer);
+ RequestProcessor processor = new MapRequestProcessor(context, this.repository, observer, source.areUpdatesAllowed());
boolean commit = true;
MapRepositoryTransaction txn = repository.startTransaction(request.isReadOnly());
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/map/MapRepositorySource.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/map/MapRepositorySource.java 2009-12-23 02:21:59 UTC (rev 1480)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/map/MapRepositorySource.java 2009-12-27 03:18:45 UTC (rev 1481)
@@ -34,13 +34,32 @@
public interface MapRepositorySource extends RepositorySource {
/**
- * Returns the {@link CachePolicy cache policy} for the repository source
+ * Get whether this source allows updates.
+ *
+ * @return true if this source allows updates by clients, or false if no updates are allowed
+ * @see #setUpdatesAllowed(boolean)
+ */
+ boolean areUpdatesAllowed();
+
+ /**
+ * Set whether this source allows updates to data within workspaces
+ *
+ * @param updatesAllowed true if this source allows updates to data within workspaces clients, or false if updates are not
+ * allowed.
+ * @see #areUpdatesAllowed()
+ */
+ void setUpdatesAllowed( boolean updatesAllowed );
+
+ /**
+ * Returns the {@link CachePolicy cache policy} for the repository source
+ *
* @return the {@link CachePolicy cache policy} for the repository source
*/
CachePolicy getDefaultCachePolicy();
/**
* Returns the {@link RepositoryContext repository context} for the repository source
+ *
* @return the {@link RepositoryContext repository context} for the repository source
*/
RepositoryContext getRepositoryContext();
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/map/MapRequestProcessor.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/map/MapRequestProcessor.java 2009-12-23 02:21:59 UTC (rev 1480)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/map/MapRequestProcessor.java 2009-12-27 03:18:45 UTC (rev 1481)
@@ -57,6 +57,7 @@
import org.jboss.dna.graph.request.DestroyWorkspaceRequest;
import org.jboss.dna.graph.request.FullTextSearchRequest;
import org.jboss.dna.graph.request.GetWorkspacesRequest;
+import org.jboss.dna.graph.request.InvalidRequestException;
import org.jboss.dna.graph.request.InvalidWorkspaceException;
import org.jboss.dna.graph.request.LockBranchRequest;
import org.jboss.dna.graph.request.MoveBranchRequest;
@@ -75,14 +76,17 @@
private final PathFactory pathFactory;
private final PropertyFactory propertyFactory;
private final MapRepository repository;
+ private final boolean updatesAllowed;
public MapRequestProcessor( ExecutionContext context,
MapRepository repository,
- Observer observer ) {
+ Observer observer,
+ boolean updatesAllowed ) {
super(repository.getSourceName(), context, observer);
this.repository = repository;
pathFactory = context.getValueFactories().getPathFactory();
propertyFactory = context.getPropertyFactory();
+ this.updatesAllowed = updatesAllowed;
}
/**
@@ -156,6 +160,8 @@
*/
@Override
public void process( CloneBranchRequest request ) {
+ if (!updatesAllowed(request)) return;
+
MapWorkspace workspace = getWorkspace(request, request.fromWorkspace());
MapWorkspace newWorkspace = getWorkspace(request, request.intoWorkspace());
if (workspace == null || newWorkspace == null) return;
@@ -189,6 +195,8 @@
*/
@Override
public void process( CopyBranchRequest request ) {
+ if (!updatesAllowed(request)) return;
+
MapWorkspace workspace = getWorkspace(request, request.fromWorkspace());
MapWorkspace newWorkspace = getWorkspace(request, request.intoWorkspace());
if (workspace == null || newWorkspace == null) return;
@@ -214,6 +222,8 @@
*/
@Override
public void process( CreateNodeRequest request ) {
+ if (!updatesAllowed(request)) return;
+
MapWorkspace workspace = getWorkspace(request, request.inWorkspace());
if (workspace == null) return;
Path parent = request.under().getPath();
@@ -224,8 +234,7 @@
MapNode parentNode = workspace.getNode(parent);
if (parentNode == null) {
Path lowestExisting = workspace.getLowestExistingPath(parent);
- request.setError(new PathNotFoundException(request.under(), lowestExisting,
- GraphI18n.nodeDoesNotExist.text(parent)));
+ request.setError(new PathNotFoundException(request.under(), lowestExisting, GraphI18n.nodeDoesNotExist.text(parent)));
return;
}
@@ -286,6 +295,8 @@
*/
@Override
public void process( DeleteBranchRequest request ) {
+ if (!updatesAllowed(request)) return;
+
MapWorkspace workspace = getWorkspace(request, request.inWorkspace());
if (workspace == null) return;
MapNode node = getTargetNode(workspace, request, request.at());
@@ -303,6 +314,8 @@
*/
@Override
public void process( MoveBranchRequest request ) {
+ if (!updatesAllowed(request)) return;
+
MapWorkspace workspace = getWorkspace(request, request.inWorkspace());
if (workspace == null) return;
@@ -352,6 +365,8 @@
*/
@Override
public void process( UpdatePropertiesRequest request ) {
+ if (!updatesAllowed(request)) return;
+
MapWorkspace workspace = getWorkspace(request, request.inWorkspace());
MapNode node = getTargetNode(workspace, request, request.on());
if (node == null) return;
@@ -383,6 +398,8 @@
*/
@Override
public void process( CreateWorkspaceRequest request ) {
+ if (!updatesAllowed(request)) return;
+
MapWorkspace workspace = repository.createWorkspace(getExecutionContext(),
request.desiredNameOfNewWorkspace(),
request.conflictBehavior());
@@ -405,6 +422,8 @@
*/
@Override
public void process( DestroyWorkspaceRequest request ) {
+ if (!updatesAllowed(request)) return;
+
MapWorkspace workspace = repository.getWorkspace(request.workspaceName());
if (workspace != null) {
MapNode root = workspace.getRoot();
@@ -450,6 +469,8 @@
*/
@Override
public void process( CloneWorkspaceRequest request ) {
+ if (!updatesAllowed(request)) return;
+
// Find the original workspace that we're cloning ...
final ExecutionContext context = getExecutionContext();
String targetWorkspaceName = request.desiredNameOfTargetWorkspace();
@@ -561,6 +582,13 @@
return workspace;
}
+ protected boolean updatesAllowed( Request request ) {
+ if (!updatesAllowed) {
+ request.setError(new InvalidRequestException(GraphI18n.sourceIsReadOnly.text(getSourceName())));
+ }
+ return !request.hasError();
+ }
+
protected MapNode getTargetNode( MapWorkspace workspace,
Request request,
Location location ) {
Modified: trunk/dna-graph/src/main/resources/org/jboss/dna/graph/GraphI18n.properties
===================================================================
--- trunk/dna-graph/src/main/resources/org/jboss/dna/graph/GraphI18n.properties 2009-12-23 02:21:59 UTC (rev 1480)
+++ trunk/dna-graph/src/main/resources/org/jboss/dna/graph/GraphI18n.properties 2009-12-27 03:18:45 UTC (rev 1481)
@@ -87,9 +87,11 @@
nodeDoesNotExist = Could not find an existing node at {0}
errorSerializingInMemoryCachePolicyInSource = Error serializing a {0} instance owned by the {1} in-memory repository
inMemoryConnectorRequestsMustHavePathOrUuid = In-Memory connector can only process requests with a path and/or UUID
+inMemoryConnectorMustAllowUpdates = In-Memory connector "{0}" must allow updates.
pathConnectorRequestsMustHavePath = Path connectors can only process requests with a path
workspaceDoesNotExistInRepository = The workspace "{0}" does not exist in the "{1}" in-memory repository
workspaceAlreadyExistsInRepository = The workspace "{0}" already exists in the "{1}" in-memory repository
+sourceIsReadOnly = The repository source "{0}" does not allow updates. Set the "updatesAllowed" property to "true" on the repository source to allow updates.
# Federation connector
namePropertyIsRequiredForFederatedRepositorySource = The "{0}" property is required on each federated repository source
Modified: trunk/docs/reference/src/main/docbook/en-US/content/connectors/infinispan.xml
===================================================================
--- trunk/docs/reference/src/main/docbook/en-US/content/connectors/infinispan.xml 2009-12-23 02:21:59 UTC (rev 1480)
+++ trunk/docs/reference/src/main/docbook/en-US/content/connectors/infinispan.xml 2009-12-27 03:18:45 UTC (rev 1481)
@@ -91,6 +91,11 @@
<entry>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 random UUID is generated each time that the repository is started.</entry>
</row>
+ <row>
+ <entry>updatesAllowed</entry>
+ <entry>Determines whether the content in the connector is can be updated ("true"), or if the content may only be read ("false").
+ The default value is "true".</entry>
+ </row>
</tbody>
</tgroup>
</table>
Modified: trunk/docs/reference/src/main/docbook/en-US/content/connectors/jboss_cache.xml
===================================================================
--- trunk/docs/reference/src/main/docbook/en-US/content/connectors/jboss_cache.xml 2009-12-23 02:21:59 UTC (rev 1480)
+++ trunk/docs/reference/src/main/docbook/en-US/content/connectors/jboss_cache.xml 2009-12-27 03:18:45 UTC (rev 1481)
@@ -106,6 +106,11 @@
<entry>Optional property that, if used, defines the property that should be used to find the UUID value for each node
in the cache. "<code>dna:uuid</code>" is the default.</entry>
</row>
+ <row>
+ <entry>updatesAllowed</entry>
+ <entry>Determines whether the content in the connector is can be updated ("true"), or if the content may only be read ("false").
+ The default value is "true".</entry>
+ </row>
</tbody>
</tgroup>
Modified: trunk/docs/reference/src/main/docbook/en-US/content/connectors/jdbc_storage.xml
===================================================================
--- trunk/docs/reference/src/main/docbook/en-US/content/connectors/jdbc_storage.xml 2009-12-23 02:21:59 UTC (rev 1480)
+++ trunk/docs/reference/src/main/docbook/en-US/content/connectors/jdbc_storage.xml 2009-12-27 03:18:45 UTC (rev 1481)
@@ -56,9 +56,9 @@
<entry>The name of the repository source, which is used by the &RepositoryService; when obtaining a &RepositoryConnection; by name.</entry>
</row>
<row>
- <entry>supportsUpdates (Basic Model Only)</entry>
+ <entry>updatesAllowed</entry>
<entry>Determines whether the content in the database is can be updated ("true"), or if the content may only be read ("false").
- The default value is "true". This property is ignored by the Simple Model (q.v., the model property below)</entry>
+ The default value is "true".</entry>
</row>
<row>
<entry>rootNodeUuid</entry>
@@ -204,7 +204,7 @@
<entry>model</entry>
<entry>
An advanced property that dictates the type of storage schema that is used. Currently, the only supported values are "Basic" and "Simple".
- The Basic model supports a read-only mode (q.v., the "supportsUpdates" property) and database-level
+ The Basic model supports a read-only mode (q.v., the "updatesAllowed" property) and database-level
enforcement of referential integrity (q.v., the "referentialIntegrityEnforced" property above), but does not fully support all JCR functions.
As a result, the Simple model is now the default model, but DNA repositories that were created under the Basic model will continue to use
the "Basic" model regardless of the value of this property. Repositories can be converted from the Basic model to the Simple model by exporting
Modified: trunk/extensions/dna-connector-infinispan/src/main/java/org/jboss/dna/connector/infinispan/InfinispanSource.java
===================================================================
--- trunk/extensions/dna-connector-infinispan/src/main/java/org/jboss/dna/connector/infinispan/InfinispanSource.java 2009-12-23 02:21:59 UTC (rev 1480)
+++ trunk/extensions/dna-connector-infinispan/src/main/java/org/jboss/dna/connector/infinispan/InfinispanSource.java 2009-12-27 03:18:45 UTC (rev 1481)
@@ -88,6 +88,11 @@
*/
public static final String DEFAULT_NAME_OF_DEFAULT_WORKSPACE = "default";
+ /**
+ * The initial value for whether updates are allowed is "{@value} ", unless otherwise specified.
+ */
+ public static final boolean DEFAULT_UPDATES_ALLOWED = true;
+
protected static final String ROOT_NODE_UUID = "rootNodeUuid";
protected static final String SOURCE_NAME = "sourceName";
protected static final String DEFAULT_CACHE_POLICY = "defaultCachePolicy";
@@ -97,6 +102,7 @@
protected static final String DEFAULT_WORKSPACE = "defaultWorkspace";
protected static final String PREDEFINED_WORKSPACE_NAMES = "predefinedWorkspaceNames";
protected static final String ALLOW_CREATING_WORKSPACES = "allowCreatingWorkspaces";
+ protected static final String UPDATES_ALLOWED = "updatesAllowed";
private volatile String name;
private volatile UUID rootNodeUuid = UUID.randomUUID();
@@ -105,6 +111,7 @@
private volatile String cacheManagerJndiName;
private volatile int retryLimit = DEFAULT_RETRY_LIMIT;
private volatile String defaultWorkspace;
+ private volatile boolean updatesAllowed = DEFAULT_UPDATES_ALLOWED;
private volatile String[] predefinedWorkspaces = new String[] {};
private volatile RepositorySourceCapabilities capabilities = new RepositorySourceCapabilities(true, true, false, true, false);
private transient InfinispanRepository repository;
@@ -448,6 +455,14 @@
this.jndiContext = context;
}
+ public boolean areUpdatesAllowed() {
+ return this.updatesAllowed;
+ }
+
+ public void setUpdatesAllowed( boolean updatesAllowed ) {
+ this.updatesAllowed = updatesAllowed;
+ }
+
/**
* {@inheritDoc}
*/
@@ -480,6 +495,7 @@
ref.add(new StringRefAddr(CACHE_CONFIGURATION_NAME, getCacheConfigurationName()));
ref.add(new StringRefAddr(RETRY_LIMIT, Integer.toString(getRetryLimit())));
ref.add(new StringRefAddr(DEFAULT_WORKSPACE, getDefaultWorkspaceName()));
+ ref.add(new StringRefAddr(UPDATES_ALLOWED, String.valueOf(areUpdatesAllowed())));
ref.add(new StringRefAddr(ALLOW_CREATING_WORKSPACES, Boolean.toString(isCreatingWorkspacesAllowed())));
String[] workspaceNames = getPredefinedWorkspaceNames();
if (workspaceNames != null && workspaceNames.length != 0) {
@@ -537,6 +553,7 @@
String retryLimit = (String)values.get(RETRY_LIMIT);
String defaultWorkspace = (String)values.get(DEFAULT_WORKSPACE);
String createWorkspaces = (String)values.get(ALLOW_CREATING_WORKSPACES);
+ String updatesAllowed = (String)values.get(UPDATES_ALLOWED);
String combinedWorkspaceNames = (String)values.get(PREDEFINED_WORKSPACE_NAMES);
String[] workspaceNames = null;
@@ -558,6 +575,7 @@
if (defaultWorkspace != null) source.setDefaultWorkspaceName(defaultWorkspace);
if (createWorkspaces != null) source.setCreatingWorkspacesAllowed(Boolean.parseBoolean(createWorkspaces));
if (workspaceNames != null && workspaceNames.length != 0) source.setPredefinedWorkspaceNames(workspaceNames);
+ if (updatesAllowed != null) source.setUpdatesAllowed(Boolean.valueOf(updatesAllowed));
return source;
}
return null;
Modified: trunk/extensions/dna-connector-jbosscache/src/main/java/org/jboss/dna/connector/jbosscache/JBossCacheSource.java
===================================================================
--- trunk/extensions/dna-connector-jbosscache/src/main/java/org/jboss/dna/connector/jbosscache/JBossCacheSource.java 2009-12-23 02:21:59 UTC (rev 1480)
+++ trunk/extensions/dna-connector-jbosscache/src/main/java/org/jboss/dna/connector/jbosscache/JBossCacheSource.java 2009-12-27 03:18:45 UTC (rev 1481)
@@ -97,6 +97,11 @@
*/
public static final String DEFAULT_NAME_OF_DEFAULT_WORKSPACE = "default";
+ /**
+ * The initial value for whether updates are allowed is "{@value} ", unless otherwise specified.
+ */
+ public static final boolean DEFAULT_UPDATES_ALLOWED = true;
+
protected static final String ROOT_NODE_UUID = "rootNodeUuid";
protected static final String SOURCE_NAME = "sourceName";
protected static final String DEFAULT_CACHE_POLICY = "defaultCachePolicy";
@@ -107,6 +112,7 @@
protected static final String DEFAULT_WORKSPACE = "defaultWorkspace";
protected static final String PREDEFINED_WORKSPACE_NAMES = "predefinedWorkspaceNames";
protected static final String ALLOW_CREATING_WORKSPACES = "allowCreatingWorkspaces";
+ protected static final String UPDATES_ALLOWED = "updatesAllowed";
private volatile String name;
private volatile UUID rootNodeUuid = UUID.randomUUID();
@@ -116,6 +122,7 @@
private volatile String cacheJndiName;
private volatile int retryLimit = DEFAULT_RETRY_LIMIT;
private volatile String defaultWorkspace;
+ private volatile boolean updatesAllowed = DEFAULT_UPDATES_ALLOWED;
private volatile String[] predefinedWorkspaces = new String[] {};
private volatile RepositorySourceCapabilities capabilities = new RepositorySourceCapabilities(true, true, false, true, false);
private transient JBossCacheRepository repository;
@@ -553,6 +560,14 @@
this.jndiContext = context;
}
+ public boolean areUpdatesAllowed() {
+ return this.updatesAllowed;
+ }
+
+ public void setUpdatesAllowed( boolean updatesAllowed ) {
+ this.updatesAllowed = updatesAllowed;
+ }
+
/**
* {@inheritDoc}
*/
@@ -586,6 +601,7 @@
ref.add(new StringRefAddr(CACHE_CONFIGURATION_NAME, getCacheConfigurationName()));
ref.add(new StringRefAddr(RETRY_LIMIT, Integer.toString(getRetryLimit())));
ref.add(new StringRefAddr(DEFAULT_WORKSPACE, getDefaultWorkspaceName()));
+ ref.add(new StringRefAddr(UPDATES_ALLOWED, String.valueOf(areUpdatesAllowed())));
ref.add(new StringRefAddr(ALLOW_CREATING_WORKSPACES, Boolean.toString(isCreatingWorkspacesAllowed())));
String[] workspaceNames = getPredefinedWorkspaceNames();
if (workspaceNames != null && workspaceNames.length != 0) {
@@ -644,6 +660,7 @@
String retryLimit = (String)values.get(RETRY_LIMIT);
String defaultWorkspace = (String)values.get(DEFAULT_WORKSPACE);
String createWorkspaces = (String)values.get(ALLOW_CREATING_WORKSPACES);
+ String updatesAllowed = (String)values.get(UPDATES_ALLOWED);
String combinedWorkspaceNames = (String)values.get(PREDEFINED_WORKSPACE_NAMES);
String[] workspaceNames = null;
@@ -666,6 +683,7 @@
if (defaultWorkspace != null) source.setDefaultWorkspaceName(defaultWorkspace);
if (createWorkspaces != null) source.setCreatingWorkspacesAllowed(Boolean.parseBoolean(createWorkspaces));
if (workspaceNames != null && workspaceNames.length != 0) source.setPredefinedWorkspaceNames(workspaceNames);
+ if (updatesAllowed != null) source.setUpdatesAllowed(Boolean.valueOf(updatesAllowed));
return source;
}
return null;
Modified: trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/JpaSource.java
===================================================================
--- trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/JpaSource.java 2009-12-23 02:21:59 UTC (rev 1480)
+++ trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/JpaSource.java 2009-12-27 03:18:45 UTC (rev 1481)
@@ -138,10 +138,10 @@
*/
protected static final boolean SUPPORTS_REFERENCES = true;
/**
- * This source supports udpates by default, but each instance may be configured to {@link #setSupportsUpdates(boolean) be
+ * This source supports updates by default, but each instance may be configured to {@link #setAllowsUpdates(boolean) be
* read-only or updateable}.
*/
- public static final boolean DEFAULT_SUPPORTS_UPDATES = true;
+ public static final boolean DEFAULT_ALLOWS_UPDATES = true;
/**
* This source does not output executed SQL by default, but this can be overridden by calling {@link #setShowSql(boolean)}.
*/
@@ -211,7 +211,7 @@
private volatile String[] predefinedWorkspaces = new String[] {};
private volatile RepositorySourceCapabilities capabilities = new RepositorySourceCapabilities(
SUPPORTS_SAME_NAME_SIBLINGS,
- DEFAULT_SUPPORTS_UPDATES,
+ DEFAULT_ALLOWS_UPDATES,
SUPPORTS_EVENTS,
DEFAULT_SUPPORTS_CREATING_WORKSPACES,
SUPPORTS_REFERENCES);
@@ -255,22 +255,21 @@
}
/**
- * Get whether this source supports updates.
+ * Get whether this source allows updates.
*
- * @return true if this source supports updates, or false if this source only supports reading content.
+ * @return true if this source allows updates, or false if this source only supports reading content.
*/
- public boolean getSupportsUpdates() {
+ public boolean areUpdatesAllowed() {
return capabilities.supportsUpdates();
}
/**
- * Set whether this source supports updates.
+ * Set whether this source allows updates.
*
- * @param supportsUpdates true if this source supports updating content, or false if this source only supports reading
- * content.
+ * @param allowsUpdates true if this source allows updating content, or false if this source only allows reading content.
*/
- public synchronized void setSupportsUpdates( boolean supportsUpdates ) {
- capabilities = new RepositorySourceCapabilities(capabilities.supportsSameNameSiblings(), supportsUpdates,
+ public synchronized void setAllowsUpdates( boolean allowsUpdates ) {
+ capabilities = new RepositorySourceCapabilities(capabilities.supportsSameNameSiblings(), allowsUpdates,
capabilities.supportsEvents(), capabilities.supportsCreatingWorkspaces(),
capabilities.supportsReferences());
}
Modified: trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/model/simple/SimpleJpaConnection.java
===================================================================
--- trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/model/simple/SimpleJpaConnection.java 2009-12-23 02:21:59 UTC (rev 1480)
+++ trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/model/simple/SimpleJpaConnection.java 2009-12-27 03:18:45 UTC (rev 1481)
@@ -103,7 +103,7 @@
}
// Do any commands update/write?
Observer observer = this.source.getRepositoryContext().getObserver();
- RequestProcessor processor = new SimpleRequestProcessor(context, this.repository, observer);
+ RequestProcessor processor = new SimpleRequestProcessor(context, this.repository, observer, source.areUpdatesAllowed());
boolean commit = true;
MapRepositoryTransaction txn = repository.startTransaction(request.isReadOnly());
Modified: trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/model/simple/SimpleRequestProcessor.java
===================================================================
--- trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/model/simple/SimpleRequestProcessor.java 2009-12-23 02:21:59 UTC (rev 1480)
+++ trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/model/simple/SimpleRequestProcessor.java 2009-12-27 03:18:45 UTC (rev 1481)
@@ -31,8 +31,9 @@
public SimpleRequestProcessor( ExecutionContext context,
SimpleJpaRepository repository,
- Observer observer ) {
- super(context, repository, observer);
+ Observer observer,
+ boolean updatesAllowed ) {
+ super(context, repository, observer, updatesAllowed);
this.repository = repository;
this.pathFactory = context.getValueFactories().getPathFactory();
@@ -126,6 +127,8 @@
@Override
public void process( CreateWorkspaceRequest request ) {
+ if (!updatesAllowed(request)) return;
+
if (!repository.creatingWorkspacesAllowed()) {
String msg = JpaConnectorI18n.unableToCreateWorkspaces.text(getSourceName());
request.setError(new InvalidRequestException(msg));
@@ -137,6 +140,8 @@
@Override
public void process( CloneWorkspaceRequest request ) {
+ if (!updatesAllowed(request)) return;
+
if (!repository.creatingWorkspacesAllowed()) {
String msg = JpaConnectorI18n.unableToCreateWorkspaces.text(getSourceName());
request.setError(new InvalidRequestException(msg));
Added: trunk/extensions/dna-connector-store-jpa/src/test/java/org/jboss/dna/connector/store/jpa/model/simple/SimpleJpaConnectorNotWritableTest.java
===================================================================
--- trunk/extensions/dna-connector-store-jpa/src/test/java/org/jboss/dna/connector/store/jpa/model/simple/SimpleJpaConnectorNotWritableTest.java (rev 0)
+++ trunk/extensions/dna-connector-store-jpa/src/test/java/org/jboss/dna/connector/store/jpa/model/simple/SimpleJpaConnectorNotWritableTest.java 2009-12-27 03:18:45 UTC (rev 1481)
@@ -0,0 +1,67 @@
+package org.jboss.dna.connector.store.jpa.model.simple;
+
+/*
+ * JBoss DNA (http://www.jboss.org/dna)
+ * 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.
+ *
+ * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
+ * 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.
+ *
+ * JBoss DNA 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 software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+
+import org.jboss.dna.connector.store.jpa.JpaSource;
+import org.jboss.dna.connector.store.jpa.TestEnvironment;
+import org.jboss.dna.graph.Graph;
+import org.jboss.dna.graph.connector.RepositorySource;
+import org.jboss.dna.graph.connector.test.NotWritableConnectorTest;
+
+public class SimpleJpaConnectorNotWritableTest extends NotWritableConnectorTest {
+
+ private JpaSource source;
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.graph.connector.test.AbstractConnectorTest#setUpSource()
+ */
+ @Override
+ protected RepositorySource setUpSource() {
+ // Set the connection properties using the environment defined in the POM files ...
+ source = TestEnvironment.configureJpaSource("Test Repository", this);
+ source.setModel(JpaSource.Models.SIMPLE.getName());
+
+ // Override the inherited properties ...
+ source.setCompressData(true);
+
+ return source;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.graph.connector.test.AbstractConnectorTest#initializeContent(org.jboss.dna.graph.Graph)
+ */
+ @Override
+ protected void initializeContent( Graph graph ) {
+ graph.create("/testNode").and();
+
+ source.setAllowsUpdates(false);
+
+ }
+
+}
Property changes on: trunk/extensions/dna-connector-store-jpa/src/test/java/org/jboss/dna/connector/store/jpa/model/simple/SimpleJpaConnectorNotWritableTest.java
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
14 years, 4 months
Hello, dna-commits!
by Kiley
Good Day...
I was wondering if you might like to chat with me?
I found your profile online and would like to get to know you better.
Please email me back Kiley(a)AceMailFast.com
14 years, 4 months