Author: bcarothers
Date: 2009-07-23 21:15:00 -0400 (Thu, 23 Jul 2009)
New Revision: 1126
Added:
trunk/dna-integration-tests/src/test/java/org/jboss/dna/test/integration/FileSystemRepositoryTckTest.java
trunk/dna-integration-tests/src/test/resources/tck/filesystem/
trunk/dna-integration-tests/src/test/resources/tck/filesystem/configRepository.xml
trunk/dna-integration-tests/src/test/resources/tck/filesystem/repositoryOverlay.properties
Modified:
trunk/dna-graph/src/main/java/org/jboss/dna/graph/DnaLexicon.java
trunk/dna-integration-tests/src/test/java/org/jboss/dna/test/integration/AbstractRepositoryTckTest.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/DnaLexicon.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrDocumentViewExporter.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrValue.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/SessionCache.java
trunk/dna-jcr/src/main/resources/org/jboss/dna/jcr/dna_builtins.cnd
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/DnaRepositoryStub.java
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/DnaTckTest.java
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrTckTest.java
trunk/dna-jcr/src/test/resources/security/tck_roles.properties
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/FileSystemI18n.java
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/FileSystemSource.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/FileSystemConnectorCreateWorkspacesTest.java
trunk/extensions/dna-connector-filesystem/src/test/java/org/jboss/dna/connector/filesystem/FileSystemConnectorNoCreateWorkspaceTest.java
trunk/extensions/dna-connector-filesystem/src/test/java/org/jboss/dna/connector/filesystem/FileSystemConnectorNotWritableTest.java
trunk/extensions/dna-connector-filesystem/src/test/java/org/jboss/dna/connector/filesystem/FileSystemConnectorReadableTest.java
Log:
DNA-476 Add integration test that uses the file system connector
Committed patch that implements a read-only TCK test based on a filesystem connector. This
patch implements a few changes as described below:
- Minor JCR bug fixes around UUID properties for connectors that don't support UUID
properties and binary handling in JcrValue and the document view exporter
- Minor tweaks to the TCK infrastructure code to support not importing test data into
read-only repositories and having a test suite of just the read-only tests
- Less-minor tweaks to the filesystem connector to support a new way of specifying
workspace names and locations as described in
http://www.jboss.org/index.html?module=bb&op=viewtopic&t=158928. This caused a
fair amount of code shuffling within the FS connector classes.
There's also a somewhat dubious change to the filesystem connector that causes the
root folder to be returned as type dna:root instead of nt:folder. This is necessary if the
root happens to be the root of a repository workspace, as it is in this test. This is not
appropriate under some projection scenarios (e.g. /foo => /). This merits some more
discussion and thought in the future.
It is also worth noting that our FS connector was modified to return a node with primary
type nt:file and a child node of type dna:resource for each file instead of
nt:file/nt:resource. We cannot support nt:resource from our FS connector because
nt:resource extends mix:referenceable. Instead, we use a node type that is identical to
nt:resource but without extending mix:referenceable.
[ Show ?\194?\187 ]
Brian Carothers - 23/Jul/09 09:12 PM Attached patch that implements a read-only TCK test
based on a filesystem connector. This patch implements a few changes as described below: -
Minor JCR bug fixes around UUID properties for connectors that don't support UUID
properties and binary handling in JcrValue and the document view exporter - Minor tweaks
to the TCK infrastructure code to support not importing test data into read-only
repositories and having a test suite of just the read-only tests - Less-minor tweaks to
the filesystem connector to support a new way of specifying workspace names and locations
as described in
http://www.jboss.org/index.html?module=bb&op=viewtopic&t=158928.
This caused a fair amount of code shuffling within the FS connector classes. There's
also a somewhat dubious change to the filesystem connector that causes the root folder to
be returned as type dna:root instead of nt:folder. This is necessary if the root happens
to be the root of a repository wor!
kspace, as it is in this test. This is not appropriate under some projection scenarios
(e.g. /foo => /). This merits some more discussion and thought in the future. It is
also worth noting that our FS connector was modified to return a node with primary type
nt:file and a child node of type dna:resource for each file instead of
nt:file/nt:resource. We cannot support nt:resource from our FS connector because
nt:resource extends mix:referenceable. Instead, we use a node type that is identical to
nt:resource but without extending mix:referenceable.
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/DnaLexicon.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/DnaLexicon.java 2009-07-22 22:41:00
UTC (rev 1125)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/DnaLexicon.java 2009-07-24 01:15:00
UTC (rev 1126)
@@ -43,6 +43,8 @@
public static final Name NAMESPACES = new BasicName(Namespace.URI,
"namespaces");
public static final Name PROJECTION_RULES = new BasicName(Namespace.URI,
"projectionRules");
public static final Name READ_ONLY = new BasicName(Namespace.URI,
"readOnly");
+ public static final Name RESOURCE = new BasicName(Namespace.URI,
"resource");
+ public static final Name ROOT = new BasicName(Namespace.URI, "root");
public static final Name TIME_TO_EXPIRE = new BasicName(Namespace.URI,
"timeToExpire");
public static final Name NAMESPACE_URI = new BasicName(Namespace.URI,
"uri");
Modified:
trunk/dna-integration-tests/src/test/java/org/jboss/dna/test/integration/AbstractRepositoryTckTest.java
===================================================================
---
trunk/dna-integration-tests/src/test/java/org/jboss/dna/test/integration/AbstractRepositoryTckTest.java 2009-07-22
22:41:00 UTC (rev 1125)
+++
trunk/dna-integration-tests/src/test/java/org/jboss/dna/test/integration/AbstractRepositoryTckTest.java 2009-07-24
01:15:00 UTC (rev 1126)
@@ -53,8 +53,8 @@
public static TestSuite readOnlyRepositorySuite( String name ) {
TestSuite suite = new TestSuite("Tests for " + name +
"(read-only)");
suite.addTest(new ChangeRepositoryTestCase(name));
- suite.addTest(JcrTckTest.suite());
- suite.addTestSuite(DnaTckTest.class);
+ suite.addTest(JcrTckTest.readOnlySuite());
+ suite.addTest(DnaTckTest.readOnlySuite());
return suite;
}
Added:
trunk/dna-integration-tests/src/test/java/org/jboss/dna/test/integration/FileSystemRepositoryTckTest.java
===================================================================
---
trunk/dna-integration-tests/src/test/java/org/jboss/dna/test/integration/FileSystemRepositoryTckTest.java
(rev 0)
+++
trunk/dna-integration-tests/src/test/java/org/jboss/dna/test/integration/FileSystemRepositoryTckTest.java 2009-07-24
01:15:00 UTC (rev 1126)
@@ -0,0 +1,33 @@
+/*
+ * 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.test.integration;
+
+import junit.framework.Test;
+
+public class FileSystemRepositoryTckTest {
+
+ public static Test suite() {
+ return
AbstractRepositoryTckTest.readOnlyRepositorySuite("filesystem");
+ }
+}
Property changes on:
trunk/dna-integration-tests/src/test/java/org/jboss/dna/test/integration/FileSystemRepositoryTckTest.java
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Added: trunk/dna-integration-tests/src/test/resources/tck/filesystem/configRepository.xml
===================================================================
--- trunk/dna-integration-tests/src/test/resources/tck/filesystem/configRepository.xml
(rev 0)
+++
trunk/dna-integration-tests/src/test/resources/tck/filesystem/configRepository.xml 2009-07-24
01:15:00 UTC (rev 1126)
@@ -0,0 +1,95 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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 distribution; if not, write to:
+ ~ Free Software Foundation, Inc.
+ ~ 51 Franklin Street, Fifth Floor
+ ~ Boston, MA 02110-1301 USA
+ -->
+<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 'JCR' repository is a file system source with a single, default
workspace (though others could be created, too).
+ In a production release, the dna:rootNodeUuid would be specified here as well to
ensure stability over restarts.
+ Since we don't specify a rootNodeUuid, a random UUID will be generated each
time that the corresponding test is run.
+ -->
+ <dna:source jcr:name="Store"
dna:classname="org.jboss.dna.connector.filesystem.FileSystemSource"
+ dna:workspaceRootPath="./src/test/resources/tck/filesystem"
+ dna:defaultWorkspaceName="defaultWorkspace"
+ dna:predefinedWorkspaceNames="otherWorkspace"
+ dna:creatingWorkspacesAllowed="false"
+ />
+ <!--
+ <dna:source jcr:name="Store"
dna:classname="org.jboss.dna.graph.connector.inmemory.InMemoryRepositorySource"
/>
+ -->
+ </dna:sources>
+ <!--
+ Define the mime type detectors. This is an optional section. By default, each engine
will use the
+ MIME type detector that uses filename extensions. So we wouldn't need to define
the same detector again,
+ but this is how you'd define another extension.
+ -->
+ <dna:mimeTypeDetectors>
+ <dna:mimeTypeDetector jcr:name="Detector">
+ <dna:description>Standard extension-based MIME type
detector</dna:description>
+ <!--
+ Specify the implementation class (required), as a child element or attribute
on parent element.
+ -->
+
<dna:classname>org.jboss.dna.graph.mimetype.ExtensionBasedMimeTypeDetector</dna:classname>
+ <!--
+ Specify the classpath (optional) as an ordered list of 'names', where
each name is significant to
+ the classpath factory. For example, a name could be an OSGI identifier or a
Maven coordinate,
+ depending upon the classpath factory being used. If there is only one
'name' in the classpath,
+ it may be specified as an attribute on the 'mimeTypeDetector'
element. If there is more than one
+ 'name', then they must be specified as child 'classpath'
elements. Blank or empty values are ignored.
+ -->
+ <dna:classpath></dna:classpath>
+ </dna:mimeTypeDetector>
+ </dna:mimeTypeDetectors>
+ <!--
+ Define the JCR repositories
+ -->
+ <dna:repositories>
+ <!--
+ Define a JCR repository that accesses the 'JCR' source directly.
+ This of course is optional, since we could access the same content through
'JCR'.
+ -->
+ <dna:repository jcr:name="Test Repository Source">
+ <!-- Specify the source that should be used for the repository -->
+ <dna:source>Store</dna:source>
+ <!-- Define the options for the JCR repository, using camelcase version of
JcrRepository.Option names
+-->
+ <dna:options jcr:primaryType="dna:options">
+ <jaasLoginConfigName jcr:primaryType="dna:option"
dna:value="dna-jcr"/>
+ <projectNodeTypes jcr:primaryType="dna:option"
dna:value="false"/>
+ </dna:options>
+ <!-- Define any namespaces for this repository, other than those already
defined by JCR or DNA
+-->
+ <namespaces jcr:primaryType="dna:namespaces">
+ <dnatest jcr:primaryType="dna:namespace"
dna:uri="http://jboss.org/dna/test/1.0"/>
+ </namespaces>
+ </dna:repository>
+ </dna:repositories>
+</configuration>
Property changes on:
trunk/dna-integration-tests/src/test/resources/tck/filesystem/configRepository.xml
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Added:
trunk/dna-integration-tests/src/test/resources/tck/filesystem/repositoryOverlay.properties
===================================================================
---
trunk/dna-integration-tests/src/test/resources/tck/filesystem/repositoryOverlay.properties
(rev 0)
+++
trunk/dna-integration-tests/src/test/resources/tck/filesystem/repositoryOverlay.properties 2009-07-24
01:15:00 UTC (rev 1126)
@@ -0,0 +1,8 @@
+# Placeholder for any overlaid properties for this repo configuration
+
+javax.jcr.tck.dnaSkipImport=true
+
+
+javax.jcr.tck.nodetype=nt\:file
+javax.jcr.tck.nodetype2=nt\:file
+
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/DnaLexicon.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/DnaLexicon.java 2009-07-22 22:41:00 UTC
(rev 1125)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/DnaLexicon.java 2009-07-24 01:15:00 UTC
(rev 1126)
@@ -35,7 +35,6 @@
public static final Name NAMESPACE = new BasicName(Namespace.URI,
"namespace");
public static final Name NODE_TYPES = new BasicName(Namespace.URI,
"nodeTypes");
public static final Name REPOSITORIES = new BasicName(Namespace.URI,
"repositories");
- public static final Name ROOT = new BasicName(Namespace.URI, "root");
public static final Name SYSTEM = new BasicName(Namespace.URI, "system");
public static final Name URI = new BasicName(Namespace.URI, "uri");
}
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrDocumentViewExporter.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrDocumentViewExporter.java 2009-07-22
22:41:00 UTC (rev 1125)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrDocumentViewExporter.java 2009-07-24
01:15:00 UTC (rev 1126)
@@ -23,6 +23,7 @@
*/
package org.jboss.dna.jcr;
+import java.io.IOException;
import java.io.OutputStream;
import java.text.CharacterIterator;
import java.text.StringCharacterIterator;
@@ -39,6 +40,7 @@
import net.jcip.annotations.NotThreadSafe;
import org.jboss.dna.common.text.TextEncoder;
import org.jboss.dna.common.text.XmlNameEncoder;
+import org.jboss.dna.common.util.Base64;
import org.jboss.dna.graph.ExecutionContext;
import org.jboss.dna.graph.property.Name;
import org.jboss.dna.graph.property.ValueFactories;
@@ -56,6 +58,8 @@
@NotThreadSafe
class JcrDocumentViewExporter extends AbstractJcrExporter {
+ private static final int ENCODE_BUFFER_SIZE = 2 << 15;
+
private static final TextEncoder VALUE_ENCODER = new
JcrDocumentViewExporter.JcrDocumentViewPropertyEncoder();
JcrDocumentViewExporter( JcrSession session ) {
@@ -99,14 +103,19 @@
while (properties.hasNext()) {
Property prop = properties.nextProperty();
+ Name propName = ((AbstractJcrProperty)prop).name();
+
+ String localPropName = getPrefixedName(propName);
+
if (skipBinary && PropertyType.BINARY == prop.getType()) {
+ atts.addAttribute(propName.getNamespaceUri(),
+ propName.getLocalName(),
+ localPropName,
+ PropertyType.nameFromValue(prop.getType()),
+ "");
continue;
}
- Name propName = ((AbstractJcrProperty)prop).name();
-
- String localPropName = getPrefixedName(propName);
-
Value value;
if (prop instanceof JcrSingleValueProperty) {
value = prop.getValue();
@@ -115,11 +124,31 @@
// 6.4.2.5
value = prop.getValues()[0];
}
+
+ String valueAsString;
+ if (PropertyType.BINARY == prop.getType()) {
+ StringBuffer buff = new StringBuffer(ENCODE_BUFFER_SIZE);
+ try {
+ Base64.InputStream is = new Base64.InputStream(value.getStream(),
Base64.ENCODE);
+
+ byte[] bytes = new byte[ENCODE_BUFFER_SIZE];
+ int len;
+ while (-1 != (len = is.read(bytes, 0, ENCODE_BUFFER_SIZE))) {
+ buff.append(new String(bytes, 0, len));
+ }
+ } catch (IOException ioe) {
+ throw new RepositoryException(ioe);
+ }
+ valueAsString = buff.toString();
+ } else {
+ valueAsString = VALUE_ENCODER.encode(value.getString());
+ }
+
atts.addAttribute(propName.getNamespaceUri(),
propName.getLocalName(),
localPropName,
PropertyType.nameFromValue(prop.getType()),
- VALUE_ENCODER.encode(value.getString()));
+ valueAsString);
}
Name name;
@@ -148,8 +177,10 @@
* Indicates whether the current node is an XML text node as per section 6.4.2.3 of
the JCR 1.0 specification. XML text nodes
* are nodes that have the name "jcr:xmltext" and only one property
(besides the mandatory
* "jcr:primaryType"). The property must have a property name of
"jcr:xmlcharacters", a type of
- * <code>String</code>, and does not have multiple values.<p/> In
practice, this is handled in DNA by making XML text nodes
- * have a type of "dna:xmltext", which enforces these property
characteristics.
+ * <code>String</code>, and does not have multiple values.
+ * <p/>
+ * In practice, this is handled in DNA by making XML text nodes have a type of
"dna:xmltext", which enforces these
+ * property characteristics.
*
* @param node the node to test
* @return whether this node is a special xml text node
@@ -224,6 +255,7 @@
* underscore characters that might otherwise suggest an encoding, as defined in
{@link XmlNameEncoder}.
*/
protected static class JcrDocumentViewPropertyEncoder extends XmlNameEncoder {
+
private static final Set<Character> MAPPED_CHARACTERS;
static {
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrValue.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrValue.java 2009-07-22 22:41:00 UTC
(rev 1125)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrValue.java 2009-07-24 01:15:00 UTC
(rev 1126)
@@ -56,6 +56,7 @@
private final ValueFactories valueFactories;
private final int type;
private final Object value;
+ private InputStream asStream = null;
JcrValue( ValueFactories valueFactories,
SessionCache sessionCache,
@@ -187,10 +188,12 @@
throw new IllegalStateException(JcrI18n.nonInputStreamConsumed.text());
}
try {
- Binary binary = valueFactories.getBinaryFactory().create(value);
- InputStream convertedValue = new SelfClosingInputStream(binary);
- state = State.INPUT_STREAM_CONSUMED;
- return convertedValue;
+ if (asStream == null) {
+ Binary binary = valueFactories.getBinaryFactory().create(value);
+ asStream = new SelfClosingInputStream(binary);
+ state = State.INPUT_STREAM_CONSUMED;
+ }
+ return asStream;
} catch (RuntimeException error) {
throw createValueFormatException(InputStream.class);
}
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/SessionCache.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/SessionCache.java 2009-07-22 22:41:00
UTC (rev 1125)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/SessionCache.java 2009-07-24 01:15:00
UTC (rev 1126)
@@ -2067,43 +2067,7 @@
uuidProperty = propertyFactory.create(JcrLexicon.UUID, uuid);
}
}
- if (uuidProperty == null) {
-
org.jboss.dna.graph.session.GraphSession.PropertyInfo<JcrPropertyPayload> uuidInfo =
node.getProperty(JcrLexicon.UUID);
- if (uuidInfo != null) {
- uuidProperty = uuidInfo.getProperty();
- }
- if (uuidProperty != null) {
- // Grab the first 'good' UUID value ...
- for (Object uuidValue : uuidProperty) {
- try {
- uuid = factories.getUuidFactory().create(uuidValue);
- break;
- } catch (ValueFormatException e) {
- // Ignore; just continue with the next property value
- }
- }
- }
- if (uuid == null) {
- // Look for the DNA UUID property ...
- uuidInfo = node.getProperty(DnaLexicon.UUID);
- if (uuidInfo != null) {
- uuidProperty = uuidInfo.getProperty();
- }
- if (uuidProperty != null) {
- // Grab the first 'good' UUID value ...
- for (Object uuidValue : uuidProperty) {
- try {
- uuid = factories.getUuidFactory().create(uuidValue);
- break;
- } catch (ValueFormatException e) {
- // Ignore; just continue with the next property value
- }
- }
- }
- }
- }
- if (uuid == null) uuid = UUID.randomUUID();
- if (uuidProperty == null) uuidProperty =
propertyFactory.create(JcrLexicon.UUID, uuid);
+ if (uuid != null && uuidProperty == null) uuidProperty =
propertyFactory.create(JcrLexicon.UUID, uuid);
// Look for the primary type of the node ...
Map<Name, Property> graphProperties =
persistentNode.getPropertiesByName();
Modified: trunk/dna-jcr/src/main/resources/org/jboss/dna/jcr/dna_builtins.cnd
===================================================================
--- trunk/dna-jcr/src/main/resources/org/jboss/dna/jcr/dna_builtins.cnd 2009-07-22
22:41:00 UTC (rev 1125)
+++ trunk/dna-jcr/src/main/resources/org/jboss/dna/jcr/dna_builtins.cnd 2009-07-24
01:15:00 UTC (rev 1126)
@@ -53,3 +53,8 @@
+ jcr:system (dna:system) = dna:system autocreated mandatory protected ignore
+ * (nt:base) = nt:unstructured multiple version
+[dna:resource] > nt:base
+- jcr:data (binary) primary mandatory
+- jcr:encoding (string) copy
+- jcr:lastModified (date) mandatory ignore
+- jcr:mimeType (string) copy mandatory
Modified: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/DnaRepositoryStub.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/DnaRepositoryStub.java 2009-07-22
22:41:00 UTC (rev 1125)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/DnaRepositoryStub.java 2009-07-24
01:15:00 UTC (rev 1126)
@@ -39,6 +39,9 @@
* Concrete implementation of {@link RepositoryStub} based on DNA-specific
configuration.
*/
public class DnaRepositoryStub extends RepositoryStub {
+
+ public static final String DNA_SKIP_IMPORT =
"javax.jcr.tck.dnaSkipImport";
+
private static final String REPOSITORY_SOURCE_NAME = "Test Repository
Source";
private static String currentConfigurationName = "default";
@@ -46,7 +49,6 @@
private Properties configProps;
private String repositoryConfigurationName;
private JcrRepository repository;
-
static {
@@ -69,7 +71,7 @@
private void configureRepository() {
repositoryConfigurationName = currentConfigurationName;
-
+
// Create the in-memory (DNA) repository
JcrConfiguration configuration = new JcrConfiguration();
try {
@@ -94,7 +96,6 @@
JcrEngine engine = configuration.build();
engine.start();
- // Problems problems = engine.getRepositoryService().getStartupProblems();
Problems problems = engine.getProblems();
// Print all of the problems from the engine configuration ...
for (Problem problem : problems) {
@@ -110,24 +111,27 @@
try {
repository = engine.getRepository(REPOSITORY_SOURCE_NAME);
- // Set up some sample nodes in the graph to match the expected test
configuration
- Graph graph = Graph.create(repository.getRepositorySourceName(),
- engine.getRepositoryConnectionFactory(),
- executionContext);
- Path destinationPath =
executionContext.getValueFactories().getPathFactory().createRootPath();
+ // This needs to check configProps directly to avoid an infinite loop
+ String skipImport = (String)configProps.get(DNA_SKIP_IMPORT);
+ if (!Boolean.valueOf(skipImport)) {
- InputStream xmlStream =
getClass().getResourceAsStream("/tck/repositoryForTckTests.xml");
- graph.importXmlFrom(xmlStream).into(destinationPath);
+ // Set up some sample nodes in the graph to match the expected test
configuration
+ Graph graph = Graph.create(repository.getRepositorySourceName(),
+ engine.getRepositoryConnectionFactory(),
+ executionContext);
+ Path destinationPath =
executionContext.getValueFactories().getPathFactory().createRootPath();
- graph.createWorkspace().named("otherWorkspace");
+ InputStream xmlStream =
getClass().getResourceAsStream("/tck/repositoryForTckTests.xml");
+ graph.importXmlFrom(xmlStream).into(destinationPath);
+ graph.createWorkspace().named("otherWorkspace");
+ }
} catch (Exception ex) {
// The TCK tries to quash this exception. Print it out to be more obvious.
ex.printStackTrace();
throw new IllegalStateException("Failed to initialize the repository
with text content.", ex);
}
-
}
public static void setCurrentConfigurationName( String newConfigName ) {
Modified: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/DnaTckTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/DnaTckTest.java 2009-07-22 22:41:00 UTC
(rev 1125)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/DnaTckTest.java 2009-07-24 01:15:00 UTC
(rev 1126)
@@ -13,6 +13,8 @@
import javax.jcr.Session;
import javax.jcr.SimpleCredentials;
import javax.jcr.nodetype.ConstraintViolationException;
+import junit.framework.Test;
+import junit.framework.TestSuite;
import org.apache.jackrabbit.test.AbstractJCRTest;
import org.jboss.dna.jcr.nodetype.NodeTypeTemplate;
@@ -23,6 +25,25 @@
Session session;
+ public DnaTckTest( String testName ) {
+ super();
+
+ this.setName(testName);
+ this.isReadOnly = true;
+ }
+
+ public static Test readOnlySuite() {
+ TestSuite suite = new TestSuite("DNA JCR API tests");
+
+ suite.addTest(new DnaTckTest("testShouldAllowAdminSessionToRead"));
+ suite.addTest(new DnaTckTest("testShouldAllowReadOnlySessionToRead"));
+ suite.addTest(new
DnaTckTest("testShouldAllowReadWriteSessionToRead"));
+ suite.addTest(new
DnaTckTest("testShouldNotSeeWorkspacesWithoutReadPermission"));
+ suite.addTest(new
DnaTckTest("testShouldMapReadRolesToWorkspacesWhenSpecified"));
+
+ return suite;
+ }
+
@Override
protected void tearDown() throws Exception {
try {
@@ -254,11 +275,35 @@
*
* @throws Exception
*/
- public void testShouldMapRolesToWorkspacesWhenSpecified() throws Exception {
+ public void testShouldMapReadRolesToWorkspacesWhenSpecified() throws Exception {
Credentials creds = new SimpleCredentials("defaultonly",
"defaultonly".toCharArray());
session = helper.getRepository().login(creds);
testRead(session);
+
+ session.logout();
+
+ session = helper.getRepository().login(creds, "otherWorkspace");
+ testRead(session);
+ try {
+ testWrite(session);
+ fail("User 'defaultuser' should not have write access to
'otherWorkspace'");
+ } catch (AccessDeniedException expected) {
+ }
+ session.logout();
+ }
+
+ /**
+ * User defaultuser is configured to have readwrite in "otherWorkspace" and
readonly in the default workspace. This test makes
+ * sure both work.
+ *
+ * @throws Exception
+ */
+ public void testShouldMapWriteRolesToWorkspacesWhenSpecified() throws Exception {
+ Credentials creds = new SimpleCredentials("defaultonly",
"defaultonly".toCharArray());
+ session = helper.getRepository().login(creds);
+
+ testRead(session);
testWrite(session);
session.logout();
Modified: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrTckTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrTckTest.java 2009-07-22 22:41:00 UTC
(rev 1125)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrTckTest.java 2009-07-24 01:15:00 UTC
(rev 1126)
@@ -107,6 +107,23 @@
}
/**
+ * Wrapper for read-only tests
+ *
+ * @return a new instance of {@link JCRTestSuite}.
+ */
+ public static Test readOnlySuite() {
+ // Uncomment this to execute all tests
+ // return new JCRTestSuite();
+
+ // Or uncomment the following lines to execute the different sets/suites of tests
...
+ TestSuite suite = new TestSuite("JCR 1.0 API tests");
+
+ suite.addTest(new LevelOneFeatureTests());
+
+ return suite;
+ }
+
+ /**
* Test suite that includes the Level 1 JCR TCK API tests from the Jackrabbit
project.
*/
private static class LevelOneFeatureTests extends TestSuite {
Modified: trunk/dna-jcr/src/test/resources/security/tck_roles.properties
===================================================================
--- trunk/dna-jcr/src/test/resources/security/tck_roles.properties 2009-07-22 22:41:00 UTC
(rev 1125)
+++ trunk/dna-jcr/src/test/resources/security/tck_roles.properties 2009-07-24 01:15:00 UTC
(rev 1126)
@@ -2,6 +2,6 @@
superuser=admin
readwrite=readwrite
readonly=readonly
-# default workspace name is the empty string
-defaultonly=readwrite.Store.default,readonly.Store.otherWorkspace
+# defaultWorkspace is the default workspace name for the filesystem TCK test
+defaultonly=readwrite.Store.default,readonly.Store.otherWorkspace,readwrite.Store.defaultWorkspace
noaccess=readonly.Store.otherWorkspace
Modified:
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-07-22
22:41:00 UTC (rev 1125)
+++
trunk/extensions/dna-connector-filesystem/src/main/java/org/jboss/dna/connector/filesystem/FileSystemConnection.java 2009-07-24
01:15:00 UTC (rev 1126)
@@ -25,7 +25,8 @@
import java.io.File;
import java.io.FilenameFilter;
-import java.util.Set;
+import java.util.Map;
+import java.util.UUID;
import java.util.concurrent.TimeUnit;
import javax.transaction.xa.XAResource;
import org.jboss.dna.graph.ExecutionContext;
@@ -44,28 +45,35 @@
public class FileSystemConnection implements RepositoryConnection {
private final String sourceName;
- private final File defaultWorkspace;
+ private final String defaultWorkspaceName;
private final CachePolicy cachePolicy;
- private final Set<String> availableWorkspaceNames;
+ private final Map<String, File> availableWorkspaces;
private final boolean creatingWorkspacesAllowed;
private final FilenameFilter filenameFilter;
+ private final UUID rootNodeUuid;
+ private final String workspaceRootPath;
private final boolean updatesAllowed;
FileSystemConnection( String sourceName,
- File defaultWorkspace,
- Set<String> availableWorkspaceNames,
+ String defaultWorkspaceName,
+ Map<String, File> availableWorkspaces,
boolean creatingWorkspacesAllowed,
CachePolicy cachePolicy,
+ UUID rootNodeUuid,
+ String workspaceRootPath,
FilenameFilter filenameFilter,
boolean updatesAllowed ) {
assert sourceName != null;
assert sourceName.trim().length() != 0;
- assert availableWorkspaceNames != null;
+ assert availableWorkspaces != null;
+ assert rootNodeUuid != null;
this.sourceName = sourceName;
- this.defaultWorkspace = defaultWorkspace;
- this.availableWorkspaceNames = availableWorkspaceNames;
+ this.defaultWorkspaceName = defaultWorkspaceName;
+ this.availableWorkspaces = availableWorkspaces;
this.creatingWorkspacesAllowed = creatingWorkspacesAllowed;
this.cachePolicy = cachePolicy;
+ this.rootNodeUuid = rootNodeUuid;
+ this.workspaceRootPath = workspaceRootPath;
this.filenameFilter = filenameFilter;
this.updatesAllowed = updatesAllowed;
}
@@ -115,8 +123,9 @@
*/
public void execute( ExecutionContext context,
Request request ) throws RepositorySourceException {
- RequestProcessor proc = new FileSystemRequestProcessor(sourceName,
defaultWorkspace, availableWorkspaceNames,
- creatingWorkspacesAllowed,
context, filenameFilter, updatesAllowed);
+ RequestProcessor proc = new FileSystemRequestProcessor(sourceName,
defaultWorkspaceName, availableWorkspaces,
+ creatingWorkspacesAllowed,
rootNodeUuid, workspaceRootPath,
+ context, filenameFilter,
updatesAllowed);
try {
proc.process(request);
} finally {
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-07-22
22:41:00 UTC (rev 1125)
+++
trunk/extensions/dna-connector-filesystem/src/main/java/org/jboss/dna/connector/filesystem/FileSystemI18n.java 2009-07-24
01:15:00 UTC (rev 1126)
@@ -40,6 +40,9 @@
public static I18n pathForPredefinedWorkspaceDoesNotExist;
public static I18n pathForPredefinedWorkspaceIsNotDirectory;
public static I18n pathForPredefinedWorkspaceCannotBeRead;
+ public static I18n pathForWorkspaceRootDoesNotExist;
+ public static I18n pathForWorkspaceRootIsNotDirectory;
+ public static I18n pathForWorkspaceRootCannotBeRead;
public static I18n propertyIsRequired;
public static I18n locationInRequestMustHavePath;
public static I18n sameNameSiblingsAreNotAllowed;
Modified:
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-07-22
22:41:00 UTC (rev 1125)
+++
trunk/extensions/dna-connector-filesystem/src/main/java/org/jboss/dna/connector/filesystem/FileSystemRequestProcessor.java 2009-07-24
01:15:00 UTC (rev 1126)
@@ -31,8 +31,11 @@
import java.io.InputStream;
import java.util.Collections;
import java.util.HashSet;
+import java.util.Map;
import java.util.Set;
+import java.util.UUID;
import org.jboss.dna.common.i18n.I18n;
+import org.jboss.dna.graph.DnaLexicon;
import org.jboss.dna.graph.ExecutionContext;
import org.jboss.dna.graph.JcrLexicon;
import org.jboss.dna.graph.JcrNtLexicon;
@@ -77,43 +80,68 @@
private static final String DEFAULT_MIME_TYPE = "application/octet";
private final String defaultNamespaceUri;
- private final Set<String> availableWorkspaceNames;
+ private final Map<String, File> availableWorkspaces;
private final boolean creatingWorkspacesAllowed;
- private final File defaultWorkspace;
+ private final String defaultWorkspaceName;
+ private final File workspaceRootPath;
private final FilenameFilter filenameFilter;
private final boolean updatesAllowed;
private final MimeTypeDetector mimeTypeDetector;
+ private final UUID rootNodeUuid;
/**
* @param sourceName
- * @param defaultWorkspace
- * @param availableWorkspaceNames
+ * @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 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
*/
protected FileSystemRequestProcessor( String sourceName,
- File defaultWorkspace,
- Set<String> availableWorkspaceNames,
+ String defaultWorkspaceName,
+ Map<String, File> availableWorkspaces,
boolean creatingWorkspacesAllowed,
+ UUID rootNodeUuid,
+ String workspaceRootPath,
ExecutionContext context,
FilenameFilter filenameFilter,
boolean updatesAllowed ) {
super(sourceName, context, null);
- assert defaultWorkspace != null;
- assert defaultWorkspace.exists();
- assert defaultWorkspace.canRead();
- assert defaultWorkspace.isDirectory();
- assert availableWorkspaceNames != null;
- this.availableWorkspaceNames = availableWorkspaceNames;
+ assert defaultWorkspaceName != null;
+ assert availableWorkspaces != null;
+ assert rootNodeUuid != null;
+ this.availableWorkspaces = availableWorkspaces;
this.creatingWorkspacesAllowed = creatingWorkspacesAllowed;
this.defaultNamespaceUri =
getExecutionContext().getNamespaceRegistry().getDefaultNamespaceUri();
+ this.rootNodeUuid = rootNodeUuid;
this.filenameFilter = filenameFilter;
- this.defaultWorkspace = defaultWorkspace;
+ this.defaultWorkspaceName = defaultWorkspaceName;
this.updatesAllowed = updatesAllowed;
this.mimeTypeDetector = context.getMimeTypeDetector();
+
+ 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;
+ }
}
/**
@@ -134,6 +162,11 @@
// 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
@@ -180,13 +213,20 @@
return;
}
+ PropertyFactory factory = getExecutionContext().getPropertyFactory();
+
// Find the existing file for the parent ...
Location location = request.at();
Path path = getPathFor(location, request);
if (path.isRoot()) {
- // There are no properties on the root ...
+ // 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;
}
@@ -197,7 +237,6 @@
return;
}
// Generate the properties for this File object ...
- PropertyFactory factory = getExecutionContext().getPropertyFactory();
DateTimeFactory dateFactory =
getExecutionContext().getValueFactories().getDateFactory();
// Note that we don't have 'created' timestamps, just last modified,
so we'll have to use them
if (file.isDirectory()) {
@@ -209,7 +248,9 @@
// It is a file, but ...
if (path.getLastSegment().getName().equals(JcrLexicon.CONTENT)) {
// The request is to get properties of the "jcr:content" child
node ...
- request.addProperty(factory.create(JcrLexicon.PRIMARY_TYPE,
JcrNtLexicon.RESOURCE));
+ // ... 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")));
@@ -330,23 +371,19 @@
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 =
getCanonicalWorkspaceName(defaultWorkspace);
+ 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.availableWorkspaceNames) {
+ for (String available : this.availableWorkspaces.keySet()) {
if (workspaceName.equals(available)) {
found = true;
break;
}
- File directory = new File(available);
- if (directory.exists() && directory.isDirectory() &&
directory.canRead()
- &&
getCanonicalWorkspaceName(directory).equals(workspaceName)) {
- found = true;
- break;
- }
}
+
if (!found) {
request.setError(new
InvalidWorkspaceException(FileSystemI18n.workspaceDoesNotExist.text(workspaceName)));
return;
@@ -354,9 +391,9 @@
// 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 = new File(workspaceName);
+ File directory = availableWorkspaces.get(workspaceName);
if (directory.exists() && directory.isDirectory() &&
directory.canRead()) {
- request.setActualWorkspaceName(getCanonicalWorkspaceName(directory));
+ request.setActualWorkspaceName(workspaceName);
request.setActualRootLocation(Location.create(pathFactory().createRootPath()));
} else {
request.setError(new
InvalidWorkspaceException(FileSystemI18n.workspaceDoesNotExist.text(workspaceName)));
@@ -372,12 +409,13 @@
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 (String name : this.availableWorkspaceNames) {
- File directory = new File(name);
+ for (Map.Entry<String, File> entry : this.availableWorkspaces.entrySet())
{
+ File directory = entry.getValue();
if (directory.exists() && directory.isDirectory() &&
directory.canRead()) {
- names.add(getCanonicalWorkspaceName(directory));
+ names.add(entry.getKey());
}
}
+
request.setAvailableWorkspaceNames(Collections.unmodifiableSet(names));
}
@@ -389,6 +427,12 @@
*/
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();
@@ -424,7 +468,7 @@
if (directory.exists() && directory.isDirectory() &&
directory.canRead()) {
request.setActualWorkspaceName(getCanonicalWorkspaceName(directory));
request.setActualRootLocation(Location.create(pathFactory().createRootPath()));
- availableWorkspaceNames.add(workspaceName);
+ availableWorkspaces.put(workspaceName, directory);
recordChange(request);
} else {
request.setError(new
InvalidWorkspaceException(FileSystemI18n.workspaceDoesNotExist.text(workspaceName)));
@@ -444,7 +488,7 @@
request.setError(new InvalidRequestException(msg));
}
// This doesn't delete the file/directory; rather, it just remove the
workspace from the available set ...
- if (!this.availableWorkspaceNames.remove(workspaceName)) {
+ if (this.availableWorkspaces.remove(workspaceName) == null) {
request.setError(new
InvalidWorkspaceException(FileSystemI18n.workspaceDoesNotExist.text(workspaceName)));
} else {
request.setActualRootLocation(Location.create(pathFactory().createRootPath()));
@@ -470,6 +514,11 @@
protected Path getPathFor( Location location,
Request request ) {
Path path = location.getPath();
+
+ if (location.getUuid() != null &&
rootNodeUuid.equals(location.getUuid())) {
+ return pathFactory().createRootPath();
+ }
+
if (path == null) {
I18n msg = FileSystemI18n.locationInRequestMustHavePath;
throw new RepositorySourceException(getSourceName(),
msg.text(getSourceName(), request));
@@ -478,13 +527,11 @@
}
protected File getWorkspaceDirectory( String workspaceName ) {
- File workspace = defaultWorkspace;
- if (workspaceName != null) {
- File directory = new File(workspaceName);
- if (directory.exists() && directory.isDirectory() &&
directory.canRead()) workspace = directory;
- else return null;
- }
- return workspace;
+ 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;
}
/**
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-07-22
22:41:00 UTC (rev 1125)
+++
trunk/extensions/dna-connector-filesystem/src/main/java/org/jboss/dna/connector/filesystem/FileSystemSource.java 2009-07-24
01:15:00 UTC (rev 1126)
@@ -31,7 +31,8 @@
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
-import java.util.concurrent.CopyOnWriteArraySet;
+import java.util.UUID;
+import java.util.concurrent.ConcurrentHashMap;
import javax.naming.Context;
import javax.naming.RefAddr;
import javax.naming.Reference;
@@ -40,6 +41,7 @@
import net.jcip.annotations.Immutable;
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.cache.CachePolicy;
@@ -64,10 +66,16 @@
*/
private static final long serialVersionUID = 1L;
+ /**
+ * The initial {@link #getDefaultWorkspaceName() name of the default workspace} is
"{@value} ", unless otherwise specified.
+ */
+ public static final String DEFAULT_NAME_OF_DEFAULT_WORKSPACE = "default";
+
protected static final String SOURCE_NAME = "sourceName";
protected static final String CACHE_TIME_TO_LIVE_IN_MILLISECONDS =
"cacheTimeToLiveInMilliseconds";
protected static final String RETRY_LIMIT = "retryLimit";
protected static final String DEFAULT_WORKSPACE = "defaultWorkspace";
+ protected static final String WORKSPACE_ROOT = "workspaceRootPath";
protected static final String PREDEFINED_WORKSPACE_NAMES =
"predefinedWorkspaceNames";
protected static final String ALLOW_CREATING_WORKSPACES =
"allowCreatingWorkspaces";
@@ -84,7 +92,7 @@
*/
protected static final boolean DEFAULT_SUPPORTS_CREATING_WORKSPACES = true;
/**
- * This source does not support udpates by default, but each instance may be
configured to be read-only or updateable}.
+ * This source does not support updates by default, but each instance may be
configured to be read-only or updateable}.
*/
public static final boolean DEFAULT_SUPPORTS_UPDATES = false;
@@ -99,8 +107,10 @@
private volatile String name;
private volatile int retryLimit = DEFAULT_RETRY_LIMIT;
private volatile int cacheTimeToLiveInMilliseconds =
DEFAULT_CACHE_TIME_TO_LIVE_IN_SECONDS * 1000;
- private volatile String defaultWorkspace;
+ private volatile String defaultWorkspaceName = DEFAULT_NAME_OF_DEFAULT_WORKSPACE;
+ private volatile String workspaceRootPath;
private volatile String[] predefinedWorkspaces = new String[] {};
+ private volatile UUID rootNodeUuid = UUID.randomUUID();
private volatile RepositorySourceCapabilities capabilities = new
RepositorySourceCapabilities(
SUPPORTS_SAME_NAME_SIBLINGS,
DEFAULT_SUPPORTS_UPDATES,
@@ -108,7 +118,7 @@
DEFAULT_SUPPORTS_CREATING_WORKSPACES,
SUPPORTS_REFERENCES);
private transient CachePolicy cachePolicy;
- private transient CopyOnWriteArraySet<String> availableWorkspaceNames;
+ private transient Map<String, File> availableWorkspaces;
/**
*
@@ -170,30 +180,64 @@
// }
/**
- * Get the file system path to the existing directory that should be used for the
default workspace. If the default is
- * specified as a null String or is not a valid and resolvable path, this source will
consider the default to be the current
- * working directory of this virtual machine, as defined by the <code>new
File(".")</code>.
+ * Get the relative root directory for the workspaces. If this property is set,
workspaces can be given as relative paths from
+ * this directory and all workspace paths must be ancestors of this path.
*
- * @return the file system path to the directory representing the default workspace,
or null if the default should be the
- * current working directory
+ * @return the root directory for workspaces
*/
- public String getDirectoryForDefaultWorkspace() {
- return defaultWorkspace;
+ public String getWorkspaceRootPath() {
+ return workspaceRootPath;
}
/**
- * Set the file system path to the existing directory that should be used for the
default workspace. If the default is
- * specified as a null String or is not a valid and resolvable path, this source will
consider the default to be the current
- * working directory of this virtual machine, as defined by the <code>new
File(".")</code>.
+ * Sets the relative root directory for workspaces
*
- * @param pathToDirectoryForDefaultWorkspace the valid and resolvable file system
path to the directory representing the
- * default workspace, or null if the current working directory should be used
as the default workspace
+ * @param workspaceRootPath the relative root directory for workspaces. If this value
is non-null, all workspace paths will be
+ * treated as paths relative to this directory
*/
- public synchronized void setDirectoryForDefaultWorkspace( String
pathToDirectoryForDefaultWorkspace ) {
- this.defaultWorkspace = pathToDirectoryForDefaultWorkspace;
+ public synchronized void setWorkspaceRootPath( String workspaceRootPath ) {
+ this.workspaceRootPath = workspaceRootPath;
}
/**
+ * Get the UUID that is used for the root node of each workspace
+ *
+ * @return the UUID that is used for the root node of each workspace
+ */
+ public UUID getRootNodeUuid() {
+ return rootNodeUuid;
+ }
+
+ /**
+ * Set the {@code jcr:uuid} property of the root node in each workspace to the given
value.
+ *
+ * @param rootNodeUuid the UUID to use for the root nodes of all workspaces
+ */
+ public synchronized void setRootNodeUuid( String rootNodeUuid ) {
+ CheckArg.isNotNull(rootNodeUuid, "rootNodeUuid");
+ this.rootNodeUuid = UUID.fromString(rootNodeUuid);
+ }
+
+ /**
+ * Get the name of the default workspace.
+ *
+ * @return the name of the workspace that should be used by default; never null
+ */
+ public String getDefaultWorkspaceName() {
+ return defaultWorkspaceName;
+ }
+
+ /**
+ * Set the name of the workspace that should be used when clients don't specify a
workspace.
+ *
+ * @param nameOfDefaultWorkspace the name of the workspace that should be used by
default, or null if the
+ * {@link #DEFAULT_NAME_OF_DEFAULT_WORKSPACE default name} should be used
+ */
+ public synchronized void setDefaultWorkspaceName( String nameOfDefaultWorkspace ) {
+ this.defaultWorkspaceName = nameOfDefaultWorkspace != null ?
nameOfDefaultWorkspace : DEFAULT_NAME_OF_DEFAULT_WORKSPACE;
+ }
+
+ /**
* Gets the names of the workspaces that are available when this source is created.
Each workspace name corresponds to a path
* to a directory on the file system.
*
@@ -310,7 +354,7 @@
}
ref.add(new StringRefAddr(CACHE_TIME_TO_LIVE_IN_MILLISECONDS,
Integer.toString(getCacheTimeToLiveInMilliseconds())));
ref.add(new StringRefAddr(RETRY_LIMIT, Integer.toString(getRetryLimit())));
- ref.add(new StringRefAddr(DEFAULT_WORKSPACE,
getDirectoryForDefaultWorkspace()));
+ ref.add(new StringRefAddr(DEFAULT_WORKSPACE, getDefaultWorkspaceName()));
ref.add(new StringRefAddr(ALLOW_CREATING_WORKSPACES,
Boolean.toString(isCreatingWorkspacesAllowed())));
String[] workspaceNames = getPredefinedWorkspaceNames();
if (workspaceNames != null && workspaceNames.length != 0) {
@@ -356,7 +400,7 @@
if (sourceName != null) source.setName(sourceName);
if (cacheTtlInMillis != null)
source.setCacheTimeToLiveInMilliseconds(Integer.parseInt(cacheTtlInMillis));
if (retryLimit != null) source.setRetryLimit(Integer.parseInt(retryLimit));
- if (defaultWorkspace != null)
source.setDirectoryForDefaultWorkspace(defaultWorkspace);
+ if (defaultWorkspace != null)
source.setDefaultWorkspaceName(defaultWorkspace);
if (createWorkspaces != null)
source.setCreatingWorkspacesAllowed(Boolean.parseBoolean(createWorkspaces));
if (workspaceNames != null && workspaceNames.length != 0)
source.setPredefinedWorkspaceNames(workspaceNames);
return source;
@@ -364,6 +408,18 @@
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}
*
@@ -376,54 +432,42 @@
throw new RepositorySourceException(getName(), msg.text("name"));
}
- boolean reportWarnings = false;
- if (this.availableWorkspaceNames == null) {
+ if (this.availableWorkspaces == null) {
// Set up the predefined workspace names ...
- this.availableWorkspaceNames = new CopyOnWriteArraySet<String>();
+ this.availableWorkspaces = new ConcurrentHashMap<String, File>();
for (String predefined : this.predefinedWorkspaces) {
- this.availableWorkspaceNames.add(predefined);
- }
-
- // Report the warnings for non-existant predefined workspaces
- reportWarnings = true;
- for (String path : this.availableWorkspaceNames) {
// Look for the file at this path ...
- File file = new File(path);
+ File file = new File(pathFor(predefined));
if (!file.exists()) {
-
Logger.getLogger(getClass()).warn(FileSystemI18n.pathForPredefinedWorkspaceDoesNotExist,
path, name);
+
Logger.getLogger(getClass()).warn(FileSystemI18n.pathForPredefinedWorkspaceDoesNotExist,
predefined, name);
} else if (!file.isDirectory()) {
-
Logger.getLogger(getClass()).warn(FileSystemI18n.pathForPredefinedWorkspaceIsNotDirectory,
path, name);
+
Logger.getLogger(getClass()).warn(FileSystemI18n.pathForPredefinedWorkspaceIsNotDirectory,
predefined, name);
} else if (!file.canRead()) {
-
Logger.getLogger(getClass()).warn(FileSystemI18n.pathForPredefinedWorkspaceCannotBeRead,
path, name);
+
Logger.getLogger(getClass()).warn(FileSystemI18n.pathForPredefinedWorkspaceCannotBeRead,
predefined, name);
}
+
+
+ this.availableWorkspaces.put(predefined, file);
}
}
- FilenameFilter filenameFilter = null;
- boolean supportsUpdates = getSupportsUpdates();
- File defaultWorkspace = new File(".");
- String path = getDirectoryForDefaultWorkspace();
- if (path != null) {
+ if (defaultWorkspaceName != null) {
// Look for the file at this path ...
- File file = new File(path);
- I18n warning = null;
+ File file = new File(pathFor(defaultWorkspaceName));
if (!file.exists()) {
- warning = FileSystemI18n.pathForDefaultWorkspaceDoesNotExist;
+
Logger.getLogger(getClass()).warn(FileSystemI18n.pathForPredefinedWorkspaceDoesNotExist,
defaultWorkspaceName, name);
} else if (!file.isDirectory()) {
- warning = FileSystemI18n.pathForDefaultWorkspaceIsNotDirectory;
+
Logger.getLogger(getClass()).warn(FileSystemI18n.pathForPredefinedWorkspaceIsNotDirectory,
defaultWorkspaceName, name);
} else if (!file.canRead()) {
- warning = FileSystemI18n.pathForDefaultWorkspaceCannotBeRead;
- } else {
- // good to use!
- defaultWorkspace = file;
+
Logger.getLogger(getClass()).warn(FileSystemI18n.pathForPredefinedWorkspaceCannotBeRead,
defaultWorkspaceName, name);
}
- if (reportWarnings && warning != null) {
- Logger.getLogger(getClass()).warn(warning, path, name);
- }
+
+
+ this.availableWorkspaces.put(defaultWorkspaceName, file);
}
- this.availableWorkspaceNames.add(defaultWorkspace.getPath());
- return new FileSystemConnection(name, defaultWorkspace, availableWorkspaceNames,
isCreatingWorkspacesAllowed(),
- cachePolicy, filenameFilter, supportsUpdates);
+
+ return new FileSystemConnection(name, defaultWorkspaceName, availableWorkspaces,
isCreatingWorkspacesAllowed(),
+ cachePolicy, rootNodeUuid, workspaceRootPath,
(FilenameFilter) null, getSupportsUpdates());
}
@Immutable
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-07-22
22:41:00 UTC (rev 1125)
+++
trunk/extensions/dna-connector-filesystem/src/main/resources/org/jboss/dna/connector/filesystem/FileSystemI18n.properties 2009-07-24
01:15:00 UTC (rev 1126)
@@ -29,6 +29,9 @@
pathForPredefinedWorkspaceDoesNotExist = The path "{0}" for the predefined
workspace for the file system source "{1}" does not represent an existing
directory
pathForPredefinedWorkspaceIsNotDirectory = The path "{0}" for the predefined
workspace for the file system source "{1}" is actually a path to an existing
file
pathForPredefinedWorkspaceCannotBeRead = The path "{0}" for the predefined
workspace for the file system source "{1}" cannot be read
+pathForWorkspaceRootDoesNotExist = The path "{0}" for the predefined workspace
for the file system source "{1}" does not represent an existing directory
+pathForWorkspaceRootIsNotDirectory = The path "{0}" for the predefined
workspace for the file system source "{1}" is actually a path to an existing
file
+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}
Modified:
trunk/extensions/dna-connector-filesystem/src/test/java/org/jboss/dna/connector/filesystem/FileSystemConnectorCreateWorkspacesTest.java
===================================================================
---
trunk/extensions/dna-connector-filesystem/src/test/java/org/jboss/dna/connector/filesystem/FileSystemConnectorCreateWorkspacesTest.java 2009-07-22
22:41:00 UTC (rev 1125)
+++
trunk/extensions/dna-connector-filesystem/src/test/java/org/jboss/dna/connector/filesystem/FileSystemConnectorCreateWorkspacesTest.java 2009-07-24
01:15:00 UTC (rev 1126)
@@ -25,7 +25,6 @@
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertThat;
-import java.io.File;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
@@ -56,7 +55,7 @@
FileSystemSource source = new FileSystemSource();
source.setName("Test Repository");
source.setPredefinedWorkspaceNames(predefinedWorkspaceNames);
- source.setDirectoryForDefaultWorkspace(predefinedWorkspaceNames[0]);
+ source.setDefaultWorkspaceName(predefinedWorkspaceNames[0]);
source.setCreatingWorkspacesAllowed(true);
return source;
@@ -101,11 +100,8 @@
workspaceNames.add(workspace.getName());
}
// The actual names should be the absolute paths to the directories representing
the root ...
- String absolutePathToRepositories = new
File("./src/test/resources/repositories/").getCanonicalPath();
+ String absolutePathToRepositories =
"./src/test/resources/repositories/";
- // getCanonicalPath strips the trailing separator character, so we need to
re-added it for each case
- absolutePathToRepositories += File.separatorChar;
-
assertThat(workspaceNames.remove(absolutePathToRepositories +
"airplanes"), is(true));
assertThat(workspaceNames.remove(absolutePathToRepositories + "cars"),
is(true));
assertThat(workspaceNames.isEmpty(), is(true));
Modified:
trunk/extensions/dna-connector-filesystem/src/test/java/org/jboss/dna/connector/filesystem/FileSystemConnectorNoCreateWorkspaceTest.java
===================================================================
---
trunk/extensions/dna-connector-filesystem/src/test/java/org/jboss/dna/connector/filesystem/FileSystemConnectorNoCreateWorkspaceTest.java 2009-07-22
22:41:00 UTC (rev 1125)
+++
trunk/extensions/dna-connector-filesystem/src/test/java/org/jboss/dna/connector/filesystem/FileSystemConnectorNoCreateWorkspaceTest.java 2009-07-24
01:15:00 UTC (rev 1126)
@@ -49,7 +49,7 @@
FileSystemSource source = new FileSystemSource();
source.setName("Test Repository");
source.setPredefinedWorkspaceNames(predefinedWorkspaceNames);
- source.setDirectoryForDefaultWorkspace(predefinedWorkspaceNames[0]);
+ source.setDefaultWorkspaceName(predefinedWorkspaceNames[0]);
source.setCreatingWorkspacesAllowed(false);
return source;
Modified:
trunk/extensions/dna-connector-filesystem/src/test/java/org/jboss/dna/connector/filesystem/FileSystemConnectorNotWritableTest.java
===================================================================
---
trunk/extensions/dna-connector-filesystem/src/test/java/org/jboss/dna/connector/filesystem/FileSystemConnectorNotWritableTest.java 2009-07-22
22:41:00 UTC (rev 1125)
+++
trunk/extensions/dna-connector-filesystem/src/test/java/org/jboss/dna/connector/filesystem/FileSystemConnectorNotWritableTest.java 2009-07-24
01:15:00 UTC (rev 1126)
@@ -46,7 +46,7 @@
FileSystemSource source = new FileSystemSource();
source.setName("Test Repository");
source.setPredefinedWorkspaceNames(predefinedWorkspaceNames);
- source.setDirectoryForDefaultWorkspace(predefinedWorkspaceNames[0]);
+ source.setDefaultWorkspaceName(predefinedWorkspaceNames[0]);
source.setCreatingWorkspacesAllowed(false);
return source;
Modified:
trunk/extensions/dna-connector-filesystem/src/test/java/org/jboss/dna/connector/filesystem/FileSystemConnectorReadableTest.java
===================================================================
---
trunk/extensions/dna-connector-filesystem/src/test/java/org/jboss/dna/connector/filesystem/FileSystemConnectorReadableTest.java 2009-07-22
22:41:00 UTC (rev 1125)
+++
trunk/extensions/dna-connector-filesystem/src/test/java/org/jboss/dna/connector/filesystem/FileSystemConnectorReadableTest.java 2009-07-24
01:15:00 UTC (rev 1126)
@@ -26,7 +26,6 @@
import static org.hamcrest.core.Is.is;
import static org.hamcrest.core.IsNull.notNullValue;
import static org.junit.Assert.assertThat;
-import java.io.File;
import java.util.List;
import org.jboss.dna.graph.Graph;
import org.jboss.dna.graph.JcrLexicon;
@@ -50,13 +49,13 @@
@Override
protected RepositorySource setUpSource() {
// Set the connection properties to be use the content of
"./src/test/resources/repositories" as a repository ...
- String path = new File(".").getAbsolutePath() +
"/src/test/resources/repositories/";
+ String path = "./src/test/resources/repositories/";
String[] predefinedWorkspaceNames = new String[] {path + "airplanes",
path + "cars"};
FileSystemSource source = new FileSystemSource();
source.setName("Test Repository");
source.setPredefinedWorkspaceNames(predefinedWorkspaceNames);
- source.setDirectoryForDefaultWorkspace(predefinedWorkspaceNames[0]);
- source.setCreatingWorkspacesAllowed(false);
+ source.setDefaultWorkspaceName(predefinedWorkspaceNames[0]);
+ source.setCreatingWorkspacesAllowed(true);
return source;
}