DNA SVN: r1090 - in trunk: docs/reference/src/main/docbook/en-US and 26 other directories.
by dna-commits@lists.jboss.org
Author: bcarothers
Date: 2009-07-12 18:08:43 -0400 (Sun, 12 Jul 2009)
New Revision: 1090
Added:
trunk/docs/reference/src/main/docbook/en-US/content/connectors/infinispan.xml
trunk/extensions/dna-connector-infinispan/
trunk/extensions/dna-connector-infinispan/.classpath
trunk/extensions/dna-connector-infinispan/.project
trunk/extensions/dna-connector-infinispan/pom.xml
trunk/extensions/dna-connector-infinispan/src/
trunk/extensions/dna-connector-infinispan/src/main/
trunk/extensions/dna-connector-infinispan/src/main/java/
trunk/extensions/dna-connector-infinispan/src/main/java/org/
trunk/extensions/dna-connector-infinispan/src/main/java/org/jboss/
trunk/extensions/dna-connector-infinispan/src/main/java/org/jboss/dna/
trunk/extensions/dna-connector-infinispan/src/main/java/org/jboss/dna/connector/
trunk/extensions/dna-connector-infinispan/src/main/java/org/jboss/dna/connector/infinispan/
trunk/extensions/dna-connector-infinispan/src/main/java/org/jboss/dna/connector/infinispan/InfinispanConnectorI18n.java
trunk/extensions/dna-connector-infinispan/src/main/java/org/jboss/dna/connector/infinispan/InfinispanRepository.java
trunk/extensions/dna-connector-infinispan/src/main/java/org/jboss/dna/connector/infinispan/InfinispanSource.java
trunk/extensions/dna-connector-infinispan/src/main/resources/
trunk/extensions/dna-connector-infinispan/src/main/resources/org/
trunk/extensions/dna-connector-infinispan/src/main/resources/org/jboss/
trunk/extensions/dna-connector-infinispan/src/main/resources/org/jboss/dna/
trunk/extensions/dna-connector-infinispan/src/main/resources/org/jboss/dna/connector/
trunk/extensions/dna-connector-infinispan/src/main/resources/org/jboss/dna/connector/infinispan/
trunk/extensions/dna-connector-infinispan/src/main/resources/org/jboss/dna/connector/infinispan/InfinispanConnectorI18n.properties
trunk/extensions/dna-connector-infinispan/src/test/
trunk/extensions/dna-connector-infinispan/src/test/java/
trunk/extensions/dna-connector-infinispan/src/test/java/org/
trunk/extensions/dna-connector-infinispan/src/test/java/org/jboss/
trunk/extensions/dna-connector-infinispan/src/test/java/org/jboss/dna/
trunk/extensions/dna-connector-infinispan/src/test/java/org/jboss/dna/connector/
trunk/extensions/dna-connector-infinispan/src/test/java/org/jboss/dna/connector/infinispan/
trunk/extensions/dna-connector-infinispan/src/test/java/org/jboss/dna/connector/infinispan/InfinispanConnectorI18nTest.java
trunk/extensions/dna-connector-infinispan/src/test/java/org/jboss/dna/connector/infinispan/InfinispanConnectorReadableTest.java
trunk/extensions/dna-connector-infinispan/src/test/java/org/jboss/dna/connector/infinispan/InfinispanConnectorWritableTest.java
trunk/extensions/dna-connector-infinispan/src/test/java/org/jboss/dna/connector/infinispan/InfinispanSourceTest.java
trunk/extensions/dna-connector-infinispan/src/test/resources/
trunk/extensions/dna-connector-infinispan/src/test/resources/aircraft.xml
trunk/extensions/dna-connector-infinispan/src/test/resources/cars.xml
trunk/extensions/dna-connector-infinispan/src/test/resources/log4j.properties
Modified:
trunk/docs/reference/src/main/docbook/en-US/content/developers/tools.xml
trunk/docs/reference/src/main/docbook/en-US/custom.dtd
trunk/docs/reference/src/main/docbook/en-US/master.xml
trunk/pom.xml
Log:
DNA-474
Applied patch implements a connector based on the map repository framework that uses one Infinispan cache per workspace and uses each Infinispan cache as a map of UUIDs to MapNodes. It plagiarizes liberally from the JBoss Cache connector and offers comparable functionality and configuration points.
The committed change differs from the patch attached to the JIRA issue because of the minor rename of setNameOfDefaultWorkspace and getNameOfDefaultWorkspace to setDefaultWorkspaceName and getDefaultWorkspaceName in the InfinispanSource. This corresponds to the fixes in DNA-485.
Added: trunk/docs/reference/src/main/docbook/en-US/content/connectors/infinispan.xml
===================================================================
--- trunk/docs/reference/src/main/docbook/en-US/content/connectors/infinispan.xml (rev 0)
+++ trunk/docs/reference/src/main/docbook/en-US/content/connectors/infinispan.xml 2009-07-12 22:08:43 UTC (rev 1090)
@@ -0,0 +1,93 @@
+<?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
+ -->
+<!DOCTYPE preface PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
+<!ENTITY % CustomDTD SYSTEM "../../custom.dtd">
+%CustomDTD;
+]>
+<chapter id="infinispan-connector">
+ <title>Infinispan Connector</title>
+ <para>
+ The Infinispan repository connector allows a <ulink url="http://www.jboss.org/infinispan/">Infinispan</ulink> instance to be
+ used as a JBoss DNA (and thus JCR) repository. This provides a repository that is an effective, scalable, and distributed cache,
+ and is often paired with other repository sources to provide a local or <link linkend="federation-connector">federated</link>
+ repository.
+ </para>
+ <para>
+ The &InfinispanSource; class provides a number of JavaBean properties that control its behavior:
+ </para>
+ <table frame='all'>
+ <title>&InfinispanSource; properties</title>
+ <tgroup cols='2' align='left' colsep='1' rowsep='1'>
+ <colspec colname='c1' colwidth="1*"/>
+ <colspec colname='c2' colwidth="1*"/>
+ <thead>
+ <row>
+ <entry>Property</entry>
+ <entry>Description</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>name</entry>
+ <entry>The name of the repository source, which is used by the &RepositoryService; when obtaining a &RepositoryConnection; by name.</entry>
+ </row>
+ <row>
+ <entry>cacheManagerJndiName</entry>
+ <entry>Optional property that, if used, specifies the name in JNDI where an existing Infinispan Cache Manager instance can be found.
+ That factory would then be used if needed to create an Infinispan Cache instance. If no value is provided, then the
+ Infinispan <code>DefaultCacheManager</code> class is used.</entry>
+ </row>
+ <row>
+ <entry>cacheConfigurationName</entry>
+ <entry>Optional property that, if used, specifies the name of the configuration that is supplied to the cache manager
+ when creating a new Infinispan CacheManager instance.</entry>
+ </row>
+ <row>
+ <entry>retryLimit</entry>
+ <entry>Optional property that, if used, defines the number of times that any single operation on a &RepositoryConnection; to this source should be retried
+ following a communication failure. The default value is '0'.</entry>
+ </row>
+ <row>
+ <entry>defaultCachePolicy</entry>
+ <entry>Optional property that, if used, defines the default for how long this information provided by this source may to be
+ cached by other, higher-level components. The default value of null implies that this source does not define a specific
+ duration for caching information provided by this repository source.</entry>
+ </row>
+ <row>
+ <entry>nameOfDefaultWorkspace</entry>
+ <entry>Optional property that is initialized to an empty string and which defines the name for the workspace that will be used by default
+ if none is specified.</entry>
+ </row>
+ <row>
+ <entry>predefinedWorkspaceNames</entry>
+ <entry>Optional property that defines the names of the workspaces that exist and that are available for use without having to create them.</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+</chapter>
+
Property changes on: trunk/docs/reference/src/main/docbook/en-US/content/connectors/infinispan.xml
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Modified: trunk/docs/reference/src/main/docbook/en-US/content/developers/tools.xml
===================================================================
--- trunk/docs/reference/src/main/docbook/en-US/content/developers/tools.xml 2009-07-12 22:01:21 UTC (rev 1089)
+++ trunk/docs/reference/src/main/docbook/en-US/content/developers/tools.xml 2009-07-12 22:08:43 UTC (rev 1090)
@@ -488,9 +488,9 @@
<programlisting>$ svn checkout https://anonsvn.jboss.org/repos/dna/tags/dna-{release-number}/</programlisting>
<para>
Then, go into the new directory, and perform a Maven deploy:
+ </para>
+ <programlisting>$ mvn clean deploy</programlisting>
<para>
- <programlisting>$ mvn clean deploy</programlisting>
- <para>
This will rebuild all the artifacts (from your local copy of the <emphasis>tagged</emphasis> source) and deploy them
to the local file system, which is comprised of a local checkout of the JBoss Maven2 repository
in a location specified by a combination of the <code><distributionManagement></code> section of several <code>pom.xml</code>
Modified: trunk/docs/reference/src/main/docbook/en-US/custom.dtd
===================================================================
--- trunk/docs/reference/src/main/docbook/en-US/custom.dtd 2009-07-12 22:01:21 UTC (rev 1089)
+++ trunk/docs/reference/src/main/docbook/en-US/custom.dtd 2009-07-12 22:08:43 UTC (rev 1090)
@@ -188,6 +188,7 @@
<!ENTITY SVNRepositorySource "<ulink url='&API;connector/svn/SVNRepositorySource.html'><classname>SVNRepositorySource</classname></ulink>">
<!ENTITY JBossCacheRepository "<ulink url='&API;connector/jbosscache/JBossCacheRepository.html'><classname>JBossCacheRepository</classname></ulink>">
<!ENTITY JBossCacheSource "<ulink url='&API;connector/jbosscache/JBossCacheSource.html'><classname>JBossCacheSource</classname></ulink>">
+<!ENTITY InfinispanSource "<ulink url='&API;connector/infinispan/InfinispanSource.html'><classname>InfinispanSource</classname></ulink>">
<!ENTITY ImageMetadataSequencer "<ulink url='&API;sequencer/image/ImageMetadataSequencer.html'><classname>ImageMetadataSequencer</classname></ulink>">
<!ENTITY ImageMetadata "<ulink url='&API;sequencer/image/ImageMetadata.html'><classname>ImageMetadata</classname></ulink>">
<!ENTITY ImageSequencerI18n "<ulink url='&API;sequencer/image/ImageSequencerI18n.html'><classname>ImageSequencerI18n</classname></ulink>">
Modified: trunk/docs/reference/src/main/docbook/en-US/master.xml
===================================================================
--- trunk/docs/reference/src/main/docbook/en-US/master.xml 2009-07-12 22:01:21 UTC (rev 1089)
+++ trunk/docs/reference/src/main/docbook/en-US/master.xml 2009-07-12 22:08:43 UTC (rev 1090)
@@ -115,6 +115,7 @@
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="content/connectors/federation.xml"/>
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="content/connectors/subversion.xml"/>
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="content/connectors/jboss_cache.xml"/>
+ <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="content/connectors/infinispan.xml"/>
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="content/connectors/jdbc_metadata.xml"/>
</part>
<part id="provied-sequencers-part">
Added: trunk/extensions/dna-connector-infinispan/.classpath
===================================================================
--- trunk/extensions/dna-connector-infinispan/.classpath (rev 0)
+++ trunk/extensions/dna-connector-infinispan/.classpath 2009-07-12 22:08:43 UTC (rev 1090)
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src/main/java"/>
+ <classpathentry kind="src" path="src/main/resources"/>
+ <classpathentry kind="src" output="target/test-classes" path="src/test/java"/>
+ <classpathentry kind="src" output="target/test-classes" path="src/test/resources"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+ <classpathentry kind="con" path="org.maven.ide.eclipse.MAVEN2_CLASSPATH_CONTAINER"/>
+ <classpathentry kind="output" path="target/classes"/>
+</classpath>
Added: trunk/extensions/dna-connector-infinispan/.project
===================================================================
--- trunk/extensions/dna-connector-infinispan/.project (rev 0)
+++ trunk/extensions/dna-connector-infinispan/.project 2009-07-12 22:08:43 UTC (rev 1090)
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>dna-connector-infinispan</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.maven.ide.eclipse.maven2Builder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ <nature>org.maven.ide.eclipse.maven2Nature</nature>
+ </natures>
+</projectDescription>
Added: trunk/extensions/dna-connector-infinispan/pom.xml
===================================================================
--- trunk/extensions/dna-connector-infinispan/pom.xml (rev 0)
+++ trunk/extensions/dna-connector-infinispan/pom.xml 2009-07-12 22:08:43 UTC (rev 1090)
@@ -0,0 +1,97 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.jboss.dna</groupId>
+ <artifactId>dna</artifactId>
+ <version>0.6-SNAPSHOT</version>
+ <relativePath>../..</relativePath>
+ </parent>
+ <!-- The groupId and version values are inherited from parent -->
+ <artifactId>dna-connector-infinispan</artifactId>
+ <packaging>jar</packaging>
+ <name>JBoss DNA Connector to JBoss Infinispan</name>
+ <description>JBoss DNA Connector that accesses an in-process JBoss Infinispan instance.</description>
+ <url>http://labs.jboss.org/dna</url>
+
+ <!--
+ Define the dependencies. Note that all version and scopes default to those
+ defined in the dependencyManagement section of the parent pom.
+ -->
+ <dependencies>
+ <!--
+ Common
+ -->
+ <dependency>
+ <groupId>org.jboss.dna</groupId>
+ <artifactId>dna-common</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.dna</groupId>
+ <artifactId>dna-graph</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.dna</groupId>
+ <artifactId>dna-common</artifactId>
+ <version>${pom.version}</version>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.dna</groupId>
+ <artifactId>dna-graph</artifactId>
+ <version>${pom.version}</version>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+ <!--
+ JBoss Cache
+ -->
+ <dependency>
+ <groupId>org.infinispan</groupId>
+ <artifactId>infinispan-core</artifactId>
+ <version>4.0.0.ALPHA5</version>
+ </dependency>
+ <!--
+ Testing (note the scope)
+ -->
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-all</artifactId>
+ </dependency>
+ <!--
+ Logging (require SLF4J API for compiling, but use Log4J and its SLF4J binding for testing)
+ -->
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-log4j12</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>log4j</groupId>
+ <artifactId>log4j</artifactId>
+ </dependency>
+ <!--
+ Java Concurrency in Practice annotations
+ -->
+ <dependency>
+ <groupId>net.jcip</groupId>
+ <artifactId>jcip-annotations</artifactId>
+ </dependency>
+ </dependencies>
+ <reporting>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-report-plugin</artifactId>
+ </plugin>
+ </plugins>
+ </reporting>
+</project>
\ No newline at end of file
Property changes on: trunk/extensions/dna-connector-infinispan/pom.xml
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Added: trunk/extensions/dna-connector-infinispan/src/main/java/org/jboss/dna/connector/infinispan/InfinispanConnectorI18n.java
===================================================================
--- trunk/extensions/dna-connector-infinispan/src/main/java/org/jboss/dna/connector/infinispan/InfinispanConnectorI18n.java (rev 0)
+++ trunk/extensions/dna-connector-infinispan/src/main/java/org/jboss/dna/connector/infinispan/InfinispanConnectorI18n.java 2009-07-12 22:08:43 UTC (rev 1090)
@@ -0,0 +1,43 @@
+package org.jboss.dna.connector.infinispan;
+
+import java.util.Locale;
+import java.util.Set;
+import org.jboss.dna.common.i18n.I18n;
+
+public final class InfinispanConnectorI18n {
+
+ public static I18n connectorName;
+ public static I18n nodeDoesNotExist;
+ public static I18n propertyIsRequired;
+ public static I18n errorSerializingCachePolicyInSource;
+ public static I18n objectFoundInJndiWasNotCacheManager;
+ // public static I18n unableToCloneWorkspaces;
+ // public static I18n unableToCreateWorkspaces;
+ public static I18n unableToCreateWorkspace;
+ public static I18n workspaceAlreadyExists;
+ public static I18n workspaceDoesNotExist;
+ public static I18n workspaceNameWasNotValidConfiguration;
+ public static I18n defaultCacheManagerConfigurationNameWasNotValidConfiguration;
+
+
+ static {
+ try {
+ I18n.initialize(InfinispanConnectorI18n.class);
+ } catch (final Exception err) {
+ System.err.println(err);
+ }
+ }
+
+ public static Set<Locale> getLocalizationProblemLocales() {
+ return I18n.getLocalizationProblemLocales(InfinispanConnectorI18n.class);
+ }
+
+ public static Set<String> getLocalizationProblems() {
+ return I18n.getLocalizationProblems(InfinispanConnectorI18n.class);
+ }
+
+ public static Set<String> getLocalizationProblems( Locale locale ) {
+ return I18n.getLocalizationProblems(InfinispanConnectorI18n.class, locale);
+ }
+
+}
Property changes on: trunk/extensions/dna-connector-infinispan/src/main/java/org/jboss/dna/connector/infinispan/InfinispanConnectorI18n.java
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Added: trunk/extensions/dna-connector-infinispan/src/main/java/org/jboss/dna/connector/infinispan/InfinispanRepository.java
===================================================================
--- trunk/extensions/dna-connector-infinispan/src/main/java/org/jboss/dna/connector/infinispan/InfinispanRepository.java (rev 0)
+++ trunk/extensions/dna-connector-infinispan/src/main/java/org/jboss/dna/connector/infinispan/InfinispanRepository.java 2009-07-12 22:08:43 UTC (rev 1090)
@@ -0,0 +1,82 @@
+package org.jboss.dna.connector.infinispan;
+
+import java.util.UUID;
+import org.infinispan.Cache;
+import org.infinispan.manager.CacheManager;
+import org.jboss.dna.graph.ExecutionContext;
+import org.jboss.dna.graph.connector.map.AbstractMapWorkspace;
+import org.jboss.dna.graph.connector.map.MapNode;
+import org.jboss.dna.graph.connector.map.MapRepository;
+import org.jboss.dna.graph.connector.map.MapWorkspace;
+
+public class InfinispanRepository extends MapRepository {
+
+ private final CacheManager cacheManager;
+
+ public InfinispanRepository( String sourceName,
+ UUID rootNodeUuid,
+ CacheManager cacheManager ) {
+ super(sourceName, rootNodeUuid, null);
+ assert cacheManager != null;
+ this.cacheManager = cacheManager;
+ initialize();
+ }
+
+ public InfinispanRepository( String sourceName,
+ UUID rootNodeUuid,
+ String defaultWorkspaceName,
+ CacheManager cacheManager ) {
+ super(sourceName, rootNodeUuid, defaultWorkspaceName);
+
+ assert cacheManager != null;
+ this.cacheManager = cacheManager;
+
+ initialize();
+ }
+
+ @Override
+ protected MapWorkspace createWorkspace( ExecutionContext context,
+ String name ) {
+ assert name != null;
+ assert cacheManager != null;
+ Cache<UUID, MapNode> newWorkspaceCache = cacheManager.getCache(name);
+ return new Workspace(this, name, newWorkspaceCache);
+ }
+
+ protected class Workspace extends AbstractMapWorkspace {
+ private final Cache<UUID, MapNode> workspaceCache;
+
+ public Workspace( MapRepository repository,
+ String name,
+ Cache<UUID, MapNode> workspaceCache ) {
+ super(repository, name);
+
+ this.workspaceCache = workspaceCache;
+ initialize();
+ }
+
+ @Override
+ protected void addNodeToMap( MapNode node ) {
+ assert node != null;
+ workspaceCache.put(node.getUuid(), node);
+ }
+
+ @Override
+ protected MapNode removeNodeFromMap( UUID nodeUuid ) {
+ assert nodeUuid != null;
+ return workspaceCache.remove(nodeUuid);
+ }
+
+ @Override
+ protected void removeAllNodesFromMap() {
+ workspaceCache.clear();
+ }
+
+ @Override
+ public MapNode getNode( UUID nodeUuid ) {
+ assert nodeUuid != null;
+ return workspaceCache.get(nodeUuid);
+ }
+ }
+
+}
Property changes on: trunk/extensions/dna-connector-infinispan/src/main/java/org/jboss/dna/connector/infinispan/InfinispanRepository.java
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Added: 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 (rev 0)
+++ trunk/extensions/dna-connector-infinispan/src/main/java/org/jboss/dna/connector/infinispan/InfinispanSource.java 2009-07-12 22:08:43 UTC (rev 1090)
@@ -0,0 +1,555 @@
+/*
+ * 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.infinispan;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import javax.naming.BinaryRefAddr;
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+import javax.naming.RefAddr;
+import javax.naming.Reference;
+import javax.naming.Referenceable;
+import javax.naming.StringRefAddr;
+import javax.naming.spi.ObjectFactory;
+import net.jcip.annotations.ThreadSafe;
+import org.infinispan.Cache;
+import org.infinispan.manager.CacheManager;
+import org.infinispan.manager.DefaultCacheManager;
+import org.jboss.dna.common.i18n.I18n;
+import org.jboss.dna.common.util.StringUtil;
+import org.jboss.dna.graph.cache.CachePolicy;
+import org.jboss.dna.graph.connector.RepositoryConnection;
+import org.jboss.dna.graph.connector.RepositoryContext;
+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.map.MapRepositoryConnection;
+import org.jboss.dna.graph.connector.map.MapRepositorySource;
+import org.jboss.dna.graph.observe.Observer;
+import org.jboss.dna.graph.request.CreateWorkspaceRequest.CreateConflictBehavior;
+
+/**
+ * A repository source that uses an Infinispan instance to manage the content. This source is capable of using an existing
+ * {@link CacheManager} or creating a new cache manager. This process is controlled entirely by the JavaBean properties of the
+ * InfinispanSource instance.
+ * <p>
+ * This source first attempts to find an existing cache manager found in {@link #getCacheManagerJndiName() JNDI} (or the
+ * {@link DefaultCacheManager} if no such manager is available) and the {@link #getCacheConfigurationName() cache configuration
+ * name} if supplied or the default configuration if not set.
+ * </p>
+ * <p>
+ * Like other {@link RepositorySource} classes, instances of JBossCacheSource can be placed into JNDI and do support the creation
+ * of {@link Referenceable JNDI referenceable} objects and resolution of references into JBossCacheSource.
+ * </p>
+ */
+@ThreadSafe
+public class InfinispanSource implements MapRepositorySource, ObjectFactory {
+
+ private static final long serialVersionUID = 2L;
+ /**
+ * The default limit is {@value} for retrying {@link RepositoryConnection connection} calls to the underlying source.
+ */
+ public static final int DEFAULT_RETRY_LIMIT = 0;
+
+ /**
+ * 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 ROOT_NODE_UUID = "rootNodeUuid";
+ protected static final String SOURCE_NAME = "sourceName";
+ protected static final String DEFAULT_CACHE_POLICY = "defaultCachePolicy";
+ protected static final String CACHE_CONFIGURATION_NAME = "cacheConfigurationName";
+ protected static final String CACHE_FACTORY_JNDI_NAME = "cacheManagerJndiName";
+ protected static final String RETRY_LIMIT = "retryLimit";
+ protected static final String DEFAULT_WORKSPACE = "defaultWorkspace";
+ protected static final String PREDEFINED_WORKSPACE_NAMES = "predefinedWorkspaceNames";
+ protected static final String ALLOW_CREATING_WORKSPACES = "allowCreatingWorkspaces";
+
+ private volatile String name;
+ private volatile UUID rootNodeUuid = UUID.randomUUID();
+ private volatile CachePolicy defaultCachePolicy;
+ private volatile String cacheConfigurationName;
+ private volatile String cacheManagerJndiName;
+ private volatile int retryLimit = DEFAULT_RETRY_LIMIT;
+ private volatile String defaultWorkspace;
+ private volatile String[] predefinedWorkspaces = new String[] {};
+ private volatile RepositorySourceCapabilities capabilities = new RepositorySourceCapabilities(true, true, false, true, false);
+ private transient InfinispanRepository repository;
+ private transient Context jndiContext;
+ private transient RepositoryContext repositoryContext;
+
+ /**
+ * Create a repository source instance.
+ */
+ public InfinispanSource() {
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.graph.connector.RepositorySource#initialize(org.jboss.dna.graph.connector.RepositoryContext)
+ */
+ public void initialize( RepositoryContext context ) throws RepositorySourceException {
+ this.repositoryContext = context;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getName() {
+ return this.name;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.graph.connector.RepositorySource#getCapabilities()
+ */
+ public RepositorySourceCapabilities getCapabilities() {
+ return capabilities;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.graph.connector.RepositorySource#getRetryLimit()
+ */
+ public int getRetryLimit() {
+ return retryLimit;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.graph.connector.RepositorySource#setRetryLimit(int)
+ */
+ public synchronized void setRetryLimit( int limit ) {
+ retryLimit = limit < 0 ? 0 : limit;
+ }
+
+ /**
+ * Set the name of this source
+ *
+ * @param name the name for this source
+ */
+ public synchronized void setName( String name ) {
+ if (this.name == name || this.name != null && this.name.equals(name)) return; // unchanged
+ this.name = name;
+ }
+
+ /**
+ * Get the default cache policy for this source, or null if the global default cache policy should be used
+ *
+ * @return the default cache policy, or null if this source has no explicit default cache policy
+ */
+ public CachePolicy getDefaultCachePolicy() {
+ return defaultCachePolicy;
+ }
+
+ /**
+ * @param defaultCachePolicy Sets defaultCachePolicy to the specified value.
+ */
+ public synchronized void setDefaultCachePolicy( CachePolicy defaultCachePolicy ) {
+ if (this.defaultCachePolicy == defaultCachePolicy || this.defaultCachePolicy != null
+ && this.defaultCachePolicy.equals(defaultCachePolicy)) return; // unchanged
+ this.defaultCachePolicy = defaultCachePolicy;
+ }
+
+ /**
+ * Get the name in JNDI of a {@link CacheManager} instance that should be used to create the cache for this source.
+ * <p>
+ * This source first attempts to find a cache instance using the {@link CacheManager} found in
+ * {@link #getCacheManagerJndiName() JNDI} (or the {@link DefaultCacheManager} if no such manager is available) and the
+ * {@link #getCacheConfigurationName() cache configuration name} if supplied or the default configuration if not set.
+ * </p>
+ *
+ * @return the JNDI name of the {@link CacheManager} instance that should be used, or null if the {@link DefaultCacheManager}
+ * should be used if a cache is to be created
+ * @see #setCacheManagerJndiName(String)
+ * @see #getCacheConfigurationName()
+ */
+ public String getCacheManagerJndiName() {
+ return cacheManagerJndiName;
+ }
+
+ /**
+ * Set the name in JNDI of a {@link CacheManager} instance that should be used to obtain the {@link Cache} instance used by
+ * this source.
+ * <p>
+ * This source first attempts to find a cache instance using the {@link CacheManager} found in
+ * {@link #getCacheManagerJndiName() JNDI} (or the {@link DefaultCacheManager} if no such manager is available) and the
+ * {@link #getCacheConfigurationName() cache configuration name} if supplied or the default configuration if not set.
+ * </p>
+ *
+ * @param jndiName the JNDI name of the {@link CacheManager} instance that should be used, or null if the
+ * {@link DefaultCacheManager} should be used if a cache is to be created
+ * @see #setCacheManagerJndiName(String)
+ * @see #getCacheConfigurationName()
+ */
+ public synchronized void setCacheManagerJndiName( String jndiName ) {
+ if (this.cacheManagerJndiName == jndiName || this.cacheManagerJndiName != null
+ && this.cacheManagerJndiName.equals(jndiName)) return; // unchanged
+ this.cacheManagerJndiName = jndiName;
+ }
+
+ /**
+ * Get the name of the configuration that should be used if a {@link Cache cache} is to be created using the
+ * {@link CacheManager} found in JNDI or the {@link DefaultCacheManager} if needed.
+ * <p>
+ * This source first attempts to find a cache instance using the {@link CacheManager} found in
+ * {@link #getCacheManagerJndiName() JNDI} (or the {@link DefaultCacheManager} if no such manager is available) and the
+ * {@link #getCacheConfigurationName() cache configuration name} if supplied or the default configuration if not set.
+ * </p>
+ *
+ * @return the name of the configuration that should be passed to the {@link CacheManager}, or null if the default
+ * configuration should be used
+ * @see #setCacheConfigurationName(String)
+ * @see #getCacheManagerJndiName()
+ */
+ public String getCacheConfigurationName() {
+ return cacheConfigurationName;
+ }
+
+ /**
+ * Get the name of the configuration that should be used if a {@link Cache cache} is to be created using the
+ * {@link CacheManager} found in JNDI or the {@link DefaultCacheManager} if needed.
+ * <p>
+ * This source first attempts to find a cache instance using the {@link CacheManager} found in
+ * {@link #getCacheManagerJndiName() JNDI} (or the {@link DefaultCacheManager} if no such manager is available) and the
+ * {@link #getCacheConfigurationName() cache configuration name} if supplied or the default configuration if not set.
+ * </p>
+ *
+ * @param cacheConfigurationName the name of the configuration that should be passed to the {@link CacheManager}, or null if
+ * the default configuration should be used
+ * @see #getCacheConfigurationName()
+ * @see #getCacheManagerJndiName()
+ */
+ public synchronized void setCacheConfigurationName( String cacheConfigurationName ) {
+ if (this.cacheConfigurationName == cacheConfigurationName || this.cacheConfigurationName != null
+ && this.cacheConfigurationName.equals(cacheConfigurationName)) return; // unchanged
+ this.cacheConfigurationName = cacheConfigurationName;
+ }
+
+ /**
+ * Get the UUID of the root node for the cache. If the cache exists, this UUID is not used but is instead set to the UUID of
+ * the existing root node.
+ *
+ * @return the UUID of the root node for the cache.
+ */
+ public String getRootNodeUuid() {
+ return this.rootNodeUuid.toString();
+ }
+
+ /**
+ * Get the UUID of the root node for the cache. If the cache exists, this UUID is not used but is instead set to the UUID of
+ * the existing root node.
+ *
+ * @return the UUID of the root node for the cache.
+ */
+ public UUID getRootNodeUuidObject() {
+ return this.rootNodeUuid;
+ }
+
+ /**
+ * Set the UUID of the root node in this repository. If the cache exists, this UUID is not used but is instead set to the UUID
+ * of the existing root node.
+ *
+ * @param rootNodeUuid the UUID of the root node for the cache, or null if the UUID should be randomly generated
+ */
+ public synchronized void setRootNodeUuid( String rootNodeUuid ) {
+ UUID uuid = null;
+ if (rootNodeUuid == null) uuid = UUID.randomUUID();
+ else uuid = UUID.fromString(rootNodeUuid);
+ if (this.rootNodeUuid.equals(uuid)) return; // unchanged
+ this.rootNodeUuid = uuid;
+ }
+
+ /**
+ * 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 defaultWorkspace;
+ }
+
+ /**
+ * 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.defaultWorkspace = nameOfDefaultWorkspace != null ? nameOfDefaultWorkspace : DEFAULT_NAME_OF_DEFAULT_WORKSPACE;
+ }
+
+ /**
+ * Gets the names of the workspaces that are available when this source is created.
+ *
+ * @return the names of the workspaces that this source starts with, or null if there are no such workspaces
+ * @see #setPredefinedWorkspaceNames(String[])
+ * @see #setCreatingWorkspacesAllowed(boolean)
+ */
+ public synchronized String[] getPredefinedWorkspaceNames() {
+ String[] copy = new String[predefinedWorkspaces.length];
+ System.arraycopy(predefinedWorkspaces, 0, copy, 0, predefinedWorkspaces.length);
+ return copy;
+ }
+
+ /**
+ * Sets the names of the workspaces that are available when this source is created.
+ *
+ * @param predefinedWorkspaceNames the names of the workspaces that this source should start with, or null if there are no
+ * such workspaces
+ * @see #setCreatingWorkspacesAllowed(boolean)
+ * @see #getPredefinedWorkspaceNames()
+ */
+ public synchronized void setPredefinedWorkspaceNames( String[] predefinedWorkspaceNames ) {
+ this.predefinedWorkspaces = predefinedWorkspaceNames;
+ }
+
+ /**
+ * Get whether this source allows workspaces to be created dynamically.
+ *
+ * @return true if this source allows workspaces to be created by clients, or false if the
+ * {@link #getPredefinedWorkspaceNames() set of workspaces} is fixed
+ * @see #setPredefinedWorkspaceNames(String[])
+ * @see #getPredefinedWorkspaceNames()
+ * @see #setCreatingWorkspacesAllowed(boolean)
+ */
+ public boolean isCreatingWorkspacesAllowed() {
+ return capabilities.supportsCreatingWorkspaces();
+ }
+
+ /**
+ * Set whether this source allows workspaces to be created dynamically.
+ *
+ * @param allowWorkspaceCreation true if this source allows workspaces to be created by clients, or false if the
+ * {@link #getPredefinedWorkspaceNames() set of workspaces} is fixed
+ * @see #setPredefinedWorkspaceNames(String[])
+ * @see #getPredefinedWorkspaceNames()
+ * @see #isCreatingWorkspacesAllowed()
+ */
+ public synchronized void setCreatingWorkspacesAllowed( boolean allowWorkspaceCreation ) {
+ capabilities = new RepositorySourceCapabilities(true, capabilities.supportsUpdates(), false, allowWorkspaceCreation,
+ capabilities.supportsReferences());
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.graph.connector.RepositorySource#getConnection()
+ */
+ public synchronized RepositoryConnection getConnection() throws RepositorySourceException {
+ if (getName() == null) {
+ I18n msg = InfinispanConnectorI18n.propertyIsRequired;
+ throw new RepositorySourceException(getName(), msg.text("name"));
+ }
+ if (this.repository == null) {
+ Context context = getContext();
+ if (context == null) {
+ try {
+ context = new InitialContext();
+ } catch (NamingException err) {
+ throw new RepositorySourceException(name, err);
+ }
+ }
+
+ // Look for a cache manager in JNDI ...
+ CacheManager cacheManager = null;
+ String jndiName = getCacheManagerJndiName();
+ if (jndiName != null && jndiName.trim().length() != 0) {
+ Object object = null;
+ try {
+ object = context.lookup(jndiName);
+ if (object != null) cacheManager = (CacheManager)object;
+ } catch (ClassCastException err) {
+ I18n msg = InfinispanConnectorI18n.objectFoundInJndiWasNotCacheManager;
+ String className = object != null ? object.getClass().getName() : "null";
+ throw new RepositorySourceException(getName(), msg.text(jndiName, this.getName(), className), err);
+ } catch (Throwable err) {
+ if (err instanceof RuntimeException) throw (RuntimeException)err;
+ throw new RepositorySourceException(getName(), err);
+ }
+ }
+ if (cacheManager == null) cacheManager = new DefaultCacheManager();
+
+ // Now create the repository ...
+ this.repository = new InfinispanRepository(this.name, this.rootNodeUuid, this.defaultWorkspace, cacheManager);
+
+ // Create the set of initial names ...
+ for (String initialName : getPredefinedWorkspaceNames())
+ repository.createWorkspace(null, initialName, CreateConflictBehavior.DO_NOT_CREATE);
+
+ }
+
+ return new MapRepositoryConnection(this, this.repository);
+ }
+
+ /**
+ * @return repositoryContext
+ */
+ public RepositoryContext getRepositoryContext() {
+ return repositoryContext;
+ }
+
+ protected Observer getObserver() {
+ return repositoryContext != null ? repositoryContext.getObserver() : null;
+ }
+
+ protected Context getContext() {
+ return this.jndiContext;
+ }
+
+ protected synchronized void setContext( Context context ) {
+ this.jndiContext = context;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean equals( Object obj ) {
+ if (obj == this) return true;
+ if (obj instanceof InfinispanSource) {
+ InfinispanSource that = (InfinispanSource)obj;
+ if (this.getName() == null) {
+ if (that.getName() != null) return false;
+ } else {
+ if (!this.getName().equals(that.getName())) return false;
+ }
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public synchronized Reference getReference() {
+ String className = getClass().getName();
+ String managerClassName = this.getClass().getName();
+ Reference ref = new Reference(className, managerClassName, null);
+
+ ref.add(new StringRefAddr(SOURCE_NAME, getName()));
+ ref.add(new StringRefAddr(ROOT_NODE_UUID, getRootNodeUuid().toString()));
+ ref.add(new StringRefAddr(CACHE_FACTORY_JNDI_NAME, getCacheManagerJndiName()));
+ 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(ALLOW_CREATING_WORKSPACES, Boolean.toString(isCreatingWorkspacesAllowed())));
+ String[] workspaceNames = getPredefinedWorkspaceNames();
+ if (workspaceNames != null && workspaceNames.length != 0) {
+ ref.add(new StringRefAddr(PREDEFINED_WORKSPACE_NAMES, StringUtil.combineLines(workspaceNames)));
+ }
+ if (getDefaultCachePolicy() != null) {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ CachePolicy policy = getDefaultCachePolicy();
+ try {
+ ObjectOutputStream oos = new ObjectOutputStream(baos);
+ oos.writeObject(policy);
+ ref.add(new BinaryRefAddr(DEFAULT_CACHE_POLICY, baos.toByteArray()));
+ } catch (IOException e) {
+ I18n msg = InfinispanConnectorI18n.errorSerializingCachePolicyInSource;
+ throw new RepositorySourceException(getName(), msg.text(policy.getClass().getName(), getName()), e);
+ }
+ }
+ return ref;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Object getObjectInstance( Object obj,
+ javax.naming.Name name,
+ Context nameCtx,
+ Hashtable<?, ?> environment ) throws Exception {
+ if (obj instanceof Reference) {
+ Map<String, Object> values = new HashMap<String, Object>();
+ Reference ref = (Reference)obj;
+ Enumeration<?> en = ref.getAll();
+ while (en.hasMoreElements()) {
+ RefAddr subref = (RefAddr)en.nextElement();
+ if (subref instanceof StringRefAddr) {
+ String key = subref.getType();
+ Object value = subref.getContent();
+ if (value != null) values.put(key, value.toString());
+ } else if (subref instanceof BinaryRefAddr) {
+ String key = subref.getType();
+ Object value = subref.getContent();
+ if (value instanceof byte[]) {
+ // Deserialize ...
+ ByteArrayInputStream bais = new ByteArrayInputStream((byte[])value);
+ ObjectInputStream ois = new ObjectInputStream(bais);
+ value = ois.readObject();
+ values.put(key, value);
+ }
+ }
+ }
+ String sourceName = (String)values.get(SOURCE_NAME);
+ String rootNodeUuidString = (String)values.get(ROOT_NODE_UUID);
+ String cacheManagerJndiName = (String)values.get(CACHE_FACTORY_JNDI_NAME);
+ String cacheConfigurationName = (String)values.get(CACHE_CONFIGURATION_NAME);
+ Object defaultCachePolicy = values.get(DEFAULT_CACHE_POLICY);
+ String retryLimit = (String)values.get(RETRY_LIMIT);
+ String defaultWorkspace = (String)values.get(DEFAULT_WORKSPACE);
+ String createWorkspaces = (String)values.get(ALLOW_CREATING_WORKSPACES);
+
+ String combinedWorkspaceNames = (String)values.get(PREDEFINED_WORKSPACE_NAMES);
+ String[] workspaceNames = null;
+ if (combinedWorkspaceNames != null) {
+ List<String> paths = StringUtil.splitLines(combinedWorkspaceNames);
+ workspaceNames = paths.toArray(new String[paths.size()]);
+ }
+
+ // Create the source instance ...
+ InfinispanSource source = new InfinispanSource();
+ if (sourceName != null) source.setName(sourceName);
+ if (rootNodeUuidString != null) source.setRootNodeUuid(rootNodeUuidString);
+ if (cacheManagerJndiName != null) source.setCacheManagerJndiName(cacheManagerJndiName);
+ if (cacheConfigurationName != null) source.setCacheConfigurationName(cacheConfigurationName);
+ if (defaultCachePolicy instanceof CachePolicy) {
+ source.setDefaultCachePolicy((CachePolicy)defaultCachePolicy);
+ }
+ if (retryLimit != null) source.setRetryLimit(Integer.parseInt(retryLimit));
+ 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;
+ }
+ return null;
+ }
+}
Property changes on: trunk/extensions/dna-connector-infinispan/src/main/java/org/jboss/dna/connector/infinispan/InfinispanSource.java
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Added: trunk/extensions/dna-connector-infinispan/src/main/resources/org/jboss/dna/connector/infinispan/InfinispanConnectorI18n.properties
===================================================================
--- trunk/extensions/dna-connector-infinispan/src/main/resources/org/jboss/dna/connector/infinispan/InfinispanConnectorI18n.properties (rev 0)
+++ trunk/extensions/dna-connector-infinispan/src/main/resources/org/jboss/dna/connector/infinispan/InfinispanConnectorI18n.properties 2009-07-12 22:08:43 UTC (rev 1090)
@@ -0,0 +1,36 @@
+#
+# 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.
+#
+
+connectorName = Infinispan Connector
+nodeDoesNotExist = Could not find an existing node at {0}
+propertyIsRequired = The {0} property is required but has no value
+errorSerializingCachePolicyInSource = Error serializing a {0} instance owned by the {1} InfinispanSource
+objectFoundInJndiWasNotCacheManager = Object in JNDI at {0} found by InfinispanSource {1} was expected to be a org.infinispan.CacheManager but instead was {2}
+#unableToCloneWorkspaces = The InfinispanSource {0} does not allow creating workspaces, so unable to clone workspace "{1}" into "{2}"
+#unableToCreateWorkspaces = The InfinispanSource {0} does not allow creating workspaces, so unable to create workspace "{1}"
+unableToCreateWorkspace = Unable to create new workspace "{1}" in the InfinispanSource {0}
+workspaceAlreadyExists = The workspace "{1}" already exists in the InfinispanSource {0}
+workspaceDoesNotExist = The workspace "{1}" does not exist in the InfinispanSource {0}
+workspaceNameWasNotValidConfiguration = The workspace name "{0}" was not a valid Infinispan Cache Manager configuration name: {1}
+defaultCacheManagerConfigurationNameWasNotValidConfiguration = "{0}" is not a valid Infinispan Cache Manager configuration name
Added: trunk/extensions/dna-connector-infinispan/src/test/java/org/jboss/dna/connector/infinispan/InfinispanConnectorI18nTest.java
===================================================================
--- trunk/extensions/dna-connector-infinispan/src/test/java/org/jboss/dna/connector/infinispan/InfinispanConnectorI18nTest.java (rev 0)
+++ trunk/extensions/dna-connector-infinispan/src/test/java/org/jboss/dna/connector/infinispan/InfinispanConnectorI18nTest.java 2009-07-12 22:08:43 UTC (rev 1090)
@@ -0,0 +1,36 @@
+/*
+ * 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.infinispan;
+
+import org.jboss.dna.common.AbstractI18nTest;
+
+/**
+ * @author Randall Hauch
+ */
+public class InfinispanConnectorI18nTest extends AbstractI18nTest {
+
+ public InfinispanConnectorI18nTest() {
+ super(InfinispanConnectorI18n.class);
+ }
+}
Property changes on: trunk/extensions/dna-connector-infinispan/src/test/java/org/jboss/dna/connector/infinispan/InfinispanConnectorI18nTest.java
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Added: trunk/extensions/dna-connector-infinispan/src/test/java/org/jboss/dna/connector/infinispan/InfinispanConnectorReadableTest.java
===================================================================
--- trunk/extensions/dna-connector-infinispan/src/test/java/org/jboss/dna/connector/infinispan/InfinispanConnectorReadableTest.java (rev 0)
+++ trunk/extensions/dna-connector-infinispan/src/test/java/org/jboss/dna/connector/infinispan/InfinispanConnectorReadableTest.java 2009-07-12 22:08:43 UTC (rev 1090)
@@ -0,0 +1,58 @@
+package org.jboss.dna.connector.infinispan;
+
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.stub;
+import java.io.File;
+import java.io.IOException;
+import javax.naming.Context;
+import javax.naming.NamingException;
+import org.jboss.dna.graph.Graph;
+import org.jboss.dna.graph.connector.RepositorySource;
+import org.jboss.dna.graph.connector.test.ReadableConnectorTest;
+import org.xml.sax.SAXException;
+
+public class InfinispanConnectorReadableTest extends ReadableConnectorTest {
+
+ private Context mockJndi;
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.graph.connector.test.AbstractConnectorTest#setUpSource()
+ */
+ @Override
+ protected RepositorySource setUpSource() throws NamingException {
+ // Set the connection properties to be use the content of "./src/test/resources/repositories" as a repository ...
+ String[] predefinedWorkspaceNames = new String[] {"aircraft", "cars"};
+ InfinispanSource source = new InfinispanSource();
+ source.setName("Test Repository");
+ source.setPredefinedWorkspaceNames(predefinedWorkspaceNames);
+ source.setDefaultWorkspaceName(predefinedWorkspaceNames[0]);
+ source.setCreatingWorkspacesAllowed(false);
+
+ // Set up the mock JNDI ...
+ mockJndi = mock(Context.class);
+ stub(mockJndi.lookup(anyString())).toReturn(null);
+ source.setContext(mockJndi);
+
+ return source;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @throws SAXException
+ * @throws IOException
+ * @see org.jboss.dna.graph.connector.test.AbstractConnectorTest#initializeContent(org.jboss.dna.graph.Graph)
+ */
+ @Override
+ protected void initializeContent( Graph graph ) throws IOException, SAXException {
+ graph.useWorkspace("aircraft");
+ graph.importXmlFrom(new File("src/test/resources/aircraft.xml")).into("/");
+
+ graph.useWorkspace("cars");
+ graph.importXmlFrom(new File("src/test/resources/cars.xml")).into("/");
+ }
+
+}
Property changes on: trunk/extensions/dna-connector-infinispan/src/test/java/org/jboss/dna/connector/infinispan/InfinispanConnectorReadableTest.java
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Added: trunk/extensions/dna-connector-infinispan/src/test/java/org/jboss/dna/connector/infinispan/InfinispanConnectorWritableTest.java
===================================================================
--- trunk/extensions/dna-connector-infinispan/src/test/java/org/jboss/dna/connector/infinispan/InfinispanConnectorWritableTest.java (rev 0)
+++ trunk/extensions/dna-connector-infinispan/src/test/java/org/jboss/dna/connector/infinispan/InfinispanConnectorWritableTest.java 2009-07-12 22:08:43 UTC (rev 1090)
@@ -0,0 +1,53 @@
+package org.jboss.dna.connector.infinispan;
+
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.stub;
+import java.io.IOException;
+import javax.naming.Context;
+import javax.naming.NamingException;
+import org.jboss.dna.graph.Graph;
+import org.jboss.dna.graph.connector.RepositorySource;
+import org.jboss.dna.graph.connector.test.WritableConnectorTest;
+import org.xml.sax.SAXException;
+
+public class InfinispanConnectorWritableTest extends WritableConnectorTest {
+
+ private Context mockJndi;
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.graph.connector.test.AbstractConnectorTest#setUpSource()
+ */
+ @Override
+ protected RepositorySource setUpSource() throws NamingException {
+ String[] predefinedWorkspaceNames = new String[] {"default"};
+ InfinispanSource source = new InfinispanSource();
+ source.setName("Test Repository");
+ source.setPredefinedWorkspaceNames(predefinedWorkspaceNames);
+ source.setDefaultWorkspaceName(predefinedWorkspaceNames[0]);
+ source.setCreatingWorkspacesAllowed(true);
+
+ // Set up the mock JNDI ...
+ mockJndi = mock(Context.class);
+ stub(mockJndi.lookup(anyString())).toReturn(null);
+ source.setContext(mockJndi);
+
+ Graph graph = Graph.create(source, context);
+ graph.useWorkspace("default");
+
+ return source;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @throws SAXException
+ * @throws IOException
+ * @see org.jboss.dna.graph.connector.test.AbstractConnectorTest#initializeContent(org.jboss.dna.graph.Graph)
+ */
+ @Override
+ protected void initializeContent( Graph graph ) throws IOException, SAXException {
+ }
+}
Property changes on: trunk/extensions/dna-connector-infinispan/src/test/java/org/jboss/dna/connector/infinispan/InfinispanConnectorWritableTest.java
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Added: trunk/extensions/dna-connector-infinispan/src/test/java/org/jboss/dna/connector/infinispan/InfinispanSourceTest.java
===================================================================
--- trunk/extensions/dna-connector-infinispan/src/test/java/org/jboss/dna/connector/infinispan/InfinispanSourceTest.java (rev 0)
+++ trunk/extensions/dna-connector-infinispan/src/test/java/org/jboss/dna/connector/infinispan/InfinispanSourceTest.java 2009-07-12 22:08:43 UTC (rev 1090)
@@ -0,0 +1,218 @@
+/*
+ * 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.infinispan;
+
+import static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.IsNull.notNullValue;
+import static org.hamcrest.core.IsNull.nullValue;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.stub;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.UUID;
+import java.util.concurrent.TimeUnit;
+import javax.naming.Context;
+import javax.naming.Name;
+import javax.naming.RefAddr;
+import javax.naming.Reference;
+import javax.naming.spi.ObjectFactory;
+import org.infinispan.manager.CacheManager;
+import org.jboss.dna.graph.cache.BasicCachePolicy;
+import org.jboss.dna.graph.connector.RepositoryConnection;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.MockitoAnnotations;
+import org.mockito.MockitoAnnotations.Mock;
+
+/**
+ */
+public class InfinispanSourceTest {
+
+ private InfinispanSource source;
+ private RepositoryConnection connection;
+ private String validName;
+ private String validCacheConfigurationName;
+ private String validCacheManagerJndiName;
+ private UUID validRootNodeUuid;
+ @Mock
+ private Context jndiContext;
+ @Mock
+ private CacheManager cacheManager;
+
+ @Before
+ public void beforeEach() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ validName = "cache source";
+ validCacheConfigurationName = "cache config name";
+ validCacheManagerJndiName = "cache factory jndi name";
+ validRootNodeUuid = UUID.randomUUID();
+ source = new InfinispanSource();
+
+ // Set up the fake JNDI context ...
+ source.setContext(jndiContext);
+ stub(jndiContext.lookup(validCacheManagerJndiName)).toReturn(cacheManager);
+ }
+
+ @After
+ public void afterEach() throws Exception {
+ if (connection != null) {
+ connection.close();
+ }
+ }
+
+ @Test
+ public void shouldReturnNonNullCapabilities() {
+ assertThat(source.getCapabilities(), is(notNullValue()));
+ }
+
+ @Test
+ public void shouldSupportSameNameSiblings() {
+ assertThat(source.getCapabilities().supportsSameNameSiblings(), is(true));
+ }
+
+ @Test
+ public void shouldSupportUpdates() {
+ assertThat(source.getCapabilities().supportsUpdates(), is(true));
+ }
+
+ @Test
+ public void shouldHaveNullSourceNameUponConstruction() {
+ source = new InfinispanSource();
+ assertThat(source.getName(), is(nullValue()));
+ }
+
+ @Test
+ public void shouldAllowSettingName() {
+ source.setName("Something");
+ assertThat(source.getName(), is("Something"));
+ source.setName("another name");
+ assertThat(source.getName(), is("another name"));
+ }
+
+ @Test
+ public void shouldAllowSettingNameToNull() {
+ source.setName("some name");
+ source.setName(null);
+ assertThat(source.getName(), is(nullValue()));
+ }
+
+ @Test
+ public void shouldHaveDefaultRetryLimit() {
+ assertThat(source.getRetryLimit(), is(InfinispanSource.DEFAULT_RETRY_LIMIT));
+ }
+
+ @Test
+ public void shouldSetRetryLimitToZeroWhenSetWithNonPositiveValue() {
+ source.setRetryLimit(0);
+ assertThat(source.getRetryLimit(), is(0));
+ source.setRetryLimit(-1);
+ assertThat(source.getRetryLimit(), is(0));
+ source.setRetryLimit(-100);
+ assertThat(source.getRetryLimit(), is(0));
+ }
+
+ @Test
+ public void shouldAllowRetryLimitToBeSet() {
+ for (int i = 0; i != 100; ++i) {
+ source.setRetryLimit(i);
+ assertThat(source.getRetryLimit(), is(i));
+ }
+ }
+
+ @Test
+ public void shouldCreateJndiReferenceAndRecreatedObjectFromReference() throws Exception {
+ BasicCachePolicy cachePolicy = new BasicCachePolicy();
+ cachePolicy.setTimeToLive(1000L, TimeUnit.MILLISECONDS);
+ convertToAndFromJndiReference(validName,
+ validRootNodeUuid,
+ validCacheConfigurationName,
+ validCacheManagerJndiName,
+ cachePolicy,
+ 100);
+ }
+
+ @Test
+ public void shouldCreateJndiReferenceAndRecreatedObjectFromReferenceWithNullProperties() throws Exception {
+ BasicCachePolicy cachePolicy = new BasicCachePolicy();
+ cachePolicy.setTimeToLive(1000L, TimeUnit.MILLISECONDS);
+ convertToAndFromJndiReference("some source", null, null, null, null, 100);
+ convertToAndFromJndiReference(null, null, null, null, null, 100);
+ }
+
+ private void convertToAndFromJndiReference( String sourceName,
+ UUID rootNodeUuid,
+ String cacheConfigName,
+ String cacheManagerJndiName,
+ BasicCachePolicy cachePolicy,
+ int retryLimit ) throws Exception {
+ source.setRetryLimit(retryLimit);
+ source.setName(sourceName);
+ source.setCacheConfigurationName(cacheConfigName);
+ source.setCacheManagerJndiName(cacheManagerJndiName);
+ source.setDefaultCachePolicy(cachePolicy);
+ source.setRootNodeUuid(rootNodeUuid != null ? rootNodeUuid.toString() : null);
+
+ Reference ref = source.getReference();
+ assertThat(ref.getClassName(), is(InfinispanSource.class.getName()));
+ assertThat(ref.getFactoryClassName(), is(InfinispanSource.class.getName()));
+
+ Map<String, Object> refAttributes = new HashMap<String, Object>();
+ Enumeration<RefAddr> enumeration = ref.getAll();
+ while (enumeration.hasMoreElements()) {
+ RefAddr addr = enumeration.nextElement();
+ refAttributes.put(addr.getType(), addr.getContent());
+ }
+
+ // Recreate the object, use a newly constructed source ...
+ ObjectFactory factory = new InfinispanSource();
+ Name name = mock(Name.class);
+ Context context = mock(Context.class);
+ Hashtable<?, ?> env = new Hashtable<Object, Object>();
+ InfinispanSource recoveredSource = (InfinispanSource)factory.getObjectInstance(ref, name, context, env);
+ assertThat(recoveredSource, is(notNullValue()));
+
+ assertThat(recoveredSource.getName(), is(source.getName()));
+ assertThat(recoveredSource.getRootNodeUuid(), is(source.getRootNodeUuid()));
+ assertThat(recoveredSource.getRetryLimit(), is(source.getRetryLimit()));
+ assertThat(recoveredSource.getCacheManagerJndiName(), is(source.getCacheManagerJndiName()));
+ assertThat(recoveredSource.getCacheConfigurationName(), is(source.getCacheConfigurationName()));
+ assertThat(recoveredSource.getDefaultCachePolicy(), is(source.getDefaultCachePolicy()));
+
+ assertThat(recoveredSource.equals(source), is(true));
+ assertThat(source.equals(recoveredSource), is(true));
+ }
+
+ @Test
+ public void shouldCreateCacheUsingDefaultCacheManagerWhenNoCacheOrCacheManagerOrCacheConfigurationNameIsFound()
+ throws Exception {
+ source.setName(validName);
+ connection = source.getConnection();
+ assertThat(connection, is(notNullValue()));
+ // assertThat(connection.getCache(), is(notNullValue()));
+ }
+}
Property changes on: trunk/extensions/dna-connector-infinispan/src/test/java/org/jboss/dna/connector/infinispan/InfinispanSourceTest.java
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Added: trunk/extensions/dna-connector-infinispan/src/test/resources/aircraft.xml
===================================================================
--- trunk/extensions/dna-connector-infinispan/src/test/resources/aircraft.xml (rev 0)
+++ trunk/extensions/dna-connector-infinispan/src/test/resources/aircraft.xml 2009-07-12 22:08:43 UTC (rev 1090)
@@ -0,0 +1,54 @@
+<?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
+ -->
+<Aircraft xmlns:jcr="http://www.jcp.org/jcr/1.0">
+ <Business>
+ <aircraft jcr:name="Gulfstream V" maker="Gulfstream" model="G-V" introduced="1995" range="5800nm" cruiseSpeed="488kt" crew="2" emptyWeight="46200lb" url="http://en.wikipedia.org/wiki/Gulfstream_V"/>
+ <aircraft jcr:name="Learjet 45" maker="Learjet" model="LJ45" introduced="1995" numberBuilt="264+" crew="2" emptyWeight="13695lb" range="2120nm" cruiseSpeed="457kt" url="http://en.wikipedia.org/wiki/Learjet_45"/>
+ </Business>
+ <Commercial>
+ <aircraft jcr:name="Boeing 777" maker="Boeing" model="777-200LR" introduced="1995" numberBuilt="731+" maxRange="7500nm" emptyWeight="326000lb" cruiseSpeed="560mph" url="http://en.wikipedia.org/wiki/Boeing_777"/>
+ <aircraft jcr:name="Boeing 767" maker="Boeing" model="767-200" introduced="1982" numberBuilt="966+" maxRange="3950nm" emptyWeight="176650lb" cruiseSpeed="530mph" url="http://en.wikipedia.org/wiki/Boeing_767"/>
+ <aircraft jcr:name="Boeing 787" maker="Boeing" model="787-3" introduced="2009" range="3050nm" emptyWeight="223000lb" cruiseSpeed="561mph" url="http://en.wikipedia.org/wiki/Boeing_787"/>
+ <aircraft jcr:name="Boeing 757" maker="Boeing" model="757-200" introduced="1983" numberBuilt="1050" range="3900nm" maxWeight="255000lb" cruiseSpeed="530mph" url="http://en.wikipedia.org/wiki/Boeing_757"/>
+ <aircraft jcr:name="Airbus A380" maker="Airbus" model="A380-800" introduced="2007" numberBuilt="18" range="8200nm" maxWeight="1235000lb" cruiseSpeed="647mph" url="http://en.wikipedia.org/wiki/Airbus_a380"/>
+ <aircraft jcr:name="Airbus A340" maker="Airbus" model="A340-200" introduced="1993" numberBuilt="354" range="8000nm" maxWeight="606300lb" cruiseSpeed="557mph" url="http://en.wikipedia.org/wiki/Airbus_A-340"/>
+ <aircraft jcr:name="Airbus A310" maker="Airbus" model="A310-200" introduced="1983" numberBuilt="255" cruiseSpeed="850km/h" emptyWeight="176312lb" range="3670nm" url="http://en.wikipedia.org/wiki/Airbus_A-310"/>
+ <aircraft jcr:name="Embraer RJ-175" maker="Embraer" model="ERJ170-200" introduced="2004" range="3334km" cruiseSpeed="481kt" emptyWeight="21810kg" url="http://en.wikipedia.org/wiki/EMBRAER_170"/>
+ </Commercial>
+ <Vintage>
+ <aircraft jcr:name="Fokker Trimotor" maker="Fokker" model="F.VII" introduced="1925" cruiseSpeed="170km/h" emptyWeight="3050kg" crew="2" url="http://en.wikipedia.org/wiki/Fokker_trimotor"/>
+ <aircraft jcr:name="P-38 Lightning" maker="Lockheed" model="P-38" designedBy="Kelly Johnson" introduced="1941" numberBuilt="10037" rateOfClimb="4750ft/min" range="1300mi" emptyWeight="12780lb" crew="1" url="http://en.wikipedia.org/wiki/P-38_Lightning"/>
+ <aircraft jcr:name="A6M Zero" maker="Mitsubishi" model="A6M" designedBy="Jiro Horikoshi" introduced="1940" numberBuilt="11000" crew="1" emptyWeight="3704lb" serviceCeiling="33000ft" maxSpeed="331mph" range="1929mi" rateOfClimb="3100ft/min" url="http://en.wikipedia.org/wiki/A6M_Zero"/>
+ <aircraft jcr:name="Bf 109" maker="Messerschmitt" model="Bf 109" introduced="1937" url="http://en.wikipedia.org/wiki/BF_109"/>
+ <aircraft jcr:name="Wright Flyer" maker="Wright Brothers" introduced="1903" range="852ft" maxSpeed="30mph" emptyWeight="605lb" crew="1"/>
+ </Vintage>
+ <Homebuilt>
+ <aircraft jcr:name="Long-EZ" maker="Rutan Aircraft Factory" model="61" emptyWeight="760lb" fuelCapacity="200L" maxSpeed="185kt" since="1976" range="1200nm" url="http://en.wikipedia.org/wiki/Rutan_Long-EZ"/>
+ <aircraft jcr:name="Cirrus VK-30" maker="Cirrus Design" model="VK-30" emptyWeight="2400lb" maxLoad="1200lb" maxSpeed="250mph" rateOfClimb="1500ft/min" range="1300mi" url="http://en.wikipedia.org/wiki/Cirrus_VK-30"/>
+ <aircraft jcr:name="Van's RV-4" maker="Van's Aircraft" model="RV-4" introduced="1980" emptyWeight="905lb" maxLoad="500lb" maxSpeed="200mph" rateOfClimb="2450ft/min" range="725mi" url="http://en.wikipedia.org/wiki/Van%27s_Aircraft_RV-4"/>
+ </Homebuilt>
+</Aircraft>
\ No newline at end of file
Property changes on: trunk/extensions/dna-connector-infinispan/src/test/resources/aircraft.xml
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Added: trunk/extensions/dna-connector-infinispan/src/test/resources/cars.xml
===================================================================
--- trunk/extensions/dna-connector-infinispan/src/test/resources/cars.xml (rev 0)
+++ trunk/extensions/dna-connector-infinispan/src/test/resources/cars.xml 2009-07-12 22:08:43 UTC (rev 1090)
@@ -0,0 +1,48 @@
+<?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
+ -->
+<Cars xmlns:jcr="http://www.jcp.org/jcr/1.0">
+ <Hybrid>
+ <car jcr:name="Toyota Prius" maker="Toyota" model="Prius" year="2008" msrp="$21,500" userRating="4.2" valueRating="5" mpgCity="48" mpgHighway="45"/>
+ <car jcr:name="Toyota Highlander" maker="Toyota" model="Highlander" year="2008" msrp="$34,200" userRating="4" valueRating="5" mpgCity="27" mpgHighway="25"/>
+ <car jcr:name="Nissan Altima" maker="Nissan" model="Altima" year="2008" msrp="$18,260" mpgCity="23" mpgHighway="32"/>
+ </Hybrid>
+ <Sports>
+ <car jcr:name="Aston Martin DB9" maker="Aston Martin" model="DB9" year="2008" msrp="$171,600" userRating="5" mpgCity="12" mpgHighway="19" lengthInInches="185.5" wheelbaseInInches="108.0" engine="5,935 cc 5.9 liters V 12"/>
+ <car jcr:name="Infiniti G37" maker="Infiniti" model="G37" year="2008" msrp="$34,900" userRating="3.5" valueRating="4" mpgCity="18" mpgHighway="24" />
+ </Sports>
+ <Luxury>
+ <car jcr:name="Cadillac DTS" maker="Cadillac" model="DTS" year="2008" engine="3.6-liter V6" userRating="0"/>
+ <car jcr:name="Bentley Continental" maker="Bentley" model="Continental" year="2008" msrp="$170,990" mpgCity="10" mpgHighway="17" />
+ <car jcr:name="Lexus IS350" maker="Lexus" model="IS350" year="2008" msrp="$36,305" mpgCity="18" mpgHighway="25" userRating="4" valueRating="5" />
+ </Luxury>
+ <Utility>
+ <car jcr:name="Land Rover LR2" maker="Land Rover" model="LR2" year="2008" msrp="$33,985" userRating="4.5" valueRating="5" mpgCity="16" mpgHighway="23" />
+ <car jcr:name="Land Rover LR3" maker="Land Rover" model="LR3" year="2008" msrp="$48,525" userRating="5" valueRating="2" mpgCity="12" mpgHighway="17" />
+ <car jcr:name="Hummer H3" maker="Hummer" model="H3" year="2008" msrp="$30,595" userRating="3.5" valueRating="4" mpgCity="13" mpgHighway="16" />
+ <car jcr:name="Ford F-150" maker="Ford" model="F-150" year="2008" msrp="$23,910" userRating="4" valueRating="1" mpgCity="14" mpgHighway="20" />
+ </Utility>
+</Cars>
\ No newline at end of file
Property changes on: trunk/extensions/dna-connector-infinispan/src/test/resources/cars.xml
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Added: trunk/extensions/dna-connector-infinispan/src/test/resources/log4j.properties
===================================================================
--- trunk/extensions/dna-connector-infinispan/src/test/resources/log4j.properties (rev 0)
+++ trunk/extensions/dna-connector-infinispan/src/test/resources/log4j.properties 2009-07-12 22:08:43 UTC (rev 1090)
@@ -0,0 +1,15 @@
+# Direct log messages to stdout
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.Target=System.out
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %m%n
+
+# Root logger option
+log4j.rootLogger=INFO, stdout
+
+# Set up the default logging to be INFO level, then override specific units
+log4j.logger.org.jboss.dna=INFO
+
+# JBoss Cache logging
+log4j.logger.org.infinispan=WARN, stdout
+
Modified: trunk/pom.xml
===================================================================
--- trunk/pom.xml 2009-07-12 22:01:21 UTC (rev 1089)
+++ trunk/pom.xml 2009-07-12 22:08:43 UTC (rev 1090)
@@ -137,6 +137,7 @@
<module>extensions/dna-sequencer-zip</module>
<module>extensions/dna-connector-federation</module>
<module>extensions/dna-connector-filesystem</module>
+ <module>extensions/dna-connector-infinispan</module>
<module>extensions/dna-connector-jbosscache</module>
<module>extensions/dna-connector-svn</module>
<module>extensions/dna-connector-store-jpa</module>
@@ -596,7 +597,7 @@
</plugin>
</plugins>
</reporting>
-
+
<repositories>
<repository>
<id>apiviz.release</id>
16 years, 6 months
DNA SVN: r1089 - in trunk/extensions/dna-connector-jbosscache/src: test/java/org/jboss/dna/connector/jbosscache and 1 other directory.
by dna-commits@lists.jboss.org
Author: bcarothers
Date: 2009-07-12 18:01:21 -0400 (Sun, 12 Jul 2009)
New Revision: 1089
Modified:
trunk/extensions/dna-connector-jbosscache/src/main/java/org/jboss/dna/connector/jbosscache/JBossCacheSource.java
trunk/extensions/dna-connector-jbosscache/src/test/java/org/jboss/dna/connector/jbosscache/JBossCacheConnectorReadableTest.java
trunk/extensions/dna-connector-jbosscache/src/test/java/org/jboss/dna/connector/jbosscache/JBossCacheConnectorWritableTest.java
Log:
DNA-485 Standardize Default Workspace Name Property Across Sources
Applied patch that renames the Java bean property nameOfDefaultWorkspace on JBossCacheSource to defaultWorkspaceName to adhere to the implicit standard set by InMemoryRepositorySource. Since the Infinispan connector has not yet been committed, the corresponding fix will be committed with the initial check-in for that connector.
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-07-12 21:08:48 UTC (rev 1088)
+++ trunk/extensions/dna-connector-jbosscache/src/main/java/org/jboss/dna/connector/jbosscache/JBossCacheSource.java 2009-07-12 22:01:21 UTC (rev 1089)
@@ -95,7 +95,7 @@
public static final String DEFAULT_UUID_PROPERTY_NAME = DnaLexicon.UUID.getString();
/**
- * The initial {@link #getNameOfDefaultWorkspace() name of the default workspace} is "{@value} ", unless otherwise specified.
+ * The initial {@link #getDefaultWorkspaceName() name of the default workspace} is "{@value} ", unless otherwise specified.
*/
public static final String DEFAULT_NAME_OF_DEFAULT_WORKSPACE = "default";
@@ -365,7 +365,7 @@
*
* @return the name of the workspace that should be used by default; never null
*/
- public String getNameOfDefaultWorkspace() {
+ public String getDefaultWorkspaceName() {
return defaultWorkspace;
}
@@ -375,7 +375,7 @@
* @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 setNameOfDefaultWorkspace( String nameOfDefaultWorkspace ) {
+ public synchronized void setDefaultWorkspaceName( String nameOfDefaultWorkspace ) {
this.defaultWorkspace = nameOfDefaultWorkspace != null ? nameOfDefaultWorkspace : DEFAULT_NAME_OF_DEFAULT_WORKSPACE;
}
@@ -472,7 +472,8 @@
if (cacheFactory == null) cacheFactory = new DefaultCacheFactory<UUID, MapNode>();
// Now create the repository ...
- this.repository = new JBossCacheRepository(getName(), this.rootNodeUuid, createNewCache(cacheFactory, getName()));
+ this.repository = new JBossCacheRepository(getName(), this.rootNodeUuid, this.defaultWorkspace,
+ createNewCache(cacheFactory, getName()));
// Create the set of initial names ...
for (String initialName : getPredefinedWorkspaceNames())
@@ -576,7 +577,7 @@
ref.add(new StringRefAddr(CACHE_FACTORY_JNDI_NAME, getCacheFactoryJndiName()));
ref.add(new StringRefAddr(CACHE_CONFIGURATION_NAME, getCacheConfigurationName()));
ref.add(new StringRefAddr(RETRY_LIMIT, Integer.toString(getRetryLimit())));
- ref.add(new StringRefAddr(DEFAULT_WORKSPACE, getNameOfDefaultWorkspace()));
+ 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) {
@@ -654,7 +655,7 @@
source.setDefaultCachePolicy((CachePolicy)defaultCachePolicy);
}
if (retryLimit != null) source.setRetryLimit(Integer.parseInt(retryLimit));
- if (defaultWorkspace != null) source.setNameOfDefaultWorkspace(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;
Modified: trunk/extensions/dna-connector-jbosscache/src/test/java/org/jboss/dna/connector/jbosscache/JBossCacheConnectorReadableTest.java
===================================================================
--- trunk/extensions/dna-connector-jbosscache/src/test/java/org/jboss/dna/connector/jbosscache/JBossCacheConnectorReadableTest.java 2009-07-12 21:08:48 UTC (rev 1088)
+++ trunk/extensions/dna-connector-jbosscache/src/test/java/org/jboss/dna/connector/jbosscache/JBossCacheConnectorReadableTest.java 2009-07-12 22:01:21 UTC (rev 1089)
@@ -54,7 +54,7 @@
JBossCacheSource source = new JBossCacheSource();
source.setName("Test Repository");
source.setPredefinedWorkspaceNames(predefinedWorkspaceNames);
- source.setNameOfDefaultWorkspace(predefinedWorkspaceNames[0]);
+ source.setDefaultWorkspaceName(predefinedWorkspaceNames[0]);
source.setCreatingWorkspacesAllowed(false);
// Set up the mock JNDI ...
Modified: trunk/extensions/dna-connector-jbosscache/src/test/java/org/jboss/dna/connector/jbosscache/JBossCacheConnectorWritableTest.java
===================================================================
--- trunk/extensions/dna-connector-jbosscache/src/test/java/org/jboss/dna/connector/jbosscache/JBossCacheConnectorWritableTest.java 2009-07-12 21:08:48 UTC (rev 1088)
+++ trunk/extensions/dna-connector-jbosscache/src/test/java/org/jboss/dna/connector/jbosscache/JBossCacheConnectorWritableTest.java 2009-07-12 22:01:21 UTC (rev 1089)
@@ -52,7 +52,7 @@
JBossCacheSource source = new JBossCacheSource();
source.setName("Test Repository");
source.setPredefinedWorkspaceNames(predefinedWorkspaceNames);
- source.setNameOfDefaultWorkspace(predefinedWorkspaceNames[0]);
+ source.setDefaultWorkspaceName(predefinedWorkspaceNames[0]);
source.setCreatingWorkspacesAllowed(true);
// Set up the mock JNDI ...
16 years, 6 months
DNA SVN: r1088 - trunk/dna-common/src/main/java/org/jboss/dna/common/util.
by dna-commits@lists.jboss.org
Author: bcarothers
Date: 2009-07-12 17:08:48 -0400 (Sun, 12 Jul 2009)
New Revision: 1088
Modified:
trunk/dna-common/src/main/java/org/jboss/dna/common/util/StringUtil.java
Log:
DNA-484 Repository Startup Errors Use String[].toString() in Error Message
Committed patch that makes StringUtil.createString(...) wraps array parameters with a list to pretty-print them.
Modified: trunk/dna-common/src/main/java/org/jboss/dna/common/util/StringUtil.java
===================================================================
--- trunk/dna-common/src/main/java/org/jboss/dna/common/util/StringUtil.java 2009-07-09 21:56:41 UTC (rev 1087)
+++ trunk/dna-common/src/main/java/org/jboss/dna/common/util/StringUtil.java 2009-07-12 21:08:48 UTC (rev 1088)
@@ -123,6 +123,12 @@
matcher.appendReplacement(text, matcher.group());
} else {
Object parameter = parameters[ndx];
+
+ // Automatically pretty-print arrays
+ if (parameter != null && parameter.getClass().isArray()) {
+ parameter = Arrays.asList((Object[])parameter);
+ }
+
matcher.appendReplacement(text, Matcher.quoteReplacement(parameter == null ? "null" : parameter.toString()));
}
}
16 years, 6 months
DNA SVN: r1087 - in trunk: dna-jcr/src/main/java/org/jboss/dna/jcr and 1 other directories.
by dna-commits@lists.jboss.org
Author: rhauch
Date: 2009-07-09 17:56:41 -0400 (Thu, 09 Jul 2009)
New Revision: 1087
Modified:
trunk/dna-graph/src/main/java/org/jboss/dna/graph/session/GraphSession.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrContentHandler.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrSession.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/SessionCache.java
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/ImportExportTest.java
Log:
DNA-479 Workspace import does not work
Changed the JcrContentHandler implementation to use its own SessionCache object if it is a workspace import, or to use the JcrSession's existing cache if it is a session import. Several test cases were uncommented, though the import/export related TCK unit tests do not all pass and remain commented out. A bug was found in the way that SessionCache was creating child nodes: the property payloads were not getting populated for the few mandatory properties that exist upon creation. This bug was fixed, and it also cleans up a bit of the JCR-specific logic.
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/session/GraphSession.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/session/GraphSession.java 2009-07-09 20:43:56 UTC (rev 1086)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/session/GraphSession.java 2009-07-09 21:56:41 UTC (rev 1087)
@@ -2290,6 +2290,7 @@
// Set the properties on the new node, but in a private backdoor way ...
assert child.properties == null;
child.properties = newProperties;
+ child.childrenByName = cache.NO_CHILDREN;
try {
// The node has been changed, so try notifying before we record the creation (which can't be undone) ...
@@ -2745,7 +2746,6 @@
COPIED;
}
- @Immutable
public static final class PropertyInfo<PropertyPayload> {
private final Property property;
private final Status status;
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrContentHandler.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrContentHandler.java 2009-07-09 20:43:56 UTC (rev 1086)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrContentHandler.java 2009-07-09 21:56:41 UTC (rev 1087)
@@ -24,22 +24,29 @@
package org.jboss.dna.jcr;
import java.io.ByteArrayInputStream;
+import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Stack;
+import java.util.UUID;
import javax.jcr.ImportUUIDBehavior;
+import javax.jcr.ItemExistsException;
+import javax.jcr.ItemNotFoundException;
import javax.jcr.PathNotFoundException;
import javax.jcr.PropertyType;
import javax.jcr.RepositoryException;
import javax.jcr.Value;
+import javax.jcr.ValueFactory;
import javax.jcr.ValueFormatException;
+import javax.jcr.nodetype.ConstraintViolationException;
import net.jcip.annotations.NotThreadSafe;
import org.jboss.dna.common.text.TextDecoder;
import org.jboss.dna.common.text.XmlNameEncoder;
import org.jboss.dna.common.util.Base64;
-import org.jboss.dna.graph.Graph;
+import org.jboss.dna.graph.ExecutionContext;
+import org.jboss.dna.graph.Location;
import org.jboss.dna.graph.property.Name;
import org.jboss.dna.graph.property.NameFactory;
import org.jboss.dna.graph.property.NamespaceRegistry;
@@ -72,8 +79,10 @@
protected static final TextDecoder DOCUMENT_VIEW_NAME_DECODER = new JcrDocumentViewExporter.JcrDocumentViewPropertyEncoder();
private final NameFactory nameFactory;
-
- protected final JcrSession session;
+ private final NamespaceRegistry namespaces;
+ private final ValueFactory jcrValueFactory;
+ private final JcrNodeTypeManager nodeTypes;
+ private final javax.jcr.NamespaceRegistry jcrNamespaceRegistry;
protected final int uuidBehavior;
protected final String primaryTypeName;
@@ -83,7 +92,7 @@
private AbstractJcrNode currentNode;
private ContentHandler delegate;
- private Graph.Batch pendingOperations;
+ private SessionCache cache;
enum SaveMode {
WORKSPACE,
@@ -101,36 +110,58 @@
|| uuidBehavior == ImportUUIDBehavior.IMPORT_UUID_COLLISION_REPLACE_EXISTING
|| uuidBehavior == ImportUUIDBehavior.IMPORT_UUID_COLLISION_THROW;
- this.session = session;
- this.nameFactory = session.getExecutionContext().getValueFactories().getNameFactory();
- this.currentNode = session.getNode(parentPath);
+ ExecutionContext context = session.getExecutionContext();
+ this.namespaces = context.getNamespaceRegistry();
+ this.nameFactory = context.getValueFactories().getNameFactory();
this.uuidBehavior = uuidBehavior;
- if (saveMode == SaveMode.WORKSPACE) {
- this.pendingOperations = session.createBatch();
+ switch (saveMode) {
+ case SESSION:
+ cache = session.cache();
+ break;
+ case WORKSPACE:
+ cache = new SessionCache(session);
+ break;
}
+ assert cache != null;
- this.primaryTypeName = JcrLexicon.PRIMARY_TYPE.getString(this.session.namespaces());
- this.mixinTypesName = JcrLexicon.MIXIN_TYPES.getString(this.session.namespaces());
- this.uuidName = JcrLexicon.UUID.getString(this.session.namespaces());
+ this.currentNode = cache.findJcrNode(null, parentPath);
+ this.jcrValueFactory = session.getValueFactory();
+ this.nodeTypes = session.nodeTypeManager();
+ this.jcrNamespaceRegistry = session.workspace().getNamespaceRegistry();
+
+ this.primaryTypeName = JcrLexicon.PRIMARY_TYPE.getString(this.namespaces);
+ this.mixinTypesName = JcrLexicon.MIXIN_TYPES.getString(this.namespaces);
+ this.uuidName = JcrLexicon.UUID.getString(this.namespaces);
}
+ protected final NamespaceRegistry namespaces() {
+ return namespaces;
+ }
+
+ protected final JcrNodeTypeManager nodeTypes() {
+ return nodeTypes;
+ }
+
+ protected final JcrNodeType nodeTypeFor( String name ) {
+ return nodeTypes.getNodeType(nameFor(name));
+ }
+
protected final Name nameFor( String name ) {
return nameFactory.create(name);
}
protected final Value valueFor( String value,
int type ) throws ValueFormatException {
- return session.getValueFactory().createValue(value, type);
- // return new JcrValue(session.getExecutionContext().getValueFactories(), cache(), type, value);
+ return jcrValueFactory.createValue(value, type);
}
- protected final SessionCache cache() {
- return session.cache();
+ protected final Value valueFor( InputStream stream ) {
+ return jcrValueFactory.createValue(stream);
}
- protected final Graph.Batch operations() {
- return pendingOperations;
+ protected final SessionCache cache() {
+ return cache;
}
/**
@@ -153,10 +184,11 @@
*/
@Override
public void endDocument() throws SAXException {
- if (pendingOperations != null) {
- pendingOperations.execute();
+ try {
+ cache.save();
+ } catch (RepositoryException e) {
+ throw new EnclosingSAXException(e);
}
-
super.endDocument();
}
@@ -209,21 +241,17 @@
String uri ) throws SAXException {
try {
// Read from the workspace's DNA registry, as its semantics are more friendly
- NamespaceRegistry registry = session.workspace().context().getNamespaceRegistry();
+ String existingUri = namespaces.getNamespaceForPrefix(prefix);
- String existingUri = registry.getNamespaceForPrefix(prefix);
-
if (existingUri != null) {
if (existingUri.equals(uri)) {
// prefix/uri mapping is already in registry
return;
}
-
throw new RepositoryException("Prefix " + prefix + " is already permanently mapped");
}
-
// Register through the JCR workspace to ensure consistency
- session.getWorkspace().getNamespaceRegistry().registerNamespace(prefix, uri);
+ this.jcrNamespaceRegistry.registerNamespace(prefix, uri);
} catch (RepositoryException re) {
throw new EnclosingSAXException(re);
}
@@ -269,8 +297,8 @@
this.currentProps = new HashMap<String, List<Value>>();
this.valueBuffer = new StringBuffer();
- this.svNameName = JcrSvLexicon.NAME.getString(session.namespaces());
- this.svTypeName = JcrSvLexicon.TYPE.getString(session.namespaces());
+ this.svNameName = JcrSvLexicon.NAME.getString(namespaces());
+ this.svTypeName = JcrSvLexicon.TYPE.getString(namespaces());
}
/**
@@ -300,58 +328,55 @@
}
private void addNodeIfPending() throws SAXException {
- // if (currentNodeName != null) {
- // try {
- // AbstractJcrNode parentNode = parentStack.peek();
- //
- // UUID uuid = null;
- // List<Value> rawUuid = currentProps.get(uuidName);
- //
- // if (rawUuid != null) {
- // assert rawUuid.size() == 1;
- // uuid = UUID.fromString(rawUuid.get(0).getString());
- // }
- //
- // String typeName = currentProps.get(primaryTypeName).get(0).getString();
- // AbstractJcrNode newNode =
- // cache().findJcrNode(parentNode.editorFor(operations()).createChild(nameFor(currentNodeName),
- // uuid,
- // nameFor(typeName)).getUuid());
- //
- // for (Map.Entry<String, List<Value>> entry : currentProps.entrySet()) {
- // if (entry.getKey().equals(primaryTypeName)) {
- // continue;
- // }
- //
- // if (entry.getKey().equals(mixinTypesName)) {
- // for (Value value : entry.getValue()) {
- // JcrNodeType mixinType = session.workspace().nodeTypeManager().getNodeType(nameFor(value.getString()));
- // newNode.editorFor(operations()).addMixin(mixinType);
- // }
- // continue;
- // }
- //
- // if (entry.getKey().equals(uuidName)) {
- // continue;
- // }
- //
- // List<Value> values = entry.getValue();
- //
- // if (values.size() == 1) {
- // newNode.editorFor(operations()).setProperty(nameFor(entry.getKey()), (JcrValue)values.get(0));
- // } else {
- // newNode.editorFor(operations()).setProperty(nameFor(entry.getKey()),
- // values.toArray(new Value[values.size()]),
- // PropertyType.UNDEFINED);
- // }
- // }
- //
- // parentStack.push(newNode);
- // currentProps.clear();
- // } catch (RepositoryException re) {
- // throw new EnclosingSAXException(re);
- // }
- // }
+ if (currentNodeName != null) {
+ try {
+ AbstractJcrNode parentNode = parentStack.peek();
+
+ UUID uuid = null;
+ List<Value> rawUuid = currentProps.get(uuidName);
+
+ if (rawUuid != null) {
+ assert rawUuid.size() == 1;
+ uuid = UUID.fromString(rawUuid.get(0).getString());
+ }
+
+ String typeName = currentProps.get(primaryTypeName).get(0).getString();
+ AbstractJcrNode newNode = parentNode.editor().createChild(nameFor(currentNodeName), uuid, nameFor(typeName));
+
+ for (Map.Entry<String, List<Value>> entry : currentProps.entrySet()) {
+ if (entry.getKey().equals(primaryTypeName)) {
+ continue;
+ }
+
+ if (entry.getKey().equals(mixinTypesName)) {
+ for (Value value : entry.getValue()) {
+ JcrNodeType mixinType = nodeTypeFor(value.getString());
+ newNode.editor().addMixin(mixinType);
+ }
+ continue;
+ }
+
+ if (entry.getKey().equals(uuidName)) {
+ continue;
+ }
+
+ List<Value> values = entry.getValue();
+
+ if (values.size() == 1) {
+ newNode.editor().setProperty(nameFor(entry.getKey()), (JcrValue)values.get(0));
+ } else {
+ newNode.editor().setProperty(nameFor(entry.getKey()),
+ values.toArray(new Value[values.size()]),
+ PropertyType.UNDEFINED);
+ }
+ }
+
+ parentStack.push(newNode);
+ currentProps.clear();
+ } catch (RepositoryException re) {
+ throw new EnclosingSAXException(re);
+ }
+ }
}
@Override
@@ -367,11 +392,9 @@
try {
if (currentPropType == PropertyType.BINARY) {
ByteArrayInputStream is = new ByteArrayInputStream(Base64.decode(s, Base64.URL_SAFE));
- currentProps.get(currentPropName).add(session.getValueFactory().createValue(is));
+ currentProps.get(currentPropName).add(valueFor(is));
} else {
- currentProps.get(currentPropName).add(session.getValueFactory()
- .createValue(SYSTEM_VIEW_NAME_DECODER.decode(s),
- currentPropType));
+ currentProps.get(currentPropName).add(valueFor(SYSTEM_VIEW_NAME_DECODER.decode(s), currentPropType));
}
} catch (RepositoryException re) {
throw new EnclosingSAXException(re);
@@ -417,70 +440,66 @@
String localName,
String name,
Attributes atts ) throws SAXException {
- // try {
- // String primaryTypeName = atts.getValue(JcrContentHandler.this.primaryTypeName);
- // String rawUuid = atts.getValue(uuidName);
- // UUID uuid = (rawUuid != null ? UUID.fromString(rawUuid) : null);
- // AbstractJcrNode parentNode = parentStack.peek();
- //
- // if (uuid != null) {
- // AbstractJcrNode existingNodeWithUuid = (AbstractJcrNode)session.getNodeByUUID(rawUuid);
- // if (existingNodeWithUuid != null) {
- // switch (uuidBehavior) {
- // case ImportUUIDBehavior.IMPORT_UUID_COLLISION_REPLACE_EXISTING:
- // parentNode = existingNodeWithUuid.getParent();
- // parentNode.editorFor(operations()).destroyChild(uuid);
- // break;
- // case ImportUUIDBehavior.IMPORT_UUID_CREATE_NEW:
- // uuid = UUID.randomUUID();
- // break;
- // case ImportUUIDBehavior.IMPORT_UUID_COLLISION_REMOVE_EXISTING:
- // if (existingNodeWithUuid.path().isAtOrAbove(parentStack.firstElement().path())) {
- // throw new ConstraintViolationException();
- // }
- // AbstractJcrNode temp = existingNodeWithUuid.getParent();
- // temp.editorFor(operations()).destroyChild(uuid);
- // break;
- // case ImportUUIDBehavior.IMPORT_UUID_COLLISION_THROW:
- // throw new ItemExistsException();
- // }
- // }
- // }
- //
- // name = DOCUMENT_VIEW_NAME_DECODER.decode(name);
- // AbstractJcrNode currentNode = cache().findJcrNode(parentNode.editorFor(operations()).createChild(nameFor(name),
- // uuid,
- // nameFor(primaryTypeName)).getUuid());
- //
- // for (int i = 0; i < atts.getLength(); i++) {
- // if (JcrContentHandler.this.primaryTypeName.equals(atts.getQName(i))) {
- // continue;
- // }
- //
- // if (mixinTypesName.equals(atts.getQName(i))) {
- // JcrNodeType mixinType = session.workspace().nodeTypeManager().getNodeType(nameFor(atts.getValue(i)));
- // currentNode.editorFor(operations()).addMixin(mixinType);
- // continue;
- // }
- //
- // if (uuidName.equals(atts.getQName(i))) {
- // continue;
- // }
- //
- // // We may want to use the workspace context here so that we only use the permanent namespace mappings
- // // Name propName = session.executionContext.getValueFactories().getNameFactory().create(atts.getQName(i));
- // // String value = DOCUMENT_VIEW_NAME_DECODER.decode(atts.getValue(i));
- // String value = atts.getValue(i);
- // String propertyName = DOCUMENT_VIEW_NAME_DECODER.decode(atts.getQName(i));
- // currentNode.editorFor(operations()).setProperty(nameFor(propertyName),
- // (JcrValue)valueFor(value, PropertyType.STRING));
- // }
- //
- // parentStack.push(currentNode);
- // } catch (RepositoryException re) {
- // throw new EnclosingSAXException(re);
- // }
+ try {
+ String primaryTypeName = atts.getValue(JcrContentHandler.this.primaryTypeName);
+ String rawUuid = atts.getValue(uuidName);
+ UUID uuid = (rawUuid != null ? UUID.fromString(rawUuid) : null);
+ AbstractJcrNode parentNode = parentStack.peek();
+ if (uuid != null) {
+ try {
+ AbstractJcrNode existingNodeWithUuid = cache().findJcrNode(Location.create(uuid));
+ switch (uuidBehavior) {
+ case ImportUUIDBehavior.IMPORT_UUID_COLLISION_REPLACE_EXISTING:
+ existingNodeWithUuid.editor().destroy();
+ break;
+ case ImportUUIDBehavior.IMPORT_UUID_CREATE_NEW:
+ uuid = UUID.randomUUID();
+ break;
+ case ImportUUIDBehavior.IMPORT_UUID_COLLISION_REMOVE_EXISTING:
+ if (existingNodeWithUuid.path().isAtOrAbove(parentStack.firstElement().path())) {
+ throw new ConstraintViolationException();
+ }
+ existingNodeWithUuid.editor().destroy();
+ break;
+ case ImportUUIDBehavior.IMPORT_UUID_COLLISION_THROW:
+ throw new ItemExistsException();
+ }
+ } catch (ItemNotFoundException e) {
+ // don't care
+ }
+ }
+
+ name = DOCUMENT_VIEW_NAME_DECODER.decode(name);
+ AbstractJcrNode currentNode = parentNode.editor().createChild(nameFor(name), uuid, nameFor(primaryTypeName));
+
+ for (int i = 0; i < atts.getLength(); i++) {
+ if (JcrContentHandler.this.primaryTypeName.equals(atts.getQName(i))) {
+ continue;
+ }
+
+ if (mixinTypesName.equals(atts.getQName(i))) {
+ JcrNodeType mixinType = nodeTypeFor(atts.getValue(i));
+ currentNode.editor().addMixin(mixinType);
+ continue;
+ }
+
+ if (uuidName.equals(atts.getQName(i))) {
+ continue;
+ }
+
+ // We may want to use the workspace context here so that we only use the permanent namespace mappings
+ // Name propName = session.executionContext.getValueFactories().getNameFactory().create(atts.getQName(i));
+ // String value = DOCUMENT_VIEW_NAME_DECODER.decode(atts.getValue(i));
+ String value = atts.getValue(i);
+ String propertyName = DOCUMENT_VIEW_NAME_DECODER.decode(atts.getQName(i));
+ currentNode.editor().setProperty(nameFor(propertyName), (JcrValue)valueFor(value, PropertyType.STRING));
+ }
+
+ parentStack.push(currentNode);
+ } catch (RepositoryException re) {
+ throw new EnclosingSAXException(re);
+ }
}
@Override
@@ -499,20 +518,16 @@
public void characters( char[] ch,
int start,
int length ) throws SAXException {
- // try {
- // AbstractJcrNode parentNode = parentStack.peek();
- // AbstractJcrNode currentNode =
- // cache().findJcrNode(parentNode.editorFor(operations()).createChild(JcrLexicon.XMLTEXT,
- // null,
- // JcrNtLexicon.UNSTRUCTURED).getUuid());
- //
- // String s = new String(ch, start, length);
- // currentNode.editorFor(operations()).setProperty(JcrLexicon.XMLCHARACTERS,
- // (JcrValue)valueFor(s, PropertyType.STRING));
- //
- // } catch (RepositoryException re) {
- // throw new EnclosingSAXException(re);
- // }
+ try {
+ AbstractJcrNode parentNode = parentStack.peek();
+ AbstractJcrNode currentNode = parentNode.editor()
+ .createChild(JcrLexicon.XMLTEXT, null, JcrNtLexicon.UNSTRUCTURED);
+ String s = new String(ch, start, length);
+ currentNode.editor().setProperty(JcrLexicon.XMLCHARACTERS, (JcrValue)valueFor(s, PropertyType.STRING));
+
+ } catch (RepositoryException re) {
+ throw new EnclosingSAXException(re);
+ }
}
}
}
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrSession.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrSession.java 2009-07-09 20:43:56 UTC (rev 1086)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrSession.java 2009-07-09 21:56:41 UTC (rev 1087)
@@ -158,8 +158,7 @@
this.executionContext);
this.graph.useWorkspace(workspace.getName());
- this.cache = new SessionCache(this, workspace.getName(), this.executionContext, this.workspace.nodeTypeManager(),
- this.graph);
+ this.cache = new SessionCache(this);
this.isLive = true;
assert this.sessionAttributes != null;
@@ -200,6 +199,10 @@
return graph.batch();
}
+ Graph graph() {
+ return graph;
+ }
+
String sourceName() {
return this.repository.getRepositorySourceName();
}
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-09 20:43:56 UTC (rev 1086)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/SessionCache.java 2009-07-09 21:56:41 UTC (rev 1087)
@@ -141,6 +141,10 @@
private GraphSession<JcrNodePayload, JcrPropertyPayload> graphSession;
+ public SessionCache( JcrSession session ) {
+ this(session, session.workspace().getName(), session.getExecutionContext(), session.nodeTypeManager(), session.graph());
+ }
+
public SessionCache( JcrSession session,
String workspaceName,
ExecutionContext context,
@@ -202,6 +206,10 @@
return nameFactory;
}
+ ValueFactory<String> stringFactory() {
+ return factories.getStringFactory();
+ }
+
JcrNodeTypeManager nodeTypes() {
return session.nodeTypeManager();
}
@@ -1375,7 +1383,6 @@
// Create the initial properties ...
Property primaryTypeProp = propertyFactory.create(JcrLexicon.PRIMARY_TYPE, primaryTypeName);
Property nodeDefinitionProp = propertyFactory.create(DnaIntLexicon.NODE_DEFINITON, definition.getId().getString());
- List<Name> mixinTypeNames = null;
// Now add the "jcr:uuid" property if and only if referenceable ...
Node<JcrNodePayload, JcrPropertyPayload> result = null;
@@ -1388,13 +1395,10 @@
} else {
result = node.createChild(name, primaryTypeProp, nodeDefinitionProp);
}
- // Now create the payload ...
- JcrNodePayload newPayload = new JcrNodePayload(SessionCache.this, result, primaryTypeName, mixinTypeNames,
- definition.getId());
- result.setPayload(newPayload);
+ // The postCreateChild hook impl should populate the payloads
+
// Finally, return the jcr node ...
- assert result.getPayload() == newPayload;
- return (JcrNode)newPayload.getJcrNode();
+ return (JcrNode)result.getPayload().getJcrNode();
} catch (ValidationException e) {
throw new ConstraintViolationException(e.getMessage(), e.getCause());
} catch (RepositorySourceException e) {
@@ -1423,6 +1427,22 @@
}
return true;
}
+
+ /**
+ * Convenience method that destroys this node.
+ *
+ * @return true if this node was successfully removed
+ * @throws AccessDeniedException if the current session does not have the requisite privileges to perform this task
+ * @throws RepositoryException if any other error occurs
+ */
+ public boolean destroy() throws AccessDeniedException, RepositoryException {
+ try {
+ node.destroy();
+ } catch (AccessControlException e) {
+ throw new AccessDeniedException(e.getMessage(), e.getCause());
+ }
+ return true;
+ }
}
/**
@@ -1971,7 +1991,7 @@
PropertyInfo<JcrPropertyPayload> existing ) {
// Create (or reuse) the JCR Property object ...
AbstractJcrProperty jcrProp = null;
- if (existing != null) {
+ if (existing != null && existing.getPayload() != null) {
jcrProp = existing.getPayload().getJcrProperty();
} else {
AbstractJcrNode jcrNode = nodePayload.getJcrNode();
@@ -1985,7 +2005,6 @@
JcrPropertyPayload propPayload = new JcrPropertyPayload(definition.getId(), propertyType, jcrProp);
Status status = existing != null ? Status.CHANGED : Status.NEW;
return new GraphSession.PropertyInfo<JcrPropertyPayload>(dnaProp, definition.isMultiple(), status, propPayload);
-
}
@Immutable
@@ -2401,6 +2420,60 @@
}
}
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.graph.session.GraphSession.NodeOperations#postCreateChild(org.jboss.dna.graph.session.GraphSession.Node,
+ * org.jboss.dna.graph.session.GraphSession.Node, java.util.Map)
+ */
+ @Override
+ public void postCreateChild( Node<JcrNodePayload, JcrPropertyPayload> parent,
+ Node<JcrNodePayload, JcrPropertyPayload> child,
+ Map<Name, PropertyInfo<JcrPropertyPayload>> properties ) throws ValidationException {
+ super.postCreateChild(parent, child, properties);
+ // Populate the node and properties with the payloads ...
+
+ // Get the 2 properties that WILL be here ...
+ PropertyInfo<JcrPropertyPayload> primaryTypeInfo = properties.get(JcrLexicon.PRIMARY_TYPE);
+ PropertyInfo<JcrPropertyPayload> nodeDefnInfo = properties.get(DnaIntLexicon.NODE_DEFINITON);
+ Name primaryTypeName = nameFactory().create(primaryTypeInfo.getProperty().getFirstValue());
+ String nodeDefnIdStr = stringFactory().create(nodeDefnInfo.getProperty().getFirstValue());
+ NodeDefinitionId nodeDefnId = NodeDefinitionId.fromString(nodeDefnIdStr, nameFactory);
+
+ // Now create the payload ...
+ JcrNodePayload nodePayload = new JcrNodePayload(SessionCache.this, child, primaryTypeName, null, nodeDefnId);
+ child.setPayload(nodePayload);
+
+ // Now update the property infos for the two mandatory properties ...
+ JcrNodeType ntBase = nodeTypes().getNodeType(JcrNtLexicon.BASE);
+ assert ntBase != null;
+ primaryTypeInfo = createPropertyInfo(parent.getPayload(),
+ primaryTypeInfo.getProperty(),
+ ntBase.allPropertyDefinitions(JcrLexicon.PRIMARY_TYPE).iterator().next(),
+ PropertyType.NAME,
+ primaryTypeInfo);
+ properties.put(primaryTypeInfo.getName(), primaryTypeInfo);
+ nodeDefnInfo = createPropertyInfo(parent.getPayload(),
+ nodeDefnInfo.getProperty(),
+ ntBase.allPropertyDefinitions(DnaIntLexicon.NODE_DEFINITON).iterator().next(),
+ PropertyType.STRING,
+ nodeDefnInfo);
+ properties.put(nodeDefnInfo.getName(), nodeDefnInfo);
+
+ // The UUID property is optional ...
+ PropertyInfo<JcrPropertyPayload> uuidInfo = properties.get(JcrLexicon.UUID);
+ if (uuidInfo != null) {
+ JcrNodeType mixRef = nodeTypes().getNodeType(JcrMixLexicon.REFERENCEABLE);
+ assert mixRef != null;
+ uuidInfo = createPropertyInfo(parent.getPayload(),
+ uuidInfo.getProperty(),
+ mixRef.allPropertyDefinitions(JcrLexicon.UUID).iterator().next(),
+ PropertyType.STRING,
+ uuidInfo);
+ properties.put(uuidInfo.getName(), uuidInfo);
+ }
+ }
+
protected final Set<Name> getSingleMultiPropertyNames( Property dnaProperty,
Location location ) {
Set<Name> multiValuedPropertyNames = new HashSet<Name>();
Modified: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/ImportExportTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/ImportExportTest.java 2009-07-09 20:43:56 UTC (rev 1086)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/ImportExportTest.java 2009-07-09 21:56:41 UTC (rev 1087)
@@ -128,7 +128,6 @@
session.importXML(targetPath, bais, ImportUUIDBehavior.IMPORT_UUID_CREATE_NEW);
}
- @Ignore( "dna-466" )
@Test
public void shouldImportExportEscapedXmlCharactersInSystemView() throws Exception {
String testName = "importExportEscapedXmlCharacters";
16 years, 6 months
DNA SVN: r1086 - in trunk/dna-jcr/src: main/resources/org/jboss/dna/jcr and 1 other directories.
by dna-commits@lists.jboss.org
Author: bcarothers
Date: 2009-07-09 16:43:56 -0400 (Thu, 09 Jul 2009)
New Revision: 1086
Modified:
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrConfiguration.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrEngine.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrLexicon.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrWorkspace.java
trunk/dna-jcr/src/main/resources/org/jboss/dna/jcr/dna_builtins.cnd
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrConfigurationTest.java
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/RepositoryNodeTypeManagerTest.java
Log:
DNA-481 Correct path to node types under "/jcr:system"
Committed patch that changes the name of the node types projection path from /jcr:system/dna:nodeTypes to /jcr:system/jcr:nodeTypes as per the -283 spec, but retains dna:nodeTypes as the name of the primary node type for this node.
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrConfiguration.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrConfiguration.java 2009-07-09 18:25:20 UTC (rev 1085)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrConfiguration.java 2009-07-09 20:43:56 UTC (rev 1086)
@@ -591,8 +591,8 @@
protected CndImporter createCndImporter() {
// The node types will be loaded into 'dna:repositories/{repositoryName}/dna:nodeTypes/' ...
- Path nodeTypesPath = subpath(DnaLexicon.NODE_TYPES);
- createIfMissing(DnaLexicon.NODE_TYPES).and();
+ Path nodeTypesPath = subpath(JcrLexicon.NODE_TYPES);
+ createIfMissing(JcrLexicon.NODE_TYPES).and();
// Now set up the destination, but make it so that ...
Destination destination = new GraphBatchDestination(batch, true); // will NOT be executed
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrEngine.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrEngine.java 2009-07-09 18:25:20 UTC (rev 1085)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrEngine.java 2009-07-09 20:43:56 UTC (rev 1086)
@@ -164,7 +164,7 @@
JcrRepository repository = new JcrRepository(context, connectionFactory, sourceName, descriptors, options);
// Register all the the node types ...
- Node nodeTypesNode = subgraph.getNode(DnaLexicon.NODE_TYPES);
+ Node nodeTypesNode = subgraph.getNode(JcrLexicon.NODE_TYPES);
if (nodeTypesNode != null) {
repository.getRepositoryTypeManager().registerNodeTypes(subgraph, nodeTypesNode.getLocation());// throws exception
}
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrLexicon.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrLexicon.java 2009-07-09 18:25:20 UTC (rev 1085)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrLexicon.java 2009-07-09 20:43:56 UTC (rev 1086)
@@ -46,6 +46,7 @@
public static final Name LOCK_IS_DEEP = new BasicName(Namespace.URI, "lockIsDeep");
public static final Name LOCK_OWNER = new BasicName(Namespace.URI, "lockOwner");
public static final Name MERGE_FAILED = new BasicName(Namespace.URI, "mergeFailed");
+ public static final Name NODE_TYPES = new BasicName(Namespace.URI, "nodeTypes");
public static final Name PREDECESSORS = new BasicName(Namespace.URI, "predecessors");
public static final Name ROOT = new BasicName(Namespace.URI, "root");
public static final Name ROOT_VERSION = new BasicName(Namespace.URI, "rootVersion");
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrWorkspace.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrWorkspace.java 2009-07-09 18:25:20 UTC (rev 1085)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrWorkspace.java 2009-07-09 20:43:56 UTC (rev 1086)
@@ -185,7 +185,7 @@
this.queryManager = new JcrQueryManager(this.session);
if (Boolean.valueOf(repository.getOptions().get(Option.PROJECT_NODE_TYPES))) {
- Path parentOfTypeNodes = context.getValueFactories().getPathFactory().create(systemPath, DnaLexicon.NODE_TYPES);
+ Path parentOfTypeNodes = context.getValueFactories().getPathFactory().create(systemPath, JcrLexicon.NODE_TYPES);
repoTypeManager.projectOnto(this.graph, parentOfTypeNodes);
}
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-09 18:25:20 UTC (rev 1085)
+++ trunk/dna-jcr/src/main/resources/org/jboss/dna/jcr/dna_builtins.cnd 2009-07-09 20:43:56 UTC (rev 1086)
@@ -25,6 +25,7 @@
//------------------------------------------------------------------------------
// N A M E S P A C E S
//------------------------------------------------------------------------------
+<jcr = "http://www.jcp.org/jcr/1.0">
<nt = "http://www.jcp.org/jcr/nt/1.0">
<mix = "http://www.jcp.org/jcr/mix/1.0">
<dna = "http://www.jboss.org/dna/1.0">
@@ -44,7 +45,7 @@
[dna:system] > nt:base
+ dna:namespaces (dna:namespaces) = dna:namespaces autocreated mandatory protected version
-+ dna:nodeTypes (dna:nodeTypes) = dna:nodeTypes autocreated mandatory protected version
++ jcr:nodeTypes (dna:nodeTypes) = dna:nodeTypes autocreated mandatory protected version
[dna:root] > nt:base, mix:referenceable orderable
- * (undefined) multiple version
Modified: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrConfigurationTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrConfigurationTest.java 2009-07-09 18:25:20 UTC (rev 1085)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrConfigurationTest.java 2009-07-09 20:43:56 UTC (rev 1086)
@@ -351,11 +351,11 @@
assertThat(subgraph.getNode("/dna:repositories/Car Repository"), is(notNullValue()));
assertThat(subgraph.getNode("/dna:repositories/Car Repository"), hasProperty(DnaLexicon.SOURCE_NAME, "Cars"));
assertThat(subgraph.getNode("/dna:repositories/Car Repository").getChildren(), hasChild(segment("dna:options")));
- assertThat(subgraph.getNode("/dna:repositories/Car Repository/dna:nodeTypes"), is(notNullValue()));
+ assertThat(subgraph.getNode("/dna:repositories/Car Repository/jcr:nodeTypes"), is(notNullValue()));
// for (Location child : subgraph.getNode("/dna:repositories/Car Repository/dna:nodeTypes").getChildren()) {
// System.out.println(child.getPath().getLastSegment().getString(context().getNamespaceRegistry()));
// }
- assertThat(subgraph.getNode("/dna:repositories/Car Repository/dna:nodeTypes").getChildren(),
+ assertThat(subgraph.getNode("/dna:repositories/Car Repository/jcr:nodeTypes").getChildren(),
hasChildren(segment("dnatest:noSameNameSibs"),
segment("dnatest:referenceableUnstructured"),
segment("dnatest:nodeWithMandatoryProperty"),
Modified: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/RepositoryNodeTypeManagerTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/RepositoryNodeTypeManagerTest.java 2009-07-09 18:25:20 UTC (rev 1085)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/RepositoryNodeTypeManagerTest.java 2009-07-09 20:43:56 UTC (rev 1086)
@@ -112,8 +112,8 @@
Node systemNode = rootNode.getNode(JcrLexicon.SYSTEM.getString(registry));
assertThat(systemNode, is(notNullValue()));
- NodeIterator nodeTypesNodes = systemNode.getNodes(DnaLexicon.NODE_TYPES.getString(registry));
- assertEquals(nodeTypesNodes.getSize(), 1);
+ NodeIterator nodeTypesNodes = systemNode.getNodes(JcrLexicon.NODE_TYPES.getString(registry));
+ assertEquals(1, nodeTypesNodes.getSize());
}
@Test
16 years, 6 months
DNA SVN: r1085 - in trunk: dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory and 2 other directories.
by dna-commits@lists.jboss.org
Author: rhauch
Date: 2009-07-09 14:25:20 -0400 (Thu, 09 Jul 2009)
New Revision: 1085
Modified:
trunk/dna-graph/src/main/java/org/jboss/dna/graph/Graph.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory/InMemoryRepository.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/map/AbstractMapWorkspace.java
trunk/extensions/dna-connector-jbosscache/src/main/java/org/jboss/dna/connector/jbosscache/JBossCacheRepository.java
Log:
DNA-480 Clean up compiler warnings
The compiler warnings were cleaned up, except for those in JcrContentHandler (which will be addressed under DNA-479)
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/Graph.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/Graph.java 2009-07-09 16:29:03 UTC (rev 1084)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/Graph.java 2009-07-09 18:25:20 UTC (rev 1085)
@@ -6199,7 +6199,7 @@
@NotThreadSafe
public abstract class CloneAction<T> extends AbstractAction<T> implements Clone<T> {
- private final Location from;
+ protected final Location from;
/*package*/CloneAction( T afterConjunction,
Location from ) {
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory/InMemoryRepository.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory/InMemoryRepository.java 2009-07-09 16:29:03 UTC (rev 1084)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory/InMemoryRepository.java 2009-07-09 18:25:20 UTC (rev 1085)
@@ -54,6 +54,7 @@
initialize();
}
+ @Override
@GuardedBy( "getLock()" )
protected MapWorkspace createWorkspace( ExecutionContext context,
String name ) {
@@ -70,21 +71,25 @@
initialize();
}
+ @Override
protected void addNodeToMap( MapNode node ) {
assert node != null;
assert nodesByUuid != null;
nodesByUuid.put(node.getUuid(), node);
}
+ @Override
protected MapNode removeNodeFromMap( UUID nodeUuid ) {
assert nodeUuid != null;
return nodesByUuid.remove(nodeUuid);
}
+ @Override
protected void removeAllNodesFromMap() {
nodesByUuid.clear();
}
+ @Override
public MapNode getNode( UUID nodeUuid ) {
assert nodeUuid != null;
return nodesByUuid.get(nodeUuid);
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/map/AbstractMapWorkspace.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/map/AbstractMapWorkspace.java 2009-07-09 16:29:03 UTC (rev 1084)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/map/AbstractMapWorkspace.java 2009-07-09 18:25:20 UTC (rev 1085)
@@ -473,6 +473,7 @@
}
if (!reuseUuids) {
+ assert oldToNewUuids != null;
// Now, adjust any references in the new subgraph to objects in the original subgraph
// (because they were internal references, and need to be internal to the new subgraph)
PropertyFactory propertyFactory = context.getPropertyFactory();
Modified: trunk/extensions/dna-connector-jbosscache/src/main/java/org/jboss/dna/connector/jbosscache/JBossCacheRepository.java
===================================================================
--- trunk/extensions/dna-connector-jbosscache/src/main/java/org/jboss/dna/connector/jbosscache/JBossCacheRepository.java 2009-07-09 16:29:03 UTC (rev 1084)
+++ trunk/extensions/dna-connector-jbosscache/src/main/java/org/jboss/dna/connector/jbosscache/JBossCacheRepository.java 2009-07-09 18:25:20 UTC (rev 1085)
@@ -31,7 +31,7 @@
assert cache != null;
this.cache = cache;
-
+
initialize();
}
@@ -56,20 +56,24 @@
initialize();
}
+ @Override
protected void addNodeToMap( MapNode node ) {
assert node != null;
workspaceNode.put(node.getUuid(), node);
}
+ @Override
protected MapNode removeNodeFromMap( UUID nodeUuid ) {
assert nodeUuid != null;
return workspaceNode.remove(nodeUuid);
}
+ @Override
protected void removeAllNodesFromMap() {
workspaceNode.clearData();
}
+ @Override
public MapNode getNode( UUID nodeUuid ) {
assert nodeUuid != null;
return workspaceNode.get(nodeUuid);
16 years, 6 months
DNA SVN: r1084 - in trunk: dna-graph/src/main/java/org/jboss/dna/graph/connector/map and 5 other directories.
by dna-commits@lists.jboss.org
Author: rhauch
Date: 2009-07-09 12:29:03 -0400 (Thu, 09 Jul 2009)
New Revision: 1084
Added:
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/AbstractSessionTest.java
Modified:
trunk/dna-graph/src/main/java/org/jboss/dna/graph/Graph.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/map/AbstractMapWorkspace.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/map/package-info.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/BatchRequestBuilder.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/session/GraphSession.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/AbstractJcrNode.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrLexicon.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrWorkspace.java
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/AbstractJcrTest.java
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/ItemDefinitionTest.java
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrPropertyDefinitionTest.java
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrSessionTest.java
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrTckTest.java
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrWorkspaceTest.java
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/MixinTest.java
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/RepositoryNodeTypeManagerTest.java
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/TypeRegistrationTest.java
trunk/extensions/dna-connector-jbosscache/src/main/java/org/jboss/dna/connector/jbosscache/JBossCacheSource.java
Log:
DNA-466 Changes following the merge of trunk onto this branch.
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/Graph.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/Graph.java 2009-07-09 16:27:15 UTC (rev 1083)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/Graph.java 2009-07-09 16:29:03 UTC (rev 1084)
@@ -2462,13 +2462,13 @@
Name desiredName,
Segment desiredSegment,
boolean removeExisting ) {
- requests.cloneBranch(from,
- fromWorkspaceName,
- into,
- intoWorkspaceName,
- desiredName,
- desiredSegment,
- removeExisting);
+ requestQueue.cloneBranch(from,
+ fromWorkspaceName,
+ into,
+ intoWorkspaceName,
+ desiredName,
+ desiredSegment,
+ removeExisting);
return and();
}
};
@@ -2611,9 +2611,9 @@
Locations from,
Location into,
Name copyName ) {
-
+
String intoWorkspaceName = getCurrentWorkspaceName();
- if ( fromWorkspaceName == null ) fromWorkspaceName = intoWorkspaceName;
+ if (fromWorkspaceName == null) fromWorkspaceName = intoWorkspaceName;
do {
requestQueue.copyBranch(from.getLocation(), fromWorkspaceName, into, intoWorkspaceName, copyName, null);
} while ((from = from.next()) != null);
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/map/AbstractMapWorkspace.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/map/AbstractMapWorkspace.java 2009-07-09 16:27:15 UTC (rev 1083)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/map/AbstractMapWorkspace.java 2009-07-09 16:29:03 UTC (rev 1084)
@@ -458,6 +458,7 @@
UUID uuidForCopy = reuseUuids ? original.getUuid() : UUID.randomUUID();
MapNode copy = newWorkspace.createNode(context, newParent, childName, uuidForCopy);
if (!reuseUuids) {
+ assert oldToNewUuids != null;
oldToNewUuids.put(original.getUuid(), copy.getUuid());
}
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/map/package-info.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/map/package-info.java 2009-07-09 16:27:15 UTC (rev 1083)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/map/package-info.java 2009-07-09 16:29:03 UTC (rev 1084)
@@ -65,7 +65,6 @@
*
* @see org.jboss.dna.graph.connector.inmemory.InMemoryRepository
* @see org.jboss.dna.graph.connector.inmemory.InMemoryRepositorySource
- * @see org.jboss.dna.graph.connector.inmemory.InMemoryRepository#Workspace
*/
package org.jboss.dna.graph.connector.map;
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/BatchRequestBuilder.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/BatchRequestBuilder.java 2009-07-09 16:27:15 UTC (rev 1083)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/BatchRequestBuilder.java 2009-07-09 16:29:03 UTC (rev 1084)
@@ -29,6 +29,7 @@
import java.util.Map;
import org.jboss.dna.graph.Location;
import org.jboss.dna.graph.NodeConflictBehavior;
+import org.jboss.dna.graph.connector.UuidAlreadyExistsException;
import org.jboss.dna.graph.property.Name;
import org.jboss.dna.graph.property.Path;
import org.jboss.dna.graph.property.Property;
@@ -600,6 +601,33 @@
}
/**
+ * Add a request to clone a branch to another.
+ *
+ * @param from the location of the top node in the existing branch that is to be cloned
+ * @param fromWorkspace the name of the workspace where the <code>from</code> node exists
+ * @param into the location of the existing node into which the clone should be placed
+ * @param intoWorkspace the name of the workspace where the <code>into</code> node is to be cloned
+ * @param nameForClone the desired name for the node that results from the clone, or null if the name of the original should
+ * be used
+ * @param exactSegmentForClone the exact {@link Path.Segment segment} at which the cloned tree should be rooted.
+ * @param removeExisting whether any nodes in the intoWorkspace with the same UUIDs as a node in the source branch should be
+ * removed (if true) or a {@link UuidAlreadyExistsException} should be thrown.
+ * @return this builder for method chaining; never null
+ * @throws IllegalArgumentException if any of the parameters are null except for {@code nameForClone} or {@code
+ * exactSegmentForClone}. Exactly one of {@code nameForClone} and {@code exactSegmentForClone} must be null.
+ */
+ public BatchRequestBuilder cloneBranch( Location from,
+ String fromWorkspace,
+ Location into,
+ String intoWorkspace,
+ Name nameForClone,
+ Path.Segment exactSegmentForClone,
+ boolean removeExisting ) {
+ return add(new CloneBranchRequest(from, fromWorkspace, into, intoWorkspace, nameForClone, exactSegmentForClone,
+ removeExisting));
+ }
+
+ /**
* Create a request to move a branch from one location into another.
*
* @param from the location of the top node in the existing branch that is to be moved
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/session/GraphSession.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/session/GraphSession.java 2009-07-09 16:27:15 UTC (rev 1083)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/session/GraphSession.java 2009-07-09 16:29:03 UTC (rev 1084)
@@ -59,6 +59,7 @@
import org.jboss.dna.graph.property.Path.Segment;
import org.jboss.dna.graph.request.BatchRequestBuilder;
import org.jboss.dna.graph.request.ChangeRequest;
+import org.jboss.dna.graph.request.CloneBranchRequest;
import org.jboss.dna.graph.request.CopyBranchRequest;
import org.jboss.dna.graph.request.InvalidWorkspaceException;
import org.jboss.dna.graph.request.Request;
@@ -564,6 +565,7 @@
* should be used
* @param destination the path for the new cloned copy; may not be null index
* @param removeExisting true if the original should be removed, or false if the original should be left
+ * @param destPathIncludesSegment true if the destination path includes the segment that should be used
* @throws IllegalArgumentException either path is null or invalid
* @throws InvalidWorkspaceException if the source workspace name is invalid or does not exist
* @throws UuidAlreadyExistsException if copy could not be completed because the current workspace already includes at least
@@ -575,7 +577,8 @@
public void immediateClone( Path source,
String sourceWorkspace,
Path destination,
- boolean removeExisting )
+ boolean removeExisting,
+ boolean destPathIncludesSegment )
throws InvalidWorkspaceException, AccessControlException, UuidAlreadyExistsException, PathNotFoundException,
RepositorySourceException {
CheckArg.isNotNull(source, "source");
@@ -591,18 +594,42 @@
Graph.Batch batch = store.batch();
if (removeExisting) {
// Perform the copy operation, but use the "to" form (not the "into", which takes the parent) ...
- batch.copy(source).replacingExistingNodesWithSameUuids().fromWorkspace(sourceWorkspace).to(destination);
+ if (destPathIncludesSegment) {
+ batch.clone(source)
+ .fromWorkspace(sourceWorkspace)
+ .as(destination.getLastSegment())
+ .into(destination.getParent())
+ .replacingExistingNodesWithSameUuids();
+ } else {
+ Name newNodeName = destination.getLastSegment().getName();
+ batch.clone(source)
+ .fromWorkspace(sourceWorkspace)
+ .as(newNodeName)
+ .into(destination.getParent())
+ .replacingExistingNodesWithSameUuids();
+ }
} else {
// Perform the copy operation, but use the "to" form (not the "into", which takes the parent) ...
- batch.copy(source).failingIfUuidsMatch().fromWorkspace(sourceWorkspace).to(destination);
+ if (destPathIncludesSegment) {
+ batch.clone(source)
+ .fromWorkspace(sourceWorkspace)
+ .as(destination.getLastSegment())
+ .into(destination.getParent())
+ .failingIfAnyUuidsMatch();
+ } else {
+ Name newNodeName = destination.getLastSegment().getName();
+ batch.clone(source)
+ .fromWorkspace(sourceWorkspace)
+ .as(newNodeName)
+ .into(destination.getParent())
+ .failingIfAnyUuidsMatch();
+ }
}
- // And read the children of the destination's parent ...
- batch.readChildren().of(destination.getParent());
// Now execute these two operations ...
Results results = batch.execute();
// Find the copy request to get the actual location of the copy ...
- CopyBranchRequest request = (CopyBranchRequest)results.getRequests().get(0);
+ CloneBranchRequest request = (CloneBranchRequest)results.getRequests().get(0);
Location locationOfCopy = request.getActualLocationAfter();
// Find the parent node in the session ...
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/AbstractJcrNode.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/AbstractJcrNode.java 2009-07-09 16:27:15 UTC (rev 1083)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/AbstractJcrNode.java 2009-07-09 16:29:03 UTC (rev 1084)
@@ -1444,7 +1444,14 @@
throws NoSuchWorkspaceException, ItemNotFoundException, RepositoryException {
CheckArg.isNotNull(workspaceName, "workspace name");
NamespaceRegistry namespaces = this.context().getNamespaceRegistry();
+ return correspondingNodePath(workspaceName).getString(namespaces);
+ }
+ protected final Path correspondingNodePath( String workspaceName )
+ throws NoSuchWorkspaceException, ItemNotFoundException, RepositoryException {
+ assert workspaceName != null;
+ NamespaceRegistry namespaces = this.context().getNamespaceRegistry();
+
// Find the closest ancestor (including this node) that is referenceable ...
AbstractJcrNode referenceableRoot = this;
while (!referenceableRoot.isNodeType(JcrMixLexicon.REFERENCEABLE.getString(namespaces))) {
@@ -1454,7 +1461,7 @@
// Find the relative path from the nearest referenceable node to this node (or null if this node is referenceable) ...
Path relativePath = path().equals(referenceableRoot.path()) ? null : path().relativeTo(referenceableRoot.path());
UUID uuid = UUID.fromString(referenceableRoot.getUUID());
- return this.cache.getPathForCorrespondingNode(workspaceName, uuid, relativePath).getString(namespaces);
+ return this.cache.getPathForCorrespondingNode(workspaceName, uuid, relativePath);
}
/**
@@ -1469,14 +1476,15 @@
throw new InvalidItemStateException(JcrI18n.noPendingChangesAllowed.text());
}
+ Path correspondingPath = null;
try {
- getCorrespondingNodePath(srcWorkspaceName);
+ correspondingPath = correspondingNodePath(srcWorkspaceName);
} catch (ItemNotFoundException infe) {
return;
}
// Need to force remove in case this node is not referenceable
- this.session().workspace().clone(srcWorkspaceName, correspondingPath, path(), true, true);
+ cache.graphSession().immediateClone(correspondingPath, srcWorkspaceName, path(), true, true);
session().refresh(false);
}
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrLexicon.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrLexicon.java 2009-07-09 16:27:15 UTC (rev 1083)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrLexicon.java 2009-07-09 16:29:03 UTC (rev 1084)
@@ -46,7 +46,6 @@
public static final Name LOCK_IS_DEEP = new BasicName(Namespace.URI, "lockIsDeep");
public static final Name LOCK_OWNER = new BasicName(Namespace.URI, "lockOwner");
public static final Name MERGE_FAILED = new BasicName(Namespace.URI, "mergeFailed");
- public static final Name NODE_TYPES = new BasicName(Namespace.URI, "nodeTypes");
public static final Name PREDECESSORS = new BasicName(Namespace.URI, "predecessors");
public static final Name ROOT = new BasicName(Namespace.URI, "root");
public static final Name ROOT_VERSION = new BasicName(Namespace.URI, "rootVersion");
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrWorkspace.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrWorkspace.java 2009-07-09 16:27:15 UTC (rev 1083)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrWorkspace.java 2009-07-09 16:29:03 UTC (rev 1084)
@@ -185,7 +185,7 @@
this.queryManager = new JcrQueryManager(this.session);
if (Boolean.valueOf(repository.getOptions().get(Option.PROJECT_NODE_TYPES))) {
- Path parentOfTypeNodes = context.getValueFactories().getPathFactory().create(systemPath, JcrLexicon.NODE_TYPES);
+ Path parentOfTypeNodes = context.getValueFactories().getPathFactory().create(systemPath, DnaLexicon.NODE_TYPES);
repoTypeManager.projectOnto(this.graph, parentOfTypeNodes);
}
@@ -236,17 +236,16 @@
try {
Set<String> workspaceNamesFromGraph = graph.getWorkspaces();
Set<String> workspaceNames = new HashSet<String>(workspaceNamesFromGraph.size());
-
- for(String workspaceName : workspaceNamesFromGraph) {
+
+ for (String workspaceName : workspaceNamesFromGraph) {
try {
session.checkPermission(workspaceName, null, JcrSession.JCR_READ_PERMISSION);
workspaceNames.add(workspaceName);
- }
- catch (AccessControlException ace) {
+ } catch (AccessControlException ace) {
// Can happen if user doesn't have the privileges to read from the workspace
}
}
-
+
return workspaceNames.toArray(new String[workspaceNames.size()]);
} catch (RepositorySourceException e) {
throw new RepositoryException(JcrI18n.errorObtainingWorkspaceNames.text(getSourceName(), e.getMessage()), e);
@@ -354,7 +353,7 @@
}
// Now perform the clone, using the direct (non-session) method ...
- cache.graphSession().immediateClone(srcPath, srcWorkspace, destPath, removeExisting);
+ cache.graphSession().immediateClone(srcPath, srcWorkspace, destPath, removeExisting, false);
} catch (ItemNotFoundException e) {
// The destination path was not found ...
throw new PathNotFoundException(e.getLocalizedMessage(), e);
Modified: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/AbstractJcrTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/AbstractJcrTest.java 2009-07-09 16:27:15 UTC (rev 1083)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/AbstractJcrTest.java 2009-07-09 16:29:03 UTC (rev 1084)
@@ -41,7 +41,10 @@
import org.junit.BeforeClass;
/**
+ * Abstract test that sets up a SessionCache environment with a real {@link RepositoryNodeTypeManager}, albeit with a mocked
+ * JcrSession, Workspace, and Repository.
*
+ * @see AbstractSessionTest for an alternative with a more complete environment
*/
public abstract class AbstractJcrTest {
@@ -109,19 +112,23 @@
store.importXmlFrom(AbstractJcrTest.class.getClassLoader().getResourceAsStream(xmlResourceName)).into("/");
numberOfConnections = 0; // reset the number of connections
- nodeTypes = new JcrNodeTypeManager(context, rntm);
-
- // Stub the session ...
+ // Stub the session, workspace, and repository; then stub some critical methods ...
jcrSession = mock(JcrSession.class);
- stub(jcrSession.nodeTypeManager()).toReturn(nodeTypes);
-
- cache = new SessionCache(jcrSession, store.getCurrentWorkspaceName(), context, nodeTypes, store);
-
workspace = mock(Workspace.class);
repository = mock(Repository.class);
+ stub(jcrSession.getExecutionContext()).toReturn(context);
stub(jcrSession.getWorkspace()).toReturn(workspace);
stub(jcrSession.getRepository()).toReturn(repository);
stub(workspace.getName()).toReturn("workspace1");
+
+ // Create the node type manager for the session ...
+ // no need to stub the 'JcrSession.checkPermission' methods, since we're never calling 'register' on the
+ // JcrNodeTypeManager
+ nodeTypes = new JcrNodeTypeManager(jcrSession, rntm);
+ stub(jcrSession.nodeTypeManager()).toReturn(nodeTypes);
+
+ cache = new SessionCache(jcrSession, store.getCurrentWorkspaceName(), context, nodeTypes, store);
+
}
protected String getResourceNameOfXmlFileToImport() {
Added: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/AbstractSessionTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/AbstractSessionTest.java (rev 0)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/AbstractSessionTest.java 2009-07-09 16:29:03 UTC (rev 1084)
@@ -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.jcr;
+
+import static org.mockito.Mockito.stub;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.EnumMap;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import javax.jcr.RepositoryException;
+import org.jboss.dna.graph.ExecutionContext;
+import org.jboss.dna.graph.Graph;
+import org.jboss.dna.graph.MockSecurityContext;
+import org.jboss.dna.graph.SecurityContext;
+import org.jboss.dna.graph.connector.RepositoryConnection;
+import org.jboss.dna.graph.connector.RepositoryConnectionFactory;
+import org.jboss.dna.graph.connector.RepositorySourceException;
+import org.jboss.dna.graph.connector.inmemory.InMemoryRepositorySource;
+import org.jboss.dna.graph.property.NamespaceRegistry;
+import org.jboss.dna.jcr.nodetype.NodeTypeTemplate;
+import org.mockito.MockitoAnnotations;
+import org.mockito.MockitoAnnotations.Mock;
+
+/**
+ * Abstract test class that sets up a working JcrSession environment, albeit with a mocked JcrRepository.
+ *
+ * @see AbstractJcrTest for an alternative with a less complete environment
+ */
+public abstract class AbstractSessionTest {
+
+ protected String workspaceName;
+ protected ExecutionContext context;
+ protected InMemoryRepositorySource source;
+ protected JcrWorkspace workspace;
+ protected JcrSession session;
+ protected Graph graph;
+ protected RepositoryConnectionFactory connectionFactory;
+ protected RepositoryNodeTypeManager repoTypeManager;
+ protected Map<String, Object> sessionAttributes;
+ protected Map<JcrRepository.Option, String> options;
+ protected NamespaceRegistry registry;
+ @Mock
+ protected JcrRepository repository;
+
+ protected void beforeEach() throws Exception {
+ MockitoAnnotations.initMocks(this);
+
+ workspaceName = "workspace1";
+ final String repositorySourceName = "repository";
+
+ // Set up the source ...
+ source = new InMemoryRepositorySource();
+ source.setName(workspaceName);
+ source.setDefaultWorkspaceName(workspaceName);
+
+ // Set up the execution context ...
+ context = new ExecutionContext();
+ // Register the test namespace
+ context.getNamespaceRegistry().register(TestLexicon.Namespace.PREFIX, TestLexicon.Namespace.URI);
+
+ // Set up the initial content ...
+ graph = Graph.create(source, context);
+ initializeContent();
+
+ // Stub out the connection factory ...
+ connectionFactory = new RepositoryConnectionFactory() {
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.graph.connector.RepositoryConnectionFactory#createConnection(java.lang.String)
+ */
+ public RepositoryConnection createConnection( String sourceName ) throws RepositorySourceException {
+ return repositorySourceName.equals(sourceName) ? source.getConnection() : null;
+ }
+ };
+
+ // Stub out the repository, since we only need a few methods ...
+ repoTypeManager = new RepositoryNodeTypeManager(context);
+
+ try {
+ this.repoTypeManager.registerNodeTypes(new CndNodeTypeSource(new String[] {"/org/jboss/dna/jcr/jsr_170_builtins.cnd",
+ "/org/jboss/dna/jcr/dna_builtins.cnd"}));
+ this.repoTypeManager.registerNodeTypes(new NodeTemplateNodeTypeSource(getTestTypes()));
+
+ } catch (RepositoryException re) {
+ re.printStackTrace();
+ throw new IllegalStateException("Could not load node type definition files", re);
+ } catch (IOException ioe) {
+ ioe.printStackTrace();
+ throw new IllegalStateException("Could not access node type definition files", ioe);
+ }
+
+ stub(repository.getRepositoryTypeManager()).toReturn(repoTypeManager);
+ stub(repository.getRepositorySourceName()).toReturn(repositorySourceName);
+ stub(repository.getConnectionFactory()).toReturn(connectionFactory);
+
+ initializeOptions();
+ stub(repository.getOptions()).toReturn(options);
+
+ // Set up the session attributes ...
+ // Set up the session attributes ...
+ sessionAttributes = new HashMap<String, Object>();
+ sessionAttributes.put("attribute1", "value1");
+
+ // Now create the workspace ...
+ SecurityContext mockSecurityContext = new MockSecurityContext(null,
+ Collections.singleton(JcrSession.DNA_WRITE_PERMISSION));
+ workspace = new JcrWorkspace(repository, workspaceName, context.with(mockSecurityContext), sessionAttributes);
+
+ // Create the session and log in ...
+ session = (JcrSession)workspace.getSession();
+ registry = session.getExecutionContext().getNamespaceRegistry();
+ }
+
+ protected List<NodeTypeTemplate> getTestTypes() {
+ return Collections.emptyList();
+ }
+
+ protected void initializeContent() {
+
+ }
+
+ protected void initializeOptions() {
+ // Stub out the repository options ...
+ options = new EnumMap<JcrRepository.Option, String>(JcrRepository.Option.class);
+ options.put(JcrRepository.Option.PROJECT_NODE_TYPES, Boolean.FALSE.toString());
+
+ }
+}
Property changes on: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/AbstractSessionTest.java
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Modified: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/ItemDefinitionTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/ItemDefinitionTest.java 2009-07-09 16:27:15 UTC (rev 1083)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/ItemDefinitionTest.java 2009-07-09 16:29:03 UTC (rev 1084)
@@ -45,7 +45,7 @@
* BDD test cases for property and child node definition inheritance. Could be part of RepositoryNodeTypeManagerTest, but split
* off to isolate tests for this behavior vs. projection/inference and registration/unregistration behavior.
*/
-public class ItemDefinitionTest extends AbstractJcrTest {
+public class ItemDefinitionTest extends AbstractSessionTest {
private static final Name NODE_TYPE_A = new BasicName(TestLexicon.Namespace.URI, "nodeA");
private static final Name NODE_TYPE_B = new BasicName(TestLexicon.Namespace.URI, "nodeB");
@@ -67,9 +67,9 @@
@Override
protected void initializeContent() {
graph.create("/jcr:system").and().create("/jcr:system/dna:namespaces");
-
+
}
-
+
@After
public void after() throws Exception {
if (session != null && session.isLive()) {
Modified: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrPropertyDefinitionTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrPropertyDefinitionTest.java 2009-07-09 16:27:15 UTC (rev 1083)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrPropertyDefinitionTest.java 2009-07-09 16:29:03 UTC (rev 1084)
@@ -46,7 +46,7 @@
* Indirectly tests the JcrConstaintCheckerFactory through {@link JcrPropertyDefinition#satisfiesConstraints(Value)}, which
* provides the wrapper around the factory that the rest of the API is expected to utilize.
*/
-public class JcrPropertyDefinitionTest extends AbstractJcrTest {
+public class JcrPropertyDefinitionTest extends AbstractSessionTest {
protected final String[] EXPECTED_BINARY_CONSTRAINTS = new String[] {"[,5)", "[10, 20)", "(30,40]", "[50,]"};
protected final String[] EXPECTED_DATE_CONSTRAINTS = new String[] {"[,+1945-08-01T01:30:00.000Z]",
@@ -60,7 +60,6 @@
protected NodeTypeManager nodeTypeManager;
-
@Override
@Before
public void beforeEach() throws Exception {
@@ -77,7 +76,7 @@
graph.set("jcr:mixinTypes").on("/a").to(JcrMixLexicon.REFERENCEABLE);
}
-
+
@After
public void after() throws Exception {
if (session != null && session.isLive()) {
Modified: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrSessionTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrSessionTest.java 2009-07-09 16:27:15 UTC (rev 1083)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrSessionTest.java 2009-07-09 16:29:03 UTC (rev 1084)
@@ -66,7 +66,7 @@
/**
* @author jverhaeg
*/
-public class JcrSessionTest extends AbstractJcrTest {
+public class JcrSessionTest extends AbstractSessionTest {
private static final String MULTI_LINE_VALUE = "Line\t1\nLine 2\rLine 3\r\nLine 4";
@@ -74,6 +74,7 @@
@Before
public void beforeEach() throws Exception {
super.beforeEach();
+
}
@Override
@@ -88,20 +89,8 @@
// Make sure the path to the namespaces exists ...
graph.create("/jcr:system").and().create("/jcr:system/dna:namespaces").and();
- // Set up the session attributes ...
- sessionAttributes = new HashMap<String, Object>();
- sessionAttributes.put("attribute1", "value1");
-
- // Now create the workspace ...
- SecurityContext mockSecurityContext = new MockSecurityContext(null,
- Collections.singleton(JcrSession.DNA_WRITE_PERMISSION));
- workspace = new JcrWorkspace(repository, workspaceName, context.with(mockSecurityContext), sessionAttributes);
-
- // Create the session and log in ...
- session = (JcrSession)workspace.getSession();
}
-
@After
public void after() throws Exception {
if (session.isLive()) {
@@ -247,6 +236,8 @@
public void shouldProvideRootNode() throws Exception {
Node root = session.getRootNode();
assertThat(root, notNullValue());
+ String uuid = root.getUUID();
+ assertThat(uuid, notNullValue());
}
@Test
@@ -420,15 +411,6 @@
* this test.
*/
- @Test
- public void shouldProvideUuidIfReferenceable() throws Exception {
- // The root node is referenceable in DNA
- Node rootNode = session.getRootNode();
-
- UUID uuid = ((AbstractJcrNode)rootNode).location.getUuid();
- assertThat(rootNode.getUUID(), is(uuid.toString()));
- }
-
@Test( expected = UnsupportedRepositoryOperationException.class )
public void shouldNotProvideUuidIfNotReferenceable() throws Exception {
// The b node was not set up to be referenceable in this test, but does have a mixin type
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-09 16:27:15 UTC (rev 1083)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrTckTest.java 2009-07-09 16:29:03 UTC (rev 1084)
@@ -36,7 +36,6 @@
import org.apache.jackrabbit.test.api.NodeItemIsNewTest;
import org.apache.jackrabbit.test.api.NodeOrderableChildNodesTest;
import org.apache.jackrabbit.test.api.NodeRemoveMixinTest;
-import org.apache.jackrabbit.test.api.NodeTest;
import org.apache.jackrabbit.test.api.PropertyItemIsModifiedTest;
import org.apache.jackrabbit.test.api.PropertyItemIsNewTest;
import org.apache.jackrabbit.test.api.PropertyTest;
@@ -174,7 +173,7 @@
// addTestSuite(ReferencesTest.class);
// dna-466 addTestSuite(SessionTest.class);
// addTestSuite(SessionUUIDTest.class);
- addTestSuite(NodeTest.class);
+ // dna-466 addTestSuite(NodeTest.class);
// addTestSuite(NodeUUIDTest.class);
addTestSuite(NodeOrderableChildNodesTest.class);
addTestSuite(PropertyTest.class);
Modified: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrWorkspaceTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrWorkspaceTest.java 2009-07-09 16:27:15 UTC (rev 1083)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrWorkspaceTest.java 2009-07-09 16:29:03 UTC (rev 1084)
@@ -41,7 +41,7 @@
/**
* @author jverhaeg
*/
-public class JcrWorkspaceTest extends AbstractJcrTest {
+public class JcrWorkspaceTest extends AbstractSessionTest {
@BeforeClass
public static void beforeClass() {
@@ -73,7 +73,7 @@
graph.create("/jcr:system").and().create("/jcr:system/dna:namespaces").ifAbsent().and();
}
-
+
@Test( expected = IllegalArgumentException.class )
public void shouldNotAllowCloneWithNullWorkspaceName() throws Exception {
workspace.clone(null, "/src", "/dest", false);
Modified: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/MixinTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/MixinTest.java 2009-07-09 16:27:15 UTC (rev 1083)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/MixinTest.java 2009-07-09 16:29:03 UTC (rev 1084)
@@ -44,7 +44,7 @@
import org.junit.Before;
import org.junit.Test;
-public class MixinTest extends AbstractJcrTest {
+public class MixinTest extends AbstractSessionTest {
/*
* Declares the following node types:
@@ -235,7 +235,9 @@
public void shouldAllowAdditionIfResidualChildNodeDoesNotConflict() throws Exception {
graph.create("/a").and().create("/a/" + CHILD_NODE_B).and();
graph.set(JcrLexicon.PRIMARY_TYPE.getString(registry)).on("/a").to(JcrNtLexicon.UNSTRUCTURED.getString(registry));
- graph.set(JcrLexicon.PRIMARY_TYPE.getString(registry)).on("/a/" + CHILD_NODE_B).to(JcrNtLexicon.UNSTRUCTURED.getString(registry));
+ graph.set(JcrLexicon.PRIMARY_TYPE.getString(registry))
+ .on("/a/" + CHILD_NODE_B)
+ .to(JcrNtLexicon.UNSTRUCTURED.getString(registry));
Node rootNode = session.getRootNode();
Node nodeA = rootNode.getNode("a");
Modified: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/RepositoryNodeTypeManagerTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/RepositoryNodeTypeManagerTest.java 2009-07-09 16:27:15 UTC (rev 1083)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/RepositoryNodeTypeManagerTest.java 2009-07-09 16:29:03 UTC (rev 1084)
@@ -49,10 +49,9 @@
import org.jboss.dna.graph.property.NamespaceRegistry;
import org.junit.After;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
-public class RepositoryNodeTypeManagerTest extends AbstractJcrTest {
+public class RepositoryNodeTypeManagerTest extends AbstractSessionTest {
@Override
@Before
@@ -80,24 +79,8 @@
options = new EnumMap<JcrRepository.Option, String>(JcrRepository.Option.class);
options.put(JcrRepository.Option.PROJECT_NODE_TYPES, Boolean.TRUE.toString());
- stub(repository.getOptions()).toReturn(options);
-
- // Set up the session attributes ...
- sessionAttributes = new HashMap<String, Object>();
- sessionAttributes.put("attribute1", "value1");
-
- // Now create the workspace ...
- SecurityContext mockSecurityContext = new MockSecurityContext("testuser",
- Collections.singleton(JcrSession.DNA_READ_PERMISSION));
- workspace = new JcrWorkspace(repository, workspaceName, context.with(mockSecurityContext), sessionAttributes);
-
- // Create the session and log in ...
- session = (JcrSession)workspace.getSession();
-
- graph.set("jcr:primaryType").on("/jcr:system/dna:namespaces").to(DnaLexicon.NAMESPACES);
-
}
-
+
@After
public void after() throws Exception {
if (session != null && session.isLive()) {
@@ -119,7 +102,6 @@
assertEquals(namespacesNodes.getSize(), 1);
}
- @Ignore( "dna-466" )
@Test
public void shouldOnlyHaveOneNodeTypesNode() throws Exception {
NamespaceRegistry registry = context.getNamespaceRegistry();
@@ -130,7 +112,7 @@
Node systemNode = rootNode.getNode(JcrLexicon.SYSTEM.getString(registry));
assertThat(systemNode, is(notNullValue()));
- NodeIterator nodeTypesNodes = systemNode.getNodes(JcrLexicon.NODE_TYPES.getString(registry));
+ NodeIterator nodeTypesNodes = systemNode.getNodes(DnaLexicon.NODE_TYPES.getString(registry));
assertEquals(nodeTypesNodes.getSize(), 1);
}
@@ -160,7 +142,7 @@
Node systemNode = rootNode.getNode(JcrLexicon.SYSTEM.getString(registry));
assertThat(systemNode, is(notNullValue()));
- Node typesNode = systemNode.getNode(JcrLexicon.NODE_TYPES.getString(registry));
+ Node typesNode = systemNode.getNode(DnaLexicon.NODE_TYPES.getString(registry));
assertThat(typesNode, is(notNullValue()));
Collection<JcrNodeType> allNodeTypes = repoTypeManager.getAllNodeTypes();
Modified: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/TypeRegistrationTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/TypeRegistrationTest.java 2009-07-09 16:27:15 UTC (rev 1083)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/TypeRegistrationTest.java 2009-07-09 16:29:03 UTC (rev 1084)
@@ -46,7 +46,7 @@
import org.junit.Before;
import org.junit.Test;
-public class TypeRegistrationTest extends AbstractJcrTest {
+public class TypeRegistrationTest extends AbstractSessionTest {
private static final String TEST_TYPE_NAME = "dna:testNode";
private static final String TEST_TYPE_NAME2 = "dna:testNode2";
@@ -691,97 +691,94 @@
* Unregistration tests
*/
- @Test (expected=IllegalArgumentException.class)
+ @Test( expected = IllegalArgumentException.class )
public void shouldNotAllowUnregisteringNullCollection() throws Exception {
repoTypeManager.unregisterNodeType(null);
}
-
- @Test (expected=NoSuchNodeTypeException.class)
+
+ @Test( expected = NoSuchNodeTypeException.class )
public void shouldNotAllowUnregisteringInvalidTypeNames() throws Exception {
- repoTypeManager.unregisterNodeType(Arrays.asList(new Name[] { JcrNtLexicon.FILE, JcrLexicon.DATA}));
+ repoTypeManager.unregisterNodeType(Arrays.asList(new Name[] {JcrNtLexicon.FILE, JcrLexicon.DATA}));
}
- @Test (expected=InvalidNodeTypeDefinitionException.class)
+ @Test( expected = InvalidNodeTypeDefinitionException.class )
public void shouldNotAllowUnregisteringSupertype() throws Exception {
- repoTypeManager.unregisterNodeType(Arrays.asList(new Name[] { JcrNtLexicon.HIERARCHY_NODE, }));
-
+ repoTypeManager.unregisterNodeType(Arrays.asList(new Name[] {JcrNtLexicon.HIERARCHY_NODE,}));
+
}
- @Test (expected=InvalidNodeTypeDefinitionException.class)
+ @Test( expected = InvalidNodeTypeDefinitionException.class )
public void shouldNotAllowUnregisteringRequiredPrimaryType() throws Exception {
- repoTypeManager.unregisterNodeType(Arrays.asList(new Name[] { JcrNtLexicon.FROZEN_NODE, }));
+ repoTypeManager.unregisterNodeType(Arrays.asList(new Name[] {JcrNtLexicon.FROZEN_NODE,}));
}
-
- @Test (expected=InvalidNodeTypeDefinitionException.class)
+
+ @Test( expected = InvalidNodeTypeDefinitionException.class )
public void shouldNotAllowUnregisteringDefaultPrimaryType() throws Exception {
ntTemplate.setName(TEST_TYPE_NAME);
-
+
JcrNodeDefinitionTemplate childNode = new JcrNodeDefinitionTemplate(this.context);
childNode.setDefaultPrimaryType(JcrNtLexicon.FILE.getString(this.registry));
ntTemplate.getNodeDefinitionTemplates().add(childNode);
-
+
try {
repoTypeManager.registerNodeType(ntTemplate, false);
- }
- catch (Exception ex) {
+ } catch (Exception ex) {
fail(ex.getMessage());
}
-
- repoTypeManager.unregisterNodeType(Arrays.asList(new Name[] { JcrNtLexicon.FILE, }));
+
+ repoTypeManager.unregisterNodeType(Arrays.asList(new Name[] {JcrNtLexicon.FILE,}));
}
- @Test
+ @Test
public void shouldAllowUnregisteringUnusedType() throws Exception {
ntTemplate.setName(TEST_TYPE_NAME);
-
+
JcrNodeDefinitionTemplate childNode = new JcrNodeDefinitionTemplate(this.context);
childNode.setDefaultPrimaryType(JcrNtLexicon.FILE.getString(this.registry));
ntTemplate.getNodeDefinitionTemplates().add(childNode);
-
+
try {
repoTypeManager.registerNodeType(ntTemplate, false);
- }
- catch (Exception ex) {
+ } catch (Exception ex) {
fail(ex.getMessage());
}
-
+
Name typeNameAsName = nameFactory.create(TEST_TYPE_NAME);
int nodeTypeCount = repoTypeManager.getAllNodeTypes().size();
- repoTypeManager.unregisterNodeType(Arrays.asList(new Name[] { typeNameAsName }));
+ repoTypeManager.unregisterNodeType(Arrays.asList(new Name[] {typeNameAsName}));
assertThat(repoTypeManager.getAllNodeTypes().size(), is(nodeTypeCount - 1));
assertThat(repoTypeManager.getNodeType(typeNameAsName), is(nullValue()));
}
- @Test
+ @Test
public void shouldAllowUnregisteringUnusedTypesWithMutualDependencies() throws Exception {
ntTemplate.setName(TEST_TYPE_NAME);
-
+
JcrNodeDefinitionTemplate childNode = new JcrNodeDefinitionTemplate(this.context);
childNode.setDefaultPrimaryType(TEST_TYPE_NAME2);
ntTemplate.getNodeDefinitionTemplates().add(childNode);
NodeTypeTemplate ntTemplate2 = new JcrNodeTypeTemplate(this.context);
ntTemplate2.setName(TEST_TYPE_NAME2);
-
+
JcrNodeDefinitionTemplate childNode2 = new JcrNodeDefinitionTemplate(this.context);
childNode2.setDefaultPrimaryType(TEST_TYPE_NAME);
ntTemplate2.getNodeDefinitionTemplates().add(childNode2);
try {
- repoTypeManager.registerNodeTypes(Arrays.asList(new NodeTypeDefinition[] { ntTemplate, ntTemplate2 }), false);
- }
- catch (Exception ex) {
+ repoTypeManager.registerNodeTypes(Arrays.asList(new NodeTypeDefinition[] {ntTemplate, ntTemplate2}), false);
+ } catch (Exception ex) {
fail(ex.getMessage());
}
-
+
Name typeNameAsName = nameFactory.create(TEST_TYPE_NAME);
Name type2NameAsName = nameFactory.create(TEST_TYPE_NAME2);
int nodeTypeCount = repoTypeManager.getAllNodeTypes().size();
- repoTypeManager.unregisterNodeType(Arrays.asList(new Name[] { typeNameAsName, type2NameAsName }));
+ repoTypeManager.unregisterNodeType(Arrays.asList(new Name[] {typeNameAsName, type2NameAsName}));
assertThat(repoTypeManager.getAllNodeTypes().size(), is(nodeTypeCount - 2));
assertThat(repoTypeManager.getNodeType(typeNameAsName), is(nullValue()));
assertThat(repoTypeManager.getNodeType(type2NameAsName), is(nullValue()));
-
+
}
private void compareTemplatesToNodeTypes( List<NodeTypeDefinition> templates,
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-07-09 16:27:15 UTC (rev 1083)
+++ trunk/extensions/dna-connector-jbosscache/src/main/java/org/jboss/dna/connector/jbosscache/JBossCacheSource.java 2009-07-09 16:29:03 UTC (rev 1084)
@@ -477,7 +477,7 @@
// Create the set of initial names ...
for (String initialName : getPredefinedWorkspaceNames())
repository.createWorkspace(null, initialName, CreateConflictBehavior.DO_NOT_CREATE);
-
+
}
return new MapRepositoryConnection(this, this.repository);
@@ -488,11 +488,13 @@
* probably called at most once for each workspace name (except if this method fails to create a cache for a given workspace
* name).
*
- * @param workspaceName the name of the workspace
+ * @param cacheFactory the cache factory
+ * @param repositoryName the name of the repository
* @return the new cache that corresponds to the workspace name
*/
@GuardedBy( "writeLock" )
- protected Cache<UUID, MapNode> createNewCache( CacheFactory<UUID, MapNode> cacheFactory, String repositoryName ) {
+ protected Cache<UUID, MapNode> createNewCache( CacheFactory<UUID, MapNode> cacheFactory,
+ String repositoryName ) {
assert repositoryName != null;
if (cacheFactory == null) return null;
@@ -523,7 +525,6 @@
return cacheFactory.createCache();
}
-
/**
* @return repositoryContext
*/
16 years, 6 months
DNA SVN: r1083 - in trunk: dna-jcr/src/main/java/org/jboss/dna/jcr and 1 other directories.
by dna-commits@lists.jboss.org
Author: rhauch
Date: 2009-07-09 12:27:15 -0400 (Thu, 09 Jul 2009)
New Revision: 1083
Modified:
trunk/dna-graph/src/test/java/org/jboss/dna/graph/session/GraphSessionTest.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrWorkspace.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/SessionCache.java
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/AbstractJcrTest.java
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/ImportExportTest.java
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrTckTest.java
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/RepositoryNodeTypeManagerTest.java
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/SessionCacheTest.java
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/SessionCacheTest2.java
Log:
DNA-466 Additional changes and corrections, along with the commenting-out of unit tests that don't yet pass (all have 'dna-466' in the comment, either in the @Ignore() annotation or in the JcrTckTest class as line comments.
Modified: trunk/dna-graph/src/test/java/org/jboss/dna/graph/session/GraphSessionTest.java
===================================================================
--- trunk/dna-graph/src/test/java/org/jboss/dna/graph/session/GraphSessionTest.java 2009-07-09 16:26:04 UTC (rev 1082)
+++ trunk/dna-graph/src/test/java/org/jboss/dna/graph/session/GraphSessionTest.java 2009-07-09 16:27:15 UTC (rev 1083)
@@ -375,7 +375,7 @@
try {
cache.save(utility);
fail("Expected exception from the call to save");
- } catch (InvalidStateException e) {
+ } catch (ValidationException e) {
// expected ...
}
} else if (i == 1) {
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrWorkspace.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrWorkspace.java 2009-07-09 16:26:04 UTC (rev 1082)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrWorkspace.java 2009-07-09 16:27:15 UTC (rev 1083)
@@ -26,8 +26,10 @@
import java.io.IOException;
import java.io.InputStream;
import java.security.AccessControlException;
+import java.util.HashSet;
import java.util.Map;
import java.util.Set;
+import java.util.UUID;
import javax.jcr.AccessDeniedException;
import javax.jcr.InvalidSerializedDataException;
import javax.jcr.ItemExistsException;
@@ -50,6 +52,9 @@
import org.jboss.dna.common.util.CheckArg;
import org.jboss.dna.graph.ExecutionContext;
import org.jboss.dna.graph.Graph;
+import org.jboss.dna.graph.Location;
+import org.jboss.dna.graph.Subgraph;
+import org.jboss.dna.graph.SubgraphNode;
import org.jboss.dna.graph.connector.RepositoryConnectionFactory;
import org.jboss.dna.graph.connector.RepositorySource;
import org.jboss.dna.graph.connector.RepositorySourceException;
@@ -62,6 +67,8 @@
import org.jboss.dna.graph.property.ValueFormatException;
import org.jboss.dna.graph.property.basic.GraphNamespaceRegistry;
import org.jboss.dna.graph.request.InvalidWorkspaceException;
+import org.jboss.dna.graph.request.ReadBranchRequest;
+import org.jboss.dna.graph.session.GraphSession;
import org.jboss.dna.graph.session.GraphSession.Node;
import org.jboss.dna.jcr.JcrContentHandler.EnclosingSAXException;
import org.jboss.dna.jcr.JcrContentHandler.SaveMode;
@@ -314,6 +321,38 @@
Node<JcrNodePayload, JcrPropertyPayload> parent = cache.findNode(null, destPath.getParent());
cache.findBestNodeDefinition(parent, newNodeName, parent.getPayload().getPrimaryTypeName());
+ if (removeExisting) {
+ // This will remove any existing nodes in this (the "target") workspace that have the same UUIDs
+ // as nodes that will be put into this workspace with the clone operation. Thus, any such
+ // existing nodes will be removed; but if they're mandatory they cannot be removed, resulting
+ // in a ConstraintViolationException. Therefore, we have to do a little homework here ...
+ Set<UUID> uuidsInCloneBranch = getUuidsInBranch(srcPath, srcWorkspace);
+ if (!uuidsInCloneBranch.isEmpty()) {
+ // See if any of these exist in the current workspace, and if so whether they can be removed ...
+ // This is NOT very efficient, since it may result in a batch read for each node ...
+ GraphSession<JcrNodePayload, JcrPropertyPayload> graphSession = cache.graphSession();
+ Node<JcrNodePayload, JcrPropertyPayload> node = null;
+ for (UUID uuid : uuidsInCloneBranch) {
+ Location location = Location.create(uuid);
+ try {
+ node = graphSession.findNodeWith(location);
+ } catch (org.jboss.dna.graph.property.PathNotFoundException e) {
+ // okay, it's not found in the current workspace, so nothing to check ...
+ continue;
+ }
+ // Get the node type that owns the child node definition ...
+ NodeDefinitionId childDefnId = node.getPayload().getDefinitionId();
+ JcrNodeType nodeType = nodeTypeManager().getNodeType(childDefnId.getNodeTypeName());
+ JcrNodeDefinition childDefn = nodeType.childNodeDefinition(childDefnId);
+ if (childDefn.isMandatory()) {
+ // We can't just remove a mandatory node... unless its parent will be removed too!
+ String path = node.getPath().getString(context.getNamespaceRegistry());
+ throw new ConstraintViolationException(JcrI18n.cannotRemoveNodeFromClone.text(path, uuid));
+ }
+ }
+ }
+ }
+
// Now perform the clone, using the direct (non-session) method ...
cache.graphSession().immediateClone(srcPath, srcWorkspace, destPath, removeExisting);
} catch (ItemNotFoundException e) {
@@ -332,6 +371,24 @@
}
}
+ protected Set<UUID> getUuidsInBranch( Path sourcePath,
+ String workspace ) {
+ String existingWorkspace = graph.getCurrentWorkspaceName();
+ try {
+ graph.useWorkspace(workspace);
+ Subgraph subgraph = graph.getSubgraphOfDepth(ReadBranchRequest.NO_MAXIMUM_DEPTH).at(sourcePath);
+ // Collect up the UUIDs; we use UUID here because that's what JCR requires ...
+ Set<UUID> uuids = new HashSet<UUID>();
+ for (SubgraphNode nodeInSubgraph : subgraph) {
+ UUID uuid = nodeInSubgraph.getLocation().getUuid();
+ if (uuid != null) uuids.add(uuid);
+ }
+ return uuids;
+ } finally {
+ graph.useWorkspace(existingWorkspace);
+ }
+ }
+
/**
* {@inheritDoc}
*
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-09 16:26:04 UTC (rev 1082)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/SessionCache.java 2009-07-09 16:27:15 UTC (rev 1083)
@@ -1194,7 +1194,7 @@
existingChild.moveTo(node, newNodeName);
NodeDefinitionId existingChildDefinitionId = existingChild.getPayload().getDefinitionId();
- if (defn.getId().equals(existingChildDefinitionId)) {
+ if (!defn.getId().equals(existingChildDefinitionId)) {
// The node definition changed, so try to set the property ...
NodeEditor newChildEditor = getEditorFor(existingChild);
try {
Modified: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/AbstractJcrTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/AbstractJcrTest.java 2009-07-09 16:26:04 UTC (rev 1082)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/AbstractJcrTest.java 2009-07-09 16:27:15 UTC (rev 1083)
@@ -43,7 +43,7 @@
/**
*
*/
-public class AbstractJcrTest {
+public abstract class AbstractJcrTest {
protected static ExecutionContext context;
protected static RepositoryNodeTypeManager rntm;
@@ -105,7 +105,8 @@
store = Graph.create(source.getName(), connectionFactory, context);
// Load the store with content ...
- store.importXmlFrom(AbstractJcrTest.class.getClassLoader().getResourceAsStream("cars.xml")).into("/");
+ String xmlResourceName = getResourceNameOfXmlFileToImport();
+ store.importXmlFrom(AbstractJcrTest.class.getClassLoader().getResourceAsStream(xmlResourceName)).into("/");
numberOfConnections = 0; // reset the number of connections
nodeTypes = new JcrNodeTypeManager(context, rntm);
@@ -123,6 +124,10 @@
stub(workspace.getName()).toReturn("workspace1");
}
+ protected String getResourceNameOfXmlFileToImport() {
+ return "cars.xml";
+ }
+
protected Name name( String name ) {
return context.getValueFactories().getNameFactory().create(name);
}
Modified: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/ImportExportTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/ImportExportTest.java 2009-07-09 16:26:04 UTC (rev 1082)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/ImportExportTest.java 2009-07-09 16:27:15 UTC (rev 1083)
@@ -46,7 +46,6 @@
/**
* Tests of round-trip importing/exporting of repository content.
- *
*/
public class ImportExportTest {
@@ -54,14 +53,13 @@
SYSTEM,
DOCUMENT
}
-
+
private static final String BAD_CHARACTER_STRING = "Test & <Test>*";
-
private InMemoryRepositorySource source;
private JcrSession session;
private JcrRepository repository;
-
+
@Before
public void beforeEach() throws Exception {
MockitoAnnotations.initMocks(this);
@@ -100,8 +98,9 @@
repository = new JcrRepository(context, connectionFactory, "unused");
- SecurityContext mockSecurityContext = new MockSecurityContext("testuser", Collections.singleton(JcrSession.DNA_WRITE_PERMISSION));
- session = (JcrSession) repository.login(new SecurityContextCredentials(mockSecurityContext));
+ SecurityContext mockSecurityContext = new MockSecurityContext("testuser",
+ Collections.singleton(JcrSession.DNA_WRITE_PERMISSION));
+ session = (JcrSession)repository.login(new SecurityContextCredentials(mockSecurityContext));
}
@After
@@ -110,55 +109,57 @@
session.logout();
}
}
-
- private void testImportExport(String sourcePath, String targetPath, ExportType useSystemView, boolean skipBinary, boolean noRecurse)
- throws Exception
- {
+
+ private void testImportExport( String sourcePath,
+ String targetPath,
+ ExportType useSystemView,
+ boolean skipBinary,
+ boolean noRecurse ) throws Exception {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
-
+
if (useSystemView == ExportType.SYSTEM) {
session.exportSystemView(sourcePath, baos, skipBinary, noRecurse);
- }
- else {
+ } else {
session.exportDocumentView(sourcePath, baos, skipBinary, noRecurse);
}
-
+
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
-
+
session.importXML(targetPath, bais, ImportUUIDBehavior.IMPORT_UUID_CREATE_NEW);
}
+ @Ignore( "dna-466" )
@Test
public void shouldImportExportEscapedXmlCharactersInSystemView() throws Exception {
String testName = "importExportEscapedXmlCharacters";
Node rootNode = session.getRootNode();
Node sourceNode = rootNode.addNode(testName + "Source", "nt:unstructured");
Node targetNode = rootNode.addNode(testName + "Target", "nt:unstructured");
-
+
// Test data
sourceNode.setProperty("badcharacters", BAD_CHARACTER_STRING);
assertThat(sourceNode.getProperty("badcharacters").getString(), is(BAD_CHARACTER_STRING));
sourceNode.addNode(BAD_CHARACTER_STRING);
-
+
testImportExport(sourceNode.getPath(), targetNode.getPath(), ExportType.SYSTEM, false, false);
Node newSourceNode = targetNode.getNode(testName + "Source");
newSourceNode.getNode(BAD_CHARACTER_STRING);
assertThat(newSourceNode.getProperty("badcharacters").getString(), is(BAD_CHARACTER_STRING));
}
- @Ignore("JR TCK is broken")
+ @Ignore( "JR TCK is broken" )
@Test
public void shouldImportExportEscapedXmlCharactersInDocumentView() throws Exception {
String testName = "importExportEscapedXmlCharacters";
Node rootNode = session.getRootNode();
Node sourceNode = rootNode.addNode(testName + "Source", "nt:unstructured");
Node targetNode = rootNode.addNode(testName + "Target", "nt:unstructured");
-
+
// Test data
sourceNode.setProperty("badcharacters", BAD_CHARACTER_STRING);
assertThat(sourceNode.getProperty("badcharacters").getString(), is(BAD_CHARACTER_STRING));
sourceNode.addNode(BAD_CHARACTER_STRING);
-
+
testImportExport(sourceNode.getPath(), targetNode.getPath(), ExportType.DOCUMENT, false, false);
Node newSourceNode = targetNode.getNode(testName + "Source");
newSourceNode.getNode(BAD_CHARACTER_STRING);
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-09 16:26:04 UTC (rev 1082)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrTckTest.java 2009-07-09 16:27:15 UTC (rev 1083)
@@ -28,7 +28,6 @@
import org.apache.jackrabbit.test.JCRTestSuite;
import org.apache.jackrabbit.test.api.AddNodeTest;
import org.apache.jackrabbit.test.api.CheckPermissionTest;
-import org.apache.jackrabbit.test.api.DocumentViewImportTest;
import org.apache.jackrabbit.test.api.ImpersonateTest;
import org.apache.jackrabbit.test.api.NamespaceRegistryTest;
import org.apache.jackrabbit.test.api.NodeAddMixinTest;
@@ -42,8 +41,6 @@
import org.apache.jackrabbit.test.api.PropertyItemIsNewTest;
import org.apache.jackrabbit.test.api.PropertyTest;
import org.apache.jackrabbit.test.api.RepositoryLoginTest;
-import org.apache.jackrabbit.test.api.SerializationTest;
-import org.apache.jackrabbit.test.api.SessionTest;
import org.apache.jackrabbit.test.api.SetPropertyAssumeTypeTest;
import org.apache.jackrabbit.test.api.SetPropertyBooleanTest;
import org.apache.jackrabbit.test.api.SetPropertyCalendarTest;
@@ -65,7 +62,6 @@
import org.apache.jackrabbit.test.api.SetValueValueFormatExceptionTest;
import org.apache.jackrabbit.test.api.SetValueVersionExceptionTest;
import org.apache.jackrabbit.test.api.ValueFactoryTest;
-import org.apache.jackrabbit.test.api.WorkspaceCloneReferenceableTest;
import org.apache.jackrabbit.test.api.WorkspaceCloneSameNameSibsTest;
import org.apache.jackrabbit.test.api.WorkspaceCloneVersionableTest;
import org.apache.jackrabbit.test.api.WorkspaceCopyBetweenWorkspacesReferenceableTest;
@@ -75,7 +71,6 @@
import org.apache.jackrabbit.test.api.WorkspaceCopyReferenceableTest;
import org.apache.jackrabbit.test.api.WorkspaceCopySameNameSibsTest;
import org.apache.jackrabbit.test.api.WorkspaceCopyVersionableTest;
-import org.apache.jackrabbit.test.api.WorkspaceMoveReferenceableTest;
import org.apache.jackrabbit.test.api.WorkspaceMoveSameNameSibsTest;
import org.apache.jackrabbit.test.api.WorkspaceMoveVersionableTest;
@@ -177,7 +172,7 @@
addTestSuite(AddNodeTest.class);
addTestSuite(NamespaceRegistryTest.class);
// addTestSuite(ReferencesTest.class);
- addTestSuite(SessionTest.class);
+ // dna-466 addTestSuite(SessionTest.class);
// addTestSuite(SessionUUIDTest.class);
addTestSuite(NodeTest.class);
// addTestSuite(NodeUUIDTest.class);
@@ -215,7 +210,7 @@
addTestSuite(NodeCanAddMixinTest.class);
addTestSuite(NodeRemoveMixinTest.class);
- addTestSuite(WorkspaceCloneReferenceableTest.class);
+ // dna-466 addTestSuite(WorkspaceCloneReferenceableTest.class);
addTestSuite(WorkspaceCloneSameNameSibsTest.class);
// addTestSuite(WorkspaceCloneTest.class);
addTestSuite(WorkspaceCloneVersionableTest.class);
@@ -227,7 +222,7 @@
addTestSuite(WorkspaceCopySameNameSibsTest.class);
// addTestSuite(WorkspaceCopyTest.class);
addTestSuite(WorkspaceCopyVersionableTest.class);
- addTestSuite(WorkspaceMoveReferenceableTest.class);
+ // dna-466 addTestSuite(WorkspaceMoveReferenceableTest.class);
addTestSuite(WorkspaceMoveSameNameSibsTest.class);
// addTestSuite(WorkspaceMoveTest.class);
addTestSuite(WorkspaceMoveVersionableTest.class);
@@ -236,8 +231,8 @@
addTestSuite(ImpersonateTest.class);
addTestSuite(CheckPermissionTest.class);
- addTestSuite(DocumentViewImportTest.class);
- addTestSuite(SerializationTest.class);
+ // dna-466 addTestSuite(DocumentViewImportTest.class);
+ // dna-466 addTestSuite(SerializationTest.class);
addTestSuite(ValueFactoryTest.class);
}
Modified: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/RepositoryNodeTypeManagerTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/RepositoryNodeTypeManagerTest.java 2009-07-09 16:26:04 UTC (rev 1082)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/RepositoryNodeTypeManagerTest.java 2009-07-09 16:27:15 UTC (rev 1083)
@@ -49,6 +49,7 @@
import org.jboss.dna.graph.property.NamespaceRegistry;
import org.junit.After;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
public class RepositoryNodeTypeManagerTest extends AbstractJcrTest {
@@ -79,6 +80,22 @@
options = new EnumMap<JcrRepository.Option, String>(JcrRepository.Option.class);
options.put(JcrRepository.Option.PROJECT_NODE_TYPES, Boolean.TRUE.toString());
+ stub(repository.getOptions()).toReturn(options);
+
+ // Set up the session attributes ...
+ sessionAttributes = new HashMap<String, Object>();
+ sessionAttributes.put("attribute1", "value1");
+
+ // Now create the workspace ...
+ SecurityContext mockSecurityContext = new MockSecurityContext("testuser",
+ Collections.singleton(JcrSession.DNA_READ_PERMISSION));
+ workspace = new JcrWorkspace(repository, workspaceName, context.with(mockSecurityContext), sessionAttributes);
+
+ // Create the session and log in ...
+ session = (JcrSession)workspace.getSession();
+
+ graph.set("jcr:primaryType").on("/jcr:system/dna:namespaces").to(DnaLexicon.NAMESPACES);
+
}
@After
@@ -102,6 +119,7 @@
assertEquals(namespacesNodes.getSize(), 1);
}
+ @Ignore( "dna-466" )
@Test
public void shouldOnlyHaveOneNodeTypesNode() throws Exception {
NamespaceRegistry registry = context.getNamespaceRegistry();
@@ -162,8 +180,8 @@
assertThat(nodeType.hasOrderableChildNodes(),
is(typeNode.getProperty(JcrLexicon.HAS_ORDERABLE_CHILD_NODES.getString(registry)).getBoolean()));
try {
- assertThat(nodeType.getPrimaryItemName(),
- is(typeNode.getProperty(JcrLexicon.PRIMARY_ITEM_NAME.getString(registry)).getString()));
+ assertThat(nodeType.getPrimaryItemName(), is(typeNode.getProperty(JcrLexicon.PRIMARY_ITEM_NAME.getString(registry))
+ .getString()));
} catch (PathNotFoundException pnfe) {
assertThat(nodeType.getPrimaryItemName(), is(nullValue()));
}
@@ -226,7 +244,8 @@
Set<Name> requiredPrimaryTypeNames = nodeDef.getRequiredPrimaryTypeNames();
try {
- Value[] requiredPrimaryTypes = childNodeNode.getProperty(JcrLexicon.REQUIRED_PRIMARY_TYPES.getString(registry)).getValues();
+ Value[] requiredPrimaryTypes = childNodeNode.getProperty(JcrLexicon.REQUIRED_PRIMARY_TYPES.getString(registry))
+ .getValues();
assertEquals(requiredPrimaryTypes.length, requiredPrimaryTypeNames.size());
for (int i = 0; i < requiredPrimaryTypes.length; i++) {
Name rptName = context.getValueFactories().getNameFactory().create(requiredPrimaryTypes[i].getString());
@@ -249,7 +268,8 @@
assertEquals(nodeDef.allowsSameNameSiblings(),
childNodeNode.getProperty(JcrLexicon.SAME_NAME_SIBLINGS.getString(registry)).getBoolean());
assertEquals(nodeDef.getOnParentVersion(),
- OnParentVersionAction.valueFromName(childNodeNode.getProperty(JcrLexicon.ON_PARENT_VERSION.getString(registry)).getString()));
+ OnParentVersionAction.valueFromName(childNodeNode.getProperty(JcrLexicon.ON_PARENT_VERSION.getString(registry))
+ .getString()));
}
@@ -270,7 +290,8 @@
assertEquals(propertyDef.isMultiple(), propNode.getProperty(JcrLexicon.MULTIPLE.getString(registry)).getBoolean());
assertEquals(propertyDef.isProtected(), propNode.getProperty(JcrLexicon.PROTECTED.getString(registry)).getBoolean());
assertEquals(propertyDef.getOnParentVersion(),
- OnParentVersionAction.valueFromName(propNode.getProperty(JcrLexicon.ON_PARENT_VERSION.getString(registry)).getString()));
+ OnParentVersionAction.valueFromName(propNode.getProperty(JcrLexicon.ON_PARENT_VERSION.getString(registry))
+ .getString()));
assertEquals(propertyDef.getRequiredType(),
PropertyType.valueFromName(propNode.getProperty(JcrLexicon.REQUIRED_TYPE.getString(registry)).getString()));
Modified: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/SessionCacheTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/SessionCacheTest.java 2009-07-09 16:26:04 UTC (rev 1082)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/SessionCacheTest.java 2009-07-09 16:27:15 UTC (rev 1083)
@@ -6,8 +6,8 @@
* See the AUTHORS.txt file in the distribution for a full listing of
* individual contributors.
*
- * Unless otherwise indicated, all code in JBoss DNA is licensed
- * to you under the terms of the GNU Lesser General Public License as
+ * 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.
*
@@ -23,599 +23,360 @@
*/
package org.jboss.dna.jcr;
+import static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.IsNot.not;
+import static org.hamcrest.core.IsNull.notNullValue;
+import static org.hamcrest.core.IsSame.sameInstance;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.fail;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import java.util.UUID;
+import javax.jcr.PropertyType;
+import javax.jcr.RepositoryException;
+import javax.jcr.Value;
+import javax.jcr.ValueFormatException;
+import org.jboss.dna.graph.Location;
+import org.jboss.dna.graph.property.Name;
+import org.jboss.dna.graph.property.Property;
+import org.jboss.dna.graph.session.GraphSession.Node;
+import org.jboss.dna.graph.session.GraphSession.PropertyInfo;
+import org.jboss.dna.jcr.SessionCache.JcrNodePayload;
+import org.jboss.dna.jcr.SessionCache.JcrPropertyPayload;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ *
+ */
public class SessionCacheTest extends AbstractJcrTest {
- // @Override
- // @Before
- // public void beforeEach() throws Exception {
- // super.beforeEach();
- // }
- //
- // protected Graph createFrom( String repositoryName,
- // String workspaceName,
- // File file ) throws IOException, SAXException {
- // InMemoryRepositorySource source = new InMemoryRepositorySource();
- // source.setName(repositoryName);
- // Graph graph = Graph.create(source, context);
- // graph.createWorkspace().named(workspaceName);
- //
- // if (file != null) {
- // graph.importXmlFrom(file).into("/");
- // }
- // return graph;
- // }
- //
- // protected Graph getGraph( String name ) throws IOException, SAXException {
- // Graph graph = storesByName.get(name);
- // if (graph == null) {
- // graph = createFrom(name, name + " workspace", new File("src/test/resources/" + name + ".xml"));
- // storesByName.put(name, graph);
- // }
- // return graph;
- // }
- //
- // protected SessionCache getCache( String name ) throws IOException, SAXException {
- // SessionCache cache = cachesByName.get(name);
- // if (cache == null) {
- // cache = new SessionCache(session, name + " workspace", context, nodeTypes, getGraph(name));
- // cachesByName.put(name, cache);
- // }
- // return cache;
- // }
- //
- // protected Name name( String name ) {
- // return context.getValueFactories().getNameFactory().create(name);
- // }
- //
- // protected Path path( String path ) {
- // return context.getValueFactories().getPathFactory().create(path);
- // }
- //
- // protected Path.Segment segment( String segment ) {
- // return context.getValueFactories().getPathFactory().createSegment(segment);
- // }
- //
- // protected String pad( String name ) {
- // return StringUtil.justifyLeft(name, 22, ' ');
- // }
- //
- // protected void assertSameProperties( Node<JcrNodePayload, JcrPropertyPayload> nodeInfo,
- // org.jboss.dna.graph.Node dnaNode ) {
- // assertThat(nodeInfo.getLocation(), is(dnaNode.getLocation()));
- // Set<Name> propertyNames = nodeInfo.getPropertyNames();
- // for (Name propertyName : propertyNames) {
- // PropertyInfo<JcrPropertyPayload> info = nodeInfo.getProperty(propertyName);
- // assertThat(info.getName(), is(propertyName));
- // assertThat(info.getProperty().getName(), is(propertyName));
- // Property actual = dnaNode.getProperty(propertyName);
- // if (actual != null) {
- // assertThat(info.getProperty().size(), is(actual.size()));
- // assertThat(info.getProperty().getValuesAsArray(), is(actual.getValuesAsArray()));
- // } else {
- // if (propertyName.equals(JcrLexicon.UUID)) {
- // // check for a DNA UUID property ...
- // actual = dnaNode.getProperty(DnaLexicon.UUID);
- // if (actual != null) {
- // assertThat(info.getProperty().size(), is(actual.size()));
- // assertThat(info.getProperty().getValuesAsArray(), is(actual.getValuesAsArray()));
- // } else {
- // fail("missing property \"" + propertyName + "\" on " + dnaNode);
- // }
- // } else if (propertyName.equals(JcrLexicon.PRIMARY_TYPE)) {
- // // This is okay
- // } else if (propertyName.equals(DnaIntLexicon.MULTI_VALUED_PROPERTIES)) {
- // // This is okay
- // } else {
- // fail("missing property \"" + propertyName + "\" on " + dnaNode);
- // }
- // }
- // }
- // }
- //
- // protected JcrValue value( int propertyType,
- // Object value ) {
- // return new JcrValue(context.getValueFactories(), cache, propertyType, value);
- // }
- //
- // protected void assertDoesExist( Graph graph,
- // Location location ) {
- // org.jboss.dna.graph.Node node = store.getNodeAt(location);
- // assertThat(node, is(notNullValue()));
- // assertThat(node.getLocation(), is(location));
- // }
- //
- // protected void assertDoesNotExist( Graph graph,
- // Location location ) {
- // try {
- // store.getNodeAt(location);
- // fail("Shouldn't have found the node " + location);
- // } catch (PathNotFoundException e) {
- // // expected
- // }
- // }
- //
- // protected void assertDoesNotExist( Graph graph,
- // Path path ) {
- // try {
- // store.getNodeAt(path);
- // fail("Shouldn't have found the node " + path);
- // } catch (PathNotFoundException e) {
- // // expected
- // }
- // }
- //
- // protected void assertDoNotExist( Graph graph,
- // List<Location> locations ) {
- // for (Location location : locations)
- // assertDoesNotExist(graph, location);
- // }
- //
- // protected void assertProperty( org.jboss.dna.graph.session.GraphSession.Node<JcrNodePayload, JcrPropertyPayload> info,
- // Name propertyName,
- // int type,
- // Name nodeTypeName,
- // Name propertyDefinitionName,
- // int definitionType,
- // Object value ) {
- // PropertyDefinitionId defnId = new PropertyDefinitionId(nodeTypeName, propertyDefinitionName, definitionType, false);
- // PropertyInfo<JcrPropertyPayload> propertyInfo = info.getProperty(propertyName);
- // assertThat(propertyInfo, is(notNullValue()));
- // assertThat(propertyInfo.getPayload().getPropertyType(), is(type));
- // assertThat(propertyInfo.getPayload().getPropertyDefinitionId(), is(defnId));
- // org.jboss.dna.graph.property.PropertyType dnaPropertyType = PropertyTypeUtil.dnaPropertyTypeFor(type);
- // // Check the value ...
- // ValueFactory<?> factory = context.getValueFactories().getValueFactory(dnaPropertyType);
- // Object actual = factory.create(propertyInfo.getProperty().getFirstValue());
- // assertThat(actual, is(value));
- // }
- //
- // protected void assertProperty( org.jboss.dna.graph.session.GraphSession.Node<JcrNodePayload, JcrPropertyPayload> info,
- // Name propertyName,
- // int type,
- // Name nodeTypeName,
- // Name propertyDefinitionName,
- // int definitionType,
- // Object... values ) {
- // PropertyDefinitionId defnId = new PropertyDefinitionId(nodeTypeName, propertyDefinitionName, definitionType, true);
- // PropertyInfo<JcrPropertyPayload> propertyInfo = info.getProperty(propertyName);
- // assertThat(propertyInfo, is(notNullValue()));
- // assertThat(propertyInfo.getPayload().getPropertyType(), is(type));
- // assertThat(propertyInfo.getPayload().getPropertyDefinitionId(), is(defnId));
- // org.jboss.dna.graph.property.PropertyType dnaPropertyType = PropertyTypeUtil.dnaPropertyTypeFor(type);
- // // Check the values ...
- // ValueFactory<?> factory = context.getValueFactories().getValueFactory(dnaPropertyType);
- // int i = 0;
- // for (Object value : propertyInfo.getProperty()) {
- // assertThat(factory.create(value), is(values[i++]));
- // }
- // }
- //
- // protected void assertNoProperty( org.jboss.dna.graph.session.GraphSession.Node<JcrNodePayload, JcrPropertyPayload> info,
- // Name propertyName ) {
- // assertThat(info.getProperty(propertyName), is(nullValue()));
- // }
- //
- // @Test
- // public void shouldCreateWithValidParameters() {
- // assertThat(cache, is(notNullValue()));
- // }
- //
- // @Test
- // public void shouldRepeatedlyFindRootNodeInfoByPath() throws Exception {
- // String sourceName = "cars";
- // Graph store = getGraph(sourceName);
- // SessionCache cache = getCache(sourceName);
- // org.jboss.dna.graph.Node root = store.getNodeAt("/");
- // UUID rootUuid = root.getLocation().getUuid();
- // AbstractJcrNode nodeInfo = cache.findJcrRootNode();
- // assertSameProperties(nod, root)
- // assertThat(nodeInfo.getUuid(), is(rootUuid));
- // for (int i = 0; i != 20; ++i) {
- // sw.start();
- // assertThat(nodeInfo, is(sameInstance(cache.findNodeInfoForRoot())));
- // sw.stop();
- // assertThat(nodeInfo, is(sameInstance(cache.findNodeInfo(rootUuid))));
- // }
- // // System.out.println(pad(sourceName) + " ==> " + sw.getSimpleStatistics());
- // }
- //
- // @Test
- // public void shouldRepeatedlyFindRootNodeInfoByUuidFromVehiclesSource() throws Exception {
- // String sourceName = "vehicles";
- // Graph store = getGraph(sourceName);
- // SessionCache cache = getCache(sourceName);
- // sw.start();
- // Node root = store.getNodeAt("/");
- // sw.stop();
- // UUID rootUuid = root.getLocation().getUuid();
- // for (int i = 0; i != 20; ++i) {
- // sw.start();
- // NodeInfo rootInfo = cache.findNodeInfo(rootUuid);
- // sw.stop();
- // assertThat(rootInfo, is(notNullValue()));
- // }
- // // System.out.println(pad(sourceName) + " ==> " + sw.getSimpleStatistics());
- // }
- //
- // @Test
- // public void shouldRepeatedlyFindRootNodeInfoByUuidFromSourceWithPrimaryTypes() throws Exception {
- // String sourceName = "repositoryForTckTests";
- // Graph store = getGraph(sourceName);
- // SessionCache cache = getCache(sourceName);
- // sw.start();
- // Node root = store.getNodeAt("/");
- // sw.stop();
- // UUID rootUuid = root.getLocation().getUuid();
- // for (int i = 0; i != 20; ++i) {
- // sw.start();
- // NodeInfo rootInfo = cache.findNodeInfo(rootUuid);
- // sw.stop();
- // assertThat(rootInfo, is(notNullValue()));
- // }
- // // System.out.println(pad(sourceName) + " ==> " + sw.getSimpleStatistics());
- // }
- //
- // @Test
- // public void shouldFindChildrenInNodeInfoForRoot() throws Exception {
- // NodeInfo root = cache.findNodeInfoForRoot();
- // Children children = root.getChildren();
- // assertThat(children, is(notNullValue()));
- // assertThat(children.size(), is(1));
- // assertThat(children.getChild(segment("vehix:Vehicles")), is(notNullValue()));
- // }
- //
- // @Test
- // public void shouldFindNodeInfoForNonRootNodeByPath() throws Exception {
- // String sourceName = "vehicles";
- // Graph store = getGraph(sourceName);
- // SessionCache cache = getCache(sourceName);
- // // Get the root ...
- // NodeInfo root = cache.findNodeInfoForRoot();
- //
- // // Now try to load a node that is well-below the root ...
- // Path lr3Path = path("/vehix:Vehicles/vehix:Cars/vehix:Utility/vehix:Land Rover LR3");
- // Node lr3Node = store.getNodeAt(lr3Path);
- // sw.start();
- // NodeInfo lr3 = cache.findNodeInfo(root.getUuid(), lr3Path);
- // sw.stop();
- // assertThat(lr3.getUuid(), is(lr3Node.getLocation().getUuid()));
- // assertSameProperties(lr3, lr3Node);
- // // System.out.println(pad(sourceName) + " ==> " + sw.getSimpleStatistics());
- //
- // // Verify that this loaded all the intermediate nodes, by walking up ...
- // NodeInfo info = lr3;
- // while (true) {
- // UUID parent = info.getParent();
- // if (parent == null) {
- // // then we should be at the root ...
- // assertThat(info.getUuid(), is(root.getUuid()));
- // break;
- // }
- // // Otherwise, we're not at the root, so we should find the parent ...
- // info = cache.findNodeInfoInCache(parent);
- // assertThat(info, is(notNullValue()));
- // }
- // }
- //
- // @Test
- // public void shouldFindInfoForNodeUsingRelativePathFromRoot() throws Exception {
- // String sourceName = "vehicles";
- // Graph store = getGraph(sourceName);
- // SessionCache cache = getCache(sourceName);
- //
- // // Verify that the node does exist in the source ...
- // Path lr3AbsolutePath = path("/vehix:Vehicles/vehix:Cars/vehix:Utility/vehix:Land Rover LR3");
- // Node lr3Node = store.getNodeAt(lr3AbsolutePath);
- //
- // // Get the root ...
- // NodeInfo root = cache.findNodeInfoForRoot();
- //
- // // Now try to load a node that is well-below the root ...
- // Path lr3Path = path("vehix:Vehicles/vehix:Cars/vehix:Utility/vehix:Land Rover LR3");
- // assertThat(lr3Path.isAbsolute(), is(false));
- // NodeInfo lr3 = cache.findNodeInfo(root.getUuid(), lr3Path);
- // assertThat(lr3.getUuid(), is(lr3Node.getLocation().getUuid()));
- // assertSameProperties(lr3, lr3Node);
- //
- // Path recoveredPath = cache.getPathFor(lr3);
- // assertThat(recoveredPath, is(lr3AbsolutePath));
- // }
- //
- // @Test
- // public void shouldFindInfoForNodeUsingRelativePathFromNonRoot() throws Exception {
- // // Verify that the node does exist in the source ...
- // Path carsAbsolutePath = path("/vehix:Vehicles/vehix:Cars");
- // Node carsNode = store.getNodeAt(carsAbsolutePath);
- // Path lr3AbsolutePath = path("/vehix:Vehicles/vehix:Cars/vehix:Utility/vehix:Land Rover LR3");
- // Node lr3Node = store.getNodeAt(lr3AbsolutePath);
- // Path b787AbsolutePath = path("/vehix:Vehicles/vehix:Aircraft/vehix:Commercial/vehix:Boeing 787");
- // Node b787Node = store.getNodeAt(b787AbsolutePath);
- //
- // // Get the root ...
- // NodeInfo root = cache.findNodeInfoForRoot();
- //
- // // Now try to load the cars node ...
- // Path carsPath = path("vehix:Vehicles/vehix:Cars");
- // assertThat(carsPath.isAbsolute(), is(false));
- // NodeInfo cars = cache.findNodeInfo(root.getUuid(), carsPath);
- // assertThat(cars.getUuid(), is(carsNode.getLocation().getUuid()));
- // assertSameProperties(cars, carsNode);
- //
- // // Now try to find the LR3 node relative to the car ...
- // Path lr3Path = path("vehix:Utility/vehix:Land Rover LR3");
- // assertThat(lr3Path.isAbsolute(), is(false));
- // NodeInfo lr3 = cache.findNodeInfo(cars.getUuid(), lr3Path);
- // assertThat(lr3.getUuid(), is(lr3Node.getLocation().getUuid()));
- // assertSameProperties(lr3, lr3Node);
- //
- // // Now try to find the "Boeing 787" node relative to the LR3 node ...
- // Path b787Path = path("../../../vehix:Aircraft/vehix:Commercial/vehix:Boeing 787");
- // assertThat(b787Path.isAbsolute(), is(false));
- // assertThat(b787Path.isNormalized(), is(true));
- // NodeInfo b787 = cache.findNodeInfo(lr3.getUuid(), b787Path);
- // assertThat(b787.getUuid(), is(b787Node.getLocation().getUuid()));
- // assertSameProperties(b787, b787Node);
- //
- // assertThat(cache.getPathFor(cars), is(carsAbsolutePath));
- // assertThat(cache.getPathFor(lr3), is(lr3AbsolutePath));
- // assertThat(cache.getPathFor(b787), is(b787AbsolutePath));
- // }
- //
- // @Test
- // public void shouldFindJcrNodeUsingAbsolutePaths() throws Exception {
- // // Verify that the node does exist in the source ...
- // Path carsAbsolutePath = path("/vehix:Vehicles/vehix:Cars");
- // Node carsNode = store.getNodeAt(carsAbsolutePath);
- // Path lr3AbsolutePath = path("/vehix:Vehicles/vehix:Cars/vehix:Utility/vehix:Land Rover LR3");
- // Node lr3Node = store.getNodeAt(lr3AbsolutePath);
- // Path b787AbsolutePath = path("/vehix:Vehicles/vehix:Aircraft/vehix:Commercial/vehix:Boeing 787");
- // Node b787Node = store.getNodeAt(b787AbsolutePath);
- //
- // // Get the root ...
- // NodeInfo root = cache.findNodeInfoForRoot();
- //
- // // Now try to load the cars node ...
- // Path carsPath = path("vehix:Vehicles/vehix:Cars");
- // assertThat(carsPath.isAbsolute(), is(false));
- // AbstractJcrNode carJcrNode = cache.findJcrNode(root.getUuid(), carsAbsolutePath);
- // assertThat(carJcrNode.internalUuid(), is(carsNode.getLocation().getUuid()));
- // NodeInfo cars = cache.findNodeInfo(root.getUuid(), carsPath);
- // assertThat(cars.getUuid(), is(carsNode.getLocation().getUuid()));
- // assertSameProperties(cars, carsNode);
- //
- // // Now try to find the LR3 node relative to the car ...
- // Path lr3Path = path("vehix:Utility/vehix:Land Rover LR3");
- // assertThat(lr3Path.isAbsolute(), is(false));
- // AbstractJcrNode lr3JcrNode = cache.findJcrNode(root.getUuid(), lr3AbsolutePath);
- // assertThat(lr3JcrNode.internalUuid(), is(lr3Node.getLocation().getUuid()));
- // NodeInfo lr3 = cache.findNodeInfo(cars.getUuid(), lr3Path);
- // assertThat(lr3.getUuid(), is(lr3Node.getLocation().getUuid()));
- // assertSameProperties(lr3, lr3Node);
- //
- // // Now try to find the "Boeing 787" node relative to the LR3 node ...
- // Path b787Path = path("../../../vehix:Aircraft/vehix:Commercial/vehix:Boeing 787");
- // assertThat(b787Path.isAbsolute(), is(false));
- // assertThat(b787Path.isNormalized(), is(true));
- // AbstractJcrNode b787JcrNode = cache.findJcrNode(root.getUuid(), b787AbsolutePath);
- // assertThat(b787JcrNode.internalUuid(), is(b787Node.getLocation().getUuid()));
- // NodeInfo b787 = cache.findNodeInfo(lr3.getUuid(), b787Path);
- // assertThat(b787.getUuid(), is(b787Node.getLocation().getUuid()));
- // assertSameProperties(b787, b787Node);
- //
- // assertThat(cache.getPathFor(cars), is(carsAbsolutePath));
- // assertThat(cache.getPathFor(lr3), is(lr3AbsolutePath));
- // assertThat(cache.getPathFor(b787), is(b787AbsolutePath));
- // }
- //
- // @Test
- // public void shouldDeleteLeafNode() throws Exception {
- // // Find the state of some Graph nodes we'll be using in the test ...
- // Node utility = store.getNodeAt("/vehix:Vehicles/vehix:Cars/vehix:Utility");
- // Node lr2Node = store.getNodeAt("/vehix:Vehicles/vehix:Cars/vehix:Utility/vehix:Land Rover LR2");
- // Node lr3Node = store.getNodeAt("/vehix:Vehicles/vehix:Cars/vehix:Utility/vehix:Land Rover LR3");
- // int numChildrenOfUtility = utility.getChildren().size();
- // assertThat(numChildrenOfUtility, is(4));
- // assertThat(utility.getChildren(), hasChildren(segment("vehix:Land Rover LR2"),
- // segment("vehix:Land Rover LR3"),
- // segment("vehix:Hummer H3"),
- // segment("vehix:Ford F-150")));
- //
- // // Now get the editor for the 'vehix:Utility' node ...
- // NodeEditor editor = cache.getEditorFor(utility.getLocation().getUuid());
- // assertThat(editor, is(notNullValue()));
- //
- // // Destroy the LR3 node, which is a leaf ...
- // editor.destroyChild(lr3Node.getLocation().getUuid());
- //
- // // Verify that the store has not yet been changed ...
- // assertDoesExist(store, lr3Node.getLocation());
- //
- // // Save the session and verify that the node was deleted ...
- // cache.save();
- // Node utilityNode2 = store.getNodeAt(utility.getLocation());
- // assertThat(utilityNode2.getChildren().size(), is(numChildrenOfUtility - 1));
- // assertThat(utilityNode2.getChildren(), hasChildren(segment("vehix:Land Rover LR2"), // no LR3!
- // segment("vehix:Hummer H3"),
- // segment("vehix:Ford F-150")));
- // // Should no longer find the LR3 node in the graph ...
- // assertDoesNotExist(store, lr3Node.getLocation().getUuid());
- // assertDoesExist(store, lr2Node.getLocation());
- // }
- //
- // @Test
- // public void shouldDeleteNonLeafNode() throws Exception {
- // // Find the state of some Graph nodes we'll be using in the test ...
- // Node carsNode = store.getNodeAt("/vehix:Vehicles/vehix:Cars");
- // Node utility = store.getNodeAt("/vehix:Vehicles/vehix:Cars/vehix:Utility");
- // Node hybrid = store.getNodeAt("/vehix:Vehicles/vehix:Cars/vehix:Hybrid");
- // Node luxury = store.getNodeAt("/vehix:Vehicles/vehix:Cars/vehix:Luxury");
- // Node sports = store.getNodeAt("/vehix:Vehicles/vehix:Cars/vehix:Sports");
- // Node lr3 = store.getNodeAt("/vehix:Vehicles/vehix:Cars/vehix:Utility/vehix:Land Rover LR3");
- // Node lr2 = store.getNodeAt("/vehix:Vehicles/vehix:Cars/vehix:Utility/vehix:Land Rover LR2");
- // Node f150 = store.getNodeAt("/vehix:Vehicles/vehix:Cars/vehix:Utility/vehix:Ford F-150");
- // int numChildrenOfCars = carsNode.getChildren().size();
- // assertThat(numChildrenOfCars, is(4));
- // assertThat(carsNode.getChildren(), hasChildren(segment("vehix:Hybrid"),
- // segment("vehix:Sports"),
- // segment("vehix:Luxury"),
- // segment("vehix:Utility")));
- //
- // // Load the LR2 and Hummer nodes ...
- // NodeInfo h3i = cache.findNodeInfo(utility.getLocation().getUuid(), path("vehix:Hummer H3"));
- // NodeInfo lr2i = cache.findNodeInfo(utility.getLocation().getUuid(), path("vehix:Land Rover LR2"));
- // assertThat(h3i, is(notNullValue()));
- // assertThat(lr2i, is(notNullValue()));
- // assertThat(lr2i.getUuid(), is(lr2.getLocation().getUuid()));
- //
- // // Now get the editor for the 'vehix:Cars' node ...
- // NodeEditor editor = cache.getEditorFor(carsNode.getLocation().getUuid());
- // assertThat(editor, is(notNullValue()));
- //
- // // Destroy the Utility node, which is NOT a leaf ...
- // editor.destroyChild(utility.getLocation().getUuid());
- //
- // // Verify that the store has not yet been changed ...
- // assertDoesExist(store, utility.getLocation());
- //
- // // ... but the utility node and its two loaded children have been marked for deletion ...
- // assertIsDeleted(cache, utility.getLocation().getUuid());
- // assertIsDeleted(cache, h3i.getUuid());
- // assertIsDeleted(cache, lr2i.getUuid());
- //
- // // Save the session and verify that the Utility node and its children were deleted ...
- // cache.save();
- // Node carsNode2 = store.getNodeAt(carsNode.getLocation());
- // assertThat(carsNode2.getChildren().size(), is(numChildrenOfCars - 1));
- // assertThat(carsNode2.getChildren(),
- // hasChildren(segment("vehix:Hybrid"), segment("vehix:Sports"), segment("vehix:Luxury")));
- // // Should no longer find the Utility node in the graph ...
- // assertDoesNotExist(store, utility.getLocation());
- // assertDoesNotExist(cache, utility.getLocation().getUuid());
- // assertDoesNotExist(cache, h3i.getUuid());
- // assertDoesNotExist(cache, lr2i.getUuid());
- // assertDoesNotExist(cache, lr3.getLocation().getUuid());
- // assertDoesNotExist(cache, f150.getLocation().getUuid());
- // assertDoNotExist(store, utility.getChildren());
- // assertDoesExist(store, hybrid.getLocation());
- // assertDoesExist(store, luxury.getLocation());
- // assertDoesExist(store, sports.getLocation());
- // }
- //
- // @Test
- // public void shouldGetExistingPropertyOnExistingNode() throws Exception {
- // NodeInfo root = cache.findNodeInfoForRoot();
- // NodeInfo lr3 = cache.findNodeInfo(root.getUuid(), path("/vehix:Vehicles/vehix:Cars/vehix:Utility/vehix:Land Rover LR3"));
- // assertProperty(lr3, Lexicon.MODEL, STRING, Lexicon.CAR, Lexicon.MODEL, STRING, "LR3");
- // assertProperty(lr3, Lexicon.MAKER, STRING, Lexicon.CAR, Lexicon.MAKER, STRING, "Land Rover");
- // assertProperty(lr3, Lexicon.YEAR, LONG, Lexicon.CAR, Lexicon.YEAR, LONG, 2008L);
- // assertProperty(lr3, Lexicon.MSRP, STRING, Lexicon.CAR, Lexicon.MSRP, STRING, "$48,525");
- //
- // NodeInfo db9 = cache.findNodeInfo(root.getUuid(), path("/vehix:Vehicles/vehix:Cars/vehix:Sports/vehix:Aston Martin DB9"));
- // assertProperty(db9, Lexicon.MODEL, STRING, Lexicon.CAR, Lexicon.MODEL, STRING, "DB9");
- // assertProperty(db9, Lexicon.MAKER, STRING, Lexicon.CAR, Lexicon.MAKER, STRING, "Aston Martin");
- // assertProperty(db9, Lexicon.LENGTH_IN_INCHES, DOUBLE, Lexicon.CAR, Lexicon.LENGTH_IN_INCHES, DOUBLE, 185.5D);
- //
- // NodeInfo b878 = cache.findNodeInfo(root.getUuid(),
- // path("/vehix:Vehicles/vehix:Aircraft/vehix:Commercial/vehix:Boeing 787"));
- // assertProperty(b878, Lexicon.MODEL, STRING, Lexicon.AIRCRAFT, Lexicon.MODEL, STRING, "787-3");
- // assertProperty(b878, Lexicon.MAKER, STRING, Lexicon.AIRCRAFT, Lexicon.MAKER, STRING, "Boeing");
- // assertProperty(b878, Lexicon.INTRODUCED, LONG, Lexicon.AIRCRAFT, Lexicon.INTRODUCED, LONG, 2009L);
- // assertProperty(b878, Lexicon.EMPTY_WEIGHT, STRING, JcrNtLexicon.UNSTRUCTURED, name("*"), UNDEFINED, "223000lb");
- //
- // }
- //
- // @Test
- // public void shouldNotFindNonExistantPropertyOnExistingNode() throws Exception {
- // NodeInfo root = cache.findNodeInfoForRoot();
- // NodeInfo lr3 = cache.findNodeInfo(root.getUuid(), path("/vehix:Vehicles/vehix:Cars/vehix:Utility/vehix:Land Rover LR3"));
- // assertProperty(lr3, Lexicon.MODEL, STRING, Lexicon.CAR, Lexicon.MODEL, STRING, "LR3");
- // assertProperty(lr3, Lexicon.MAKER, STRING, Lexicon.CAR, Lexicon.MAKER, STRING, "Land Rover");
- // assertNoProperty(lr3, Lexicon.LENGTH_IN_INCHES);
- // assertNoProperty(lr3, Lexicon.INTRODUCED);
- // }
- //
- // @Test
- // public void shouldSetNewValueOnExistingPropertyOnExistingNode() throws Exception {
- // NodeInfo root = cache.findNodeInfoForRoot();
- // NodeInfo lr3 = cache.findNodeInfo(root.getUuid(), path("/vehix:Vehicles/vehix:Cars/vehix:Utility/vehix:Land Rover LR3"));
- // assertProperty(lr3, Lexicon.MODEL, STRING, Lexicon.CAR, Lexicon.MODEL, STRING, "LR3");
- // assertProperty(lr3, Lexicon.MAKER, STRING, Lexicon.CAR, Lexicon.MAKER, STRING, "Land Rover");
- // assertNoProperty(lr3, Lexicon.LENGTH_IN_INCHES);
- //
- // SessionCache.NodeEditor editor = cache.getEditorFor(lr3.getUuid());
- // editor.setProperty(Lexicon.LENGTH_IN_INCHES, value(DOUBLE, 100.0D));
- // }
- //
- // @Test
- // public void shouldSetNewPropertyOnExistingNode() throws Exception {
- // NodeInfo root = cache.findNodeInfoForRoot();
- // NodeInfo db9 = cache.findNodeInfo(root.getUuid(), path("/vehix:Vehicles/vehix:Cars/vehix:Sports/vehix:Aston Martin DB9"));
- // assertProperty(db9, Lexicon.MODEL, STRING, Lexicon.CAR, Lexicon.MODEL, STRING, "DB9");
- // assertProperty(db9, Lexicon.MAKER, STRING, Lexicon.CAR, Lexicon.MAKER, STRING, "Aston Martin");
- // assertProperty(db9, Lexicon.LENGTH_IN_INCHES, DOUBLE, Lexicon.CAR, Lexicon.LENGTH_IN_INCHES, DOUBLE, 185.5D);
- //
- // SessionCache.NodeEditor editor = cache.getEditorFor(db9.getUuid());
- // editor.setProperty(Lexicon.LENGTH_IN_INCHES, value(DOUBLE, 100.0D));
- // }
- //
- // @Test( expected = ConstraintViolationException.class )
- // public void shouldFailToSetPropertyToInvalidValuesOnExistingNode() throws Exception {
- // NodeInfo root = cache.findNodeInfoForRoot();
- // NodeInfo db9 = cache.findNodeInfo(root.getUuid(), path("/vehix:Vehicles/vehix:Cars/vehix:Sports/vehix:Aston Martin DB9"));
- // assertProperty(db9, Lexicon.MODEL, STRING, Lexicon.CAR, Lexicon.MODEL, STRING, "DB9");
- // assertProperty(db9, Lexicon.MAKER, STRING, Lexicon.CAR, Lexicon.MAKER, STRING, "Aston Martin");
- // assertProperty(db9, Lexicon.LENGTH_IN_INCHES, DOUBLE, Lexicon.CAR, Lexicon.LENGTH_IN_INCHES, DOUBLE, 185.5D);
- //
- // SessionCache.NodeEditor editor = cache.getEditorFor(db9.getUuid());
- // editor.setProperty(Lexicon.LENGTH_IN_INCHES, value(STRING, "This is not a valid double"));
- // }
- //
- // @Test
- // public void shouldRemoveExistingPropertyOnExistingNode() throws Exception {
- // NodeInfo root = cache.findNodeInfoForRoot();
- // NodeInfo db9 = cache.findNodeInfo(root.getUuid(), path("/vehix:Vehicles/vehix:Cars/vehix:Sports/vehix:Aston Martin DB9"));
- // assertProperty(db9, Lexicon.MODEL, STRING, Lexicon.CAR, Lexicon.MODEL, STRING, "DB9");
- // assertProperty(db9, Lexicon.MAKER, STRING, Lexicon.CAR, Lexicon.MAKER, STRING, "Aston Martin");
- // assertProperty(db9, Lexicon.LENGTH_IN_INCHES, DOUBLE, Lexicon.CAR, Lexicon.LENGTH_IN_INCHES, DOUBLE, 185.5D);
- //
- // UUID db9uuid = db9.getUuid();
- // SessionCache.NodeEditor editor = cache.getEditorFor(db9uuid);
- // editor.removeProperty(Lexicon.LENGTH_IN_INCHES);
- //
- // db9 = cache.findNodeInfo(db9uuid);
- // assertNoProperty(db9, Lexicon.LENGTH_IN_INCHES);
- //
- // db9 = cache.findNodeInfo(root.getUuid(), path("/vehix:Vehicles/vehix:Cars/vehix:Sports/vehix:Aston Martin DB9"));
- // assertNoProperty(db9, Lexicon.LENGTH_IN_INCHES);
- // }
- //
- // protected void walkInfosForNodesUnder( NodeInfo parentInfo,
- // Stopwatch sw ) throws Exception {
- // for (ChildNode child : parentInfo.getChildren()) {
- // sw.start();
- // NodeInfo childInfo = cache.findNodeInfo(child.getUuid());
- // cache.getPathFor(childInfo);
- // sw.stop();
- //
- // // Walk the infos for nodes under the child (this is recursive) ...
- // walkInfosForNodesUnder(childInfo, sw);
- // }
- // }
- //
- // @Test
- // public void shouldFindInfoForAllNodesInGraph() throws Exception {
- // for (int i = 0; i != 3; ++i) {
- // Stopwatch sw = new Stopwatch();
- //
- // // Get the root ...
- // sw.start();
- // NodeInfo root = cache.findNodeInfoForRoot();
- // cache.getPathFor(root);
- // sw.stop();
- //
- // // Walk the infos for nodes under the root (this is recursive) ...
- // walkInfosForNodesUnder(root, sw);
- // System.out.println("Statistics for walking nodes using SessionCache: " + sw.getSimpleStatistics());
- // }
- // }
+ @Override
+ @Before
+ public void beforeEach() throws Exception {
+ super.beforeEach();
+ }
+
+ @Test
+ public void shouldRepeatedlyFindRootNode() throws Exception {
+ AbstractJcrNode root = cache.findJcrRootNode();
+ for (int i = 0; i != 10; ++i) {
+ AbstractJcrNode node = cache.findJcrRootNode();
+ assertThat(node, is(sameInstance(root)));
+ // Look up the graph node ...
+ assertMatchesStore(node);
+ }
+ }
+
+ @Test
+ public void shouldRepeatedlyFindRootNodeByPath() throws Exception {
+ AbstractJcrNode root = cache.findJcrNode(null, path("/"));
+ for (int i = 0; i != 10; ++i) {
+ AbstractJcrNode node = cache.findJcrRootNode();
+ assertThat(node, is(sameInstance(root)));
+ // Look up the graph node ...
+ assertMatchesStore(node);
+ }
+ }
+
+ @Test
+ public void shouldRepeatedlyFindRootNodeByLocationWithoutPath() throws Exception {
+ AbstractJcrNode root = cache.findJcrRootNode();
+ AbstractJcrNode root2 = cache.findJcrNode(Location.create(root.location.getIdProperties()));
+ assertThat(root2, is(sameInstance(root)));
+ }
+
+ @Test
+ public void shouldRepeatedlyFindNodeByPath() throws Exception {
+ AbstractJcrNode hybrid = cache.findJcrNode(null, path("/Cars/Hybrid"));
+ for (int i = 0; i != 10; ++i) {
+ AbstractJcrNode hybrid2 = cache.findJcrNode(null, hybrid.path());
+ assertThat(hybrid, is(sameInstance(hybrid2)));
+ // Look up the graph node ...
+ assertMatchesStore(hybrid2);
+ }
+ }
+
+ @Test
+ public void shouldRepeatedlyFindNodeByNodeId() throws Exception {
+ AbstractJcrNode hybrid = cache.findJcrNode(null, path("/Cars/Hybrid"));
+ for (int i = 0; i != 10; ++i) {
+ AbstractJcrNode hybrid2 = cache.findJcrNode(hybrid.nodeId, null);
+ assertThat(hybrid, is(sameInstance(hybrid2)));
+ // Look up the graph node ...
+ assertMatchesStore(hybrid2);
+ }
+ }
+
+ @Test
+ public void shouldRepeatedlyFindNodeByLocationWithoutPath() throws Exception {
+ AbstractJcrNode hybrid = cache.findJcrNode(null, path("/Cars/Hybrid"));
+ AbstractJcrNode hybrid2 = cache.findJcrNode(Location.create(hybrid.location.getIdProperties()));
+ assertThat(hybrid2, is(sameInstance(hybrid)));
+ }
+
+ @Test
+ public void shouldFindNodeUsingStartingNodeAndRelativePath() throws Exception {
+ AbstractJcrNode hybrid = cache.findJcrNode(null, path("/Cars/Hybrid"));
+ AbstractJcrNode highlander = cache.findJcrNode(hybrid.nodeId, hybrid.path(), path("../Hybrid/Toyota Highlander"));
+ // Make sure this is the same as if we find it directly ...
+ AbstractJcrNode highlander2 = cache.findJcrNode(null, path("/Cars/Hybrid/Toyota Highlander"));
+ assertThat(highlander, is(sameInstance(highlander2)));
+ assertMatchesStore(highlander);
+ }
+
+ @Test
+ public void shouldFindNodeItemUsingStartingNodeAndRelativePath() throws Exception {
+ AbstractJcrNode hybrid = cache.findJcrNode(null, path("/Cars/Hybrid"));
+ AbstractJcrItem highlander = cache.findJcrItem(hybrid.nodeId, hybrid.path(), path("../Hybrid/Toyota Highlander"));
+ assertThat(highlander.isNode(), is(true));
+ // Make sure this is the same as if we find it directly ...
+ AbstractJcrNode highlander2 = cache.findJcrNode(null, path("/Cars/Hybrid/Toyota Highlander"));
+ assertThat((AbstractJcrNode)highlander, is(sameInstance(highlander2)));
+ }
+
+ @Test
+ public void shouldFindPropertyItemUsingStartingNodeAndRelativePath() throws Exception {
+ AbstractJcrNode hybrid = cache.findJcrNode(null, path("/Cars/Hybrid"));
+ AbstractJcrItem altimaModel = cache.findJcrItem(hybrid.nodeId, hybrid.path(), path("../Hybrid/Nissan Altima/vehix:model"));
+ assertThat(altimaModel.isNode(), is(false));
+ javax.jcr.Node altimaModelParent = altimaModel.getParent();
+ javax.jcr.Node altima = cache.findJcrNode(null, path("/Cars/Hybrid/Nissan Altima"));
+ assertThat(altima, is(sameInstance(altimaModelParent)));
+ }
+
+ @Test
+ public void shouldFindPropertyForNodeUsingPropertyName() throws Exception {
+ AbstractJcrNode altima = cache.findJcrNode(null, path("/Cars/Hybrid/Nissan Altima"));
+ AbstractJcrItem altimaModel = cache.findJcrProperty(altima.nodeId, altima.path(), name("vehix:model"));
+ assertThat(altimaModel.isNode(), is(false));
+ javax.jcr.Node altimaModelParent = altimaModel.getParent();
+ assertThat(altima, is(sameInstance(altimaModelParent)));
+ }
+
+ @Test
+ public void shouldFindPropertiesForNode() throws Exception {
+ AbstractJcrNode altima = cache.findJcrNode(null, path("/Cars/Hybrid/Nissan Altima"));
+ Collection<AbstractJcrProperty> properties = cache.findJcrPropertiesFor(altima.nodeId, altima.path());
+ assertThat(properties.size(), is(7));
+ List<AbstractJcrProperty> properties2 = new ArrayList<AbstractJcrProperty>(properties);
+ Collections.sort(properties2);
+ Iterator<AbstractJcrProperty> iter = properties2.iterator();
+ assertProperty(iter.next(), altima, "jcr:primaryType", PropertyType.NAME, "vehix:car");
+ assertProperty(iter.next(), altima, "vehix:maker", PropertyType.STRING, "Nissan");
+ assertProperty(iter.next(), altima, "vehix:model", PropertyType.STRING, "Altima");
+ assertProperty(iter.next(), altima, "vehix:mpgCity", PropertyType.LONG, "23");
+ assertProperty(iter.next(), altima, "vehix:mpgHighway", PropertyType.LONG, "32");
+ assertProperty(iter.next(), altima, "vehix:msrp", PropertyType.STRING, "$18,260");
+ assertProperty(iter.next(), altima, "vehix:year", PropertyType.LONG, "2008");
+ }
+
+ @Test
+ public void shouldRefreshWithoutKeepingChanges() throws Exception {
+ AbstractJcrNode altima1 = cache.findJcrNode(null, path("/Cars/Hybrid/Nissan Altima"));
+ assertMatchesStore(altima1);
+ assertThat(altima1.isNew(), is(false));
+
+ // Add the child ...
+ AbstractJcrNode hybrid = cache.findJcrNode(null, path("/Cars/Hybrid"));
+ javax.jcr.Node child = hybrid.addNode("child");
+ assertThat(hybrid.isModified(), is(true));
+ assertThat(child.isNew(), is(true));
+ assertThat(hybrid.hasNode("child"), is(true));
+
+ cache.refresh(false);
+ AbstractJcrNode altima2 = cache.findJcrNode(null, path("/Cars/Hybrid/Nissan Altima"));
+ assertMatchesStore(altima2);
+
+ // The objects should no longer be the same ...
+ assertThat(altima1, is(altima2));
+ assertThat(altima1, is(not(sameInstance(altima2))));
+ assertThat(altima2.isNew(), is(false));
+
+ // The new child should no longer exist ...
+ assertThat(hybrid.hasNode("child"), is(false));
+ }
+
+ @Test
+ public void shouldRefreshAndKeepChanges() throws Exception {
+ AbstractJcrNode altima1 = cache.findJcrNode(null, path("/Cars/Hybrid/Nissan Altima"));
+ assertMatchesStore(altima1);
+ assertThat(altima1.isNew(), is(false));
+
+ // Add the child ...
+ AbstractJcrNode hybrid = cache.findJcrNode(null, path("/Cars/Hybrid"));
+ javax.jcr.Node child = hybrid.addNode("child");
+ assertThat(hybrid.isModified(), is(true));
+ assertThat(child.isNew(), is(true));
+ assertThat(hybrid.hasNode("child"), is(true));
+
+ cache.refresh(true);
+ AbstractJcrNode altima2 = cache.findJcrNode(null, path("/Cars/Hybrid/Nissan Altima"));
+ assertMatchesStore(altima2);
+
+ // The objects should still be the same ...
+ assertThat(altima1, is(altima2));
+ assertThat(altima1, is(sameInstance(altima2)));
+ assertThat(altima2.isNew(), is(false));
+
+ // The new child should still exist ...
+ assertThat(hybrid.hasNode("child"), is(true));
+ }
+
+ @Test
+ public void shouldSaveChanges() throws Exception {
+ AbstractJcrNode altima1 = cache.findJcrNode(null, path("/Cars/Hybrid/Nissan Altima"));
+ assertMatchesStore(altima1);
+ assertThat(altima1.isNew(), is(false));
+
+ // Add the child ...
+ AbstractJcrNode hybrid = cache.findJcrNode(null, path("/Cars/Hybrid"));
+ javax.jcr.Node child = hybrid.addNode("child");
+ assertThat(hybrid.isModified(), is(true));
+ assertThat(child.isNew(), is(true));
+ assertThat(hybrid.hasNode("child"), is(true));
+
+ cache.save();
+ AbstractJcrNode altima2 = cache.findJcrNode(null, path("/Cars/Hybrid/Nissan Altima"));
+ assertMatchesStore(altima2);
+
+ // The objects should no longer be the same ...
+ assertThat(altima1, is(altima2));
+ assertThat(altima1, is(not(sameInstance(altima2))));
+ assertThat(altima2.isNew(), is(false));
+
+ // The new child should still exist ...
+ assertThat(hybrid.hasNode("child"), is(true));
+ }
+
+ protected void assertProperty( AbstractJcrProperty property,
+ javax.jcr.Node node,
+ String name,
+ int propertyType,
+ Object... values ) throws Exception {
+ assertThat(property.getName(), is(name));
+ assertThat(property.getType(), is(propertyType));
+ assertThat(property.getParent(), is(node));
+ if (values.length > 1) {
+ int i = 0;
+ for (Value actual : property.getValues()) {
+ String actualString = actual.getString();
+ String expectedString = context.getValueFactories().getStringFactory().create(values[i]);
+ assertThat(actualString, is(expectedString));
+ assertCanObtainValue(actual, propertyType);
+ ++i;
+ }
+ // Getting the single value should result in an error ...
+ try {
+ property.getValue();
+ fail("Should not be able to call Property.getValue() on multi-valued properties");
+ } catch (ValueFormatException e) {
+ // expected ...
+ }
+ } else {
+ String actualString = property.getValue().getString();
+ String expectedString = context.getValueFactories().getStringFactory().create(values[0]);
+ assertThat(actualString, is(expectedString));
+ assertThat(actualString, is(property.getString()));
+ assertCanObtainValue(property.getValue(), propertyType);
+ // Getting the multiple values should result in an error ...
+ try {
+ property.getValues();
+ fail("Should not be able to call Property.getValues() on single-valued properties");
+ } catch (ValueFormatException e) {
+ // expected ...
+ }
+ // Check resolving the reference ...
+ if (propertyType == PropertyType.REFERENCE) {
+ javax.jcr.Node referenced = property.getNode();
+ assertThat(referenced, is(notNullValue()));
+ }
+ }
+ }
+
+ protected void assertCanObtainValue( Value value,
+ int expectedType ) throws Exception {
+ switch (expectedType) {
+ case PropertyType.BINARY:
+ InputStream stream = value.getStream();
+ assertThat(stream, is(notNullValue()));
+ try {
+ stream.read();
+ } finally {
+ stream.close();
+ }
+ break;
+ case PropertyType.BOOLEAN:
+ assertThat(value.getBoolean() || !value.getBoolean(), is(true));
+ break;
+ case PropertyType.DATE:
+ Calendar cal = value.getDate();
+ assertThat(cal, is(notNullValue()));
+ break;
+ case PropertyType.DOUBLE:
+ double doubleValue = value.getDouble();
+ assertThat(doubleValue < 0.0d || doubleValue >= -1.0d, is(true));
+ break;
+ case PropertyType.LONG:
+ long longValue = value.getLong();
+ assertThat(longValue < 0L || longValue >= 0L, is(true));
+ break;
+ case PropertyType.NAME:
+ context.getValueFactories().getNameFactory().create(value.getString());
+ break;
+ case PropertyType.PATH:
+ context.getValueFactories().getPathFactory().create(value.getString());
+ break;
+ case PropertyType.REFERENCE:
+ UUID uuid = context.getValueFactories().getUuidFactory().create(value.getString());
+ assertThat(uuid, is(notNullValue()));
+ break;
+ case PropertyType.STRING:
+ value.getString();
+ break;
+ }
+ }
+
+ protected void assertMatchesStore( AbstractJcrNode jcrNode ) throws RepositoryException {
+ // Find the corresponding session node ...
+ Node<JcrNodePayload, JcrPropertyPayload> nodeInfo = cache.findNode(jcrNode.nodeId, jcrNode.path());
+ // And the graph node ...
+ org.jboss.dna.graph.Node dnaNode = store.getNodeAt(jcrNode.location);
+
+ assertThat(nodeInfo.getLocation(), is(dnaNode.getLocation()));
+ Set<Name> propertyNames = nodeInfo.getPropertyNames();
+ for (Name propertyName : propertyNames) {
+ PropertyInfo<JcrPropertyPayload> info = nodeInfo.getProperty(propertyName);
+ assertThat(info.getName(), is(propertyName));
+ assertThat(info.getProperty().getName(), is(propertyName));
+ Property actual = dnaNode.getProperty(propertyName);
+ if (actual != null) {
+ assertThat(info.getProperty().size(), is(actual.size()));
+ assertThat(info.getProperty().getValuesAsArray(), is(actual.getValuesAsArray()));
+ } else {
+ if (propertyName.equals(JcrLexicon.UUID)) {
+ // check for a DNA UUID property ...
+ actual = dnaNode.getProperty(DnaLexicon.UUID);
+ if (actual != null) {
+ assertThat(info.getProperty().size(), is(actual.size()));
+ assertThat(info.getProperty().getValuesAsArray(), is(actual.getValuesAsArray()));
+ } else {
+ fail("missing property \"" + propertyName + "\" on " + dnaNode);
+ }
+ } else if (propertyName.equals(JcrLexicon.PRIMARY_TYPE)) {
+ // This is okay
+ } else if (propertyName.equals(DnaIntLexicon.MULTI_VALUED_PROPERTIES)) {
+ // This is okay
+ } else {
+ fail("missing property \"" + propertyName + "\" on " + dnaNode);
+ }
+ }
+ }
+ }
}
Modified: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/SessionCacheTest2.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/SessionCacheTest2.java 2009-07-09 16:26:04 UTC (rev 1082)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/SessionCacheTest2.java 2009-07-09 16:27:15 UTC (rev 1083)
@@ -23,30 +23,8 @@
*/
package org.jboss.dna.jcr;
-import static org.hamcrest.core.Is.is;
-import static org.hamcrest.core.IsNot.not;
-import static org.hamcrest.core.IsNull.notNullValue;
-import static org.hamcrest.core.IsSame.sameInstance;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.fail;
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.Calendar;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Set;
-import java.util.UUID;
-import javax.jcr.PropertyType;
-import javax.jcr.RepositoryException;
-import javax.jcr.Value;
-import javax.jcr.ValueFormatException;
-import org.jboss.dna.graph.Location;
-import org.jboss.dna.graph.property.Name;
-import org.jboss.dna.graph.property.Property;
+import org.jboss.dna.common.statistic.Stopwatch;
import org.jboss.dna.graph.session.GraphSession.Node;
-import org.jboss.dna.graph.session.GraphSession.PropertyInfo;
import org.jboss.dna.jcr.SessionCache.JcrNodePayload;
import org.jboss.dna.jcr.SessionCache.JcrPropertyPayload;
import org.junit.Before;
@@ -63,320 +41,87 @@
super.beforeEach();
}
- @Test
- public void shouldRepeatedlyFindRootNode() throws Exception {
- AbstractJcrNode root = cache.findJcrRootNode();
- for (int i = 0; i != 10; ++i) {
- AbstractJcrNode node = cache.findJcrRootNode();
- assertThat(node, is(sameInstance(root)));
- // Look up the graph node ...
- assertMatchesStore(node);
- }
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.jcr.AbstractJcrTest#getResourceNameOfXmlFileToImport()
+ */
+ @Override
+ protected String getResourceNameOfXmlFileToImport() {
+ return "vehicles.xml";
}
- @Test
- public void shouldRepeatedlyFindRootNodeByPath() throws Exception {
- AbstractJcrNode root = cache.findJcrNode(null, path("/"));
- for (int i = 0; i != 10; ++i) {
- AbstractJcrNode node = cache.findJcrRootNode();
- assertThat(node, is(sameInstance(root)));
- // Look up the graph node ...
- assertMatchesStore(node);
+ protected void walkInfosForNodesUnder( Node<JcrNodePayload, JcrPropertyPayload> node,
+ Stopwatch sw ) throws Exception {
+ for (Node<JcrNodePayload, JcrPropertyPayload> child : node.getChildren()) {
+ sw.start();
+ child.getPath();
+ sw.stop();
+
+ // Walk the infos for nodes under the child (this is recursive) ...
+ walkInfosForNodesUnder(child, sw);
}
}
@Test
- public void shouldRepeatedlyFindRootNodeByLocationWithoutPath() throws Exception {
- AbstractJcrNode root = cache.findJcrRootNode();
- AbstractJcrNode root2 = cache.findJcrNode(Location.create(root.location.getIdProperties()));
- assertThat(root2, is(sameInstance(root)));
- }
+ public void shouldFindInfoForAllNodesInGraph() throws Exception {
+ for (int i = 0; i != 3; ++i) {
+ super.numberOfConnections = 0;
+ Stopwatch sw = new Stopwatch();
- @Test
- public void shouldRepeatedlyFindNodeByPath() throws Exception {
- AbstractJcrNode hybrid = cache.findJcrNode(null, path("/Cars/Hybrid"));
- for (int i = 0; i != 10; ++i) {
- AbstractJcrNode hybrid2 = cache.findJcrNode(null, hybrid.path());
- assertThat(hybrid, is(sameInstance(hybrid2)));
- // Look up the graph node ...
- assertMatchesStore(hybrid2);
- }
- }
+ // Get the root ...
+ sw.start();
+ Node<JcrNodePayload, JcrPropertyPayload> root = cache.findNode(null, path("/"));
+ root.getPath();
+ root.getPayload(); // forces a load
+ sw.stop();
- @Test
- public void shouldRepeatedlyFindNodeByNodeId() throws Exception {
- AbstractJcrNode hybrid = cache.findJcrNode(null, path("/Cars/Hybrid"));
- for (int i = 0; i != 10; ++i) {
- AbstractJcrNode hybrid2 = cache.findJcrNode(hybrid.nodeId, null);
- assertThat(hybrid, is(sameInstance(hybrid2)));
- // Look up the graph node ...
- assertMatchesStore(hybrid2);
+ // Walk the infos for nodes under the root (this is recursive) ...
+ walkInfosForNodesUnder(root, sw);
+ System.out.println("Statistics for walking nodes using SessionCache: " + sw.getSimpleStatistics() + " -> "
+ + super.numberOfConnections);
}
}
@Test
- public void shouldRepeatedlyFindNodeByLocationWithoutPath() throws Exception {
- AbstractJcrNode hybrid = cache.findJcrNode(null, path("/Cars/Hybrid"));
- AbstractJcrNode hybrid2 = cache.findJcrNode(Location.create(hybrid.location.getIdProperties()));
- assertThat(hybrid2, is(sameInstance(hybrid)));
- }
+ public void shouldFindInfoForAllNodesInGraphWithLoadingDepthOf2() throws Exception {
+ cache.graphSession().setDepthForLoadingNodes(2);
+ for (int i = 0; i != 3; ++i) {
+ super.numberOfConnections = 0;
+ Stopwatch sw = new Stopwatch();
- @Test
- public void shouldFindNodeUsingStartingNodeAndRelativePath() throws Exception {
- AbstractJcrNode hybrid = cache.findJcrNode(null, path("/Cars/Hybrid"));
- AbstractJcrNode highlander = cache.findJcrNode(hybrid.nodeId, hybrid.path(), path("../Hybrid/Toyota Highlander"));
- // Make sure this is the same as if we find it directly ...
- AbstractJcrNode highlander2 = cache.findJcrNode(null, path("/Cars/Hybrid/Toyota Highlander"));
- assertThat(highlander, is(sameInstance(highlander2)));
- assertMatchesStore(highlander);
- }
+ // Get the root ...
+ sw.start();
+ Node<JcrNodePayload, JcrPropertyPayload> root = cache.findNode(null, path("/"));
+ root.getPath();
+ root.getPayload(); // forces a load
+ sw.stop();
- @Test
- public void shouldFindNodeItemUsingStartingNodeAndRelativePath() throws Exception {
- AbstractJcrNode hybrid = cache.findJcrNode(null, path("/Cars/Hybrid"));
- AbstractJcrItem highlander = cache.findJcrItem(hybrid.nodeId, hybrid.path(), path("../Hybrid/Toyota Highlander"));
- assertThat(highlander.isNode(), is(true));
- // Make sure this is the same as if we find it directly ...
- AbstractJcrNode highlander2 = cache.findJcrNode(null, path("/Cars/Hybrid/Toyota Highlander"));
- assertThat((AbstractJcrNode)highlander, is(sameInstance(highlander2)));
+ // Walk the infos for nodes under the root (this is recursive) ...
+ walkInfosForNodesUnder(root, sw);
+ System.out.println("Statistics for walking nodes using SessionCache: " + sw.getSimpleStatistics() + " -> "
+ + super.numberOfConnections);
+ }
}
@Test
- public void shouldFindPropertyItemUsingStartingNodeAndRelativePath() throws Exception {
- AbstractJcrNode hybrid = cache.findJcrNode(null, path("/Cars/Hybrid"));
- AbstractJcrItem altimaModel = cache.findJcrItem(hybrid.nodeId, hybrid.path(), path("../Hybrid/Nissan Altima/vehix:model"));
- assertThat(altimaModel.isNode(), is(false));
- javax.jcr.Node altimaModelParent = altimaModel.getParent();
- javax.jcr.Node altima = cache.findJcrNode(null, path("/Cars/Hybrid/Nissan Altima"));
- assertThat(altima, is(sameInstance(altimaModelParent)));
- }
+ public void shouldFindInfoForAllNodesInGraphWithLoadingDepthOf4() throws Exception {
+ cache.graphSession().setDepthForLoadingNodes(6);
+ for (int i = 0; i != 3; ++i) {
+ Stopwatch sw = new Stopwatch();
+ super.numberOfConnections = 0;
- @Test
- public void shouldFindPropertyForNodeUsingPropertyName() throws Exception {
- AbstractJcrNode altima = cache.findJcrNode(null, path("/Cars/Hybrid/Nissan Altima"));
- AbstractJcrItem altimaModel = cache.findJcrProperty(altima.nodeId, altima.path(), name("vehix:model"));
- assertThat(altimaModel.isNode(), is(false));
- javax.jcr.Node altimaModelParent = altimaModel.getParent();
- assertThat(altima, is(sameInstance(altimaModelParent)));
- }
+ // Get the root ...
+ sw.start();
+ Node<JcrNodePayload, JcrPropertyPayload> root = cache.findNode(null, path("/"));
+ root.getPath();
+ root.getPayload(); // forces a load
+ sw.stop();
- @Test
- public void shouldFindPropertiesForNode() throws Exception {
- AbstractJcrNode altima = cache.findJcrNode(null, path("/Cars/Hybrid/Nissan Altima"));
- Collection<AbstractJcrProperty> properties = cache.findJcrPropertiesFor(altima.nodeId, altima.path());
- assertThat(properties.size(), is(7));
- List<AbstractJcrProperty> properties2 = new ArrayList<AbstractJcrProperty>(properties);
- Collections.sort(properties2);
- Iterator<AbstractJcrProperty> iter = properties2.iterator();
- assertProperty(iter.next(), altima, "jcr:primaryType", PropertyType.NAME, "vehix:car");
- assertProperty(iter.next(), altima, "vehix:maker", PropertyType.STRING, "Nissan");
- assertProperty(iter.next(), altima, "vehix:model", PropertyType.STRING, "Altima");
- assertProperty(iter.next(), altima, "vehix:mpgCity", PropertyType.LONG, "23");
- assertProperty(iter.next(), altima, "vehix:mpgHighway", PropertyType.LONG, "32");
- assertProperty(iter.next(), altima, "vehix:msrp", PropertyType.STRING, "$18,260");
- assertProperty(iter.next(), altima, "vehix:year", PropertyType.LONG, "2008");
- }
-
- @Test
- public void shouldRefreshWithoutKeepingChanges() throws Exception {
- AbstractJcrNode altima1 = cache.findJcrNode(null, path("/Cars/Hybrid/Nissan Altima"));
- assertMatchesStore(altima1);
- assertThat(altima1.isNew(), is(false));
-
- // Add the child ...
- AbstractJcrNode hybrid = cache.findJcrNode(null, path("/Cars/Hybrid"));
- javax.jcr.Node child = hybrid.addNode("child");
- assertThat(hybrid.isModified(), is(true));
- assertThat(child.isNew(), is(true));
- assertThat(hybrid.hasNode("child"), is(true));
-
- cache.refresh(false);
- AbstractJcrNode altima2 = cache.findJcrNode(null, path("/Cars/Hybrid/Nissan Altima"));
- assertMatchesStore(altima2);
-
- // The objects should no longer be the same ...
- assertThat(altima1, is(altima2));
- assertThat(altima1, is(not(sameInstance(altima2))));
- assertThat(altima2.isNew(), is(false));
-
- // The new child should no longer exist ...
- assertThat(hybrid.hasNode("child"), is(false));
- }
-
- @Test
- public void shouldRefreshAndKeepChanges() throws Exception {
- AbstractJcrNode altima1 = cache.findJcrNode(null, path("/Cars/Hybrid/Nissan Altima"));
- assertMatchesStore(altima1);
- assertThat(altima1.isNew(), is(false));
-
- // Add the child ...
- AbstractJcrNode hybrid = cache.findJcrNode(null, path("/Cars/Hybrid"));
- javax.jcr.Node child = hybrid.addNode("child");
- assertThat(hybrid.isModified(), is(true));
- assertThat(child.isNew(), is(true));
- assertThat(hybrid.hasNode("child"), is(true));
-
- cache.refresh(true);
- AbstractJcrNode altima2 = cache.findJcrNode(null, path("/Cars/Hybrid/Nissan Altima"));
- assertMatchesStore(altima2);
-
- // The objects should still be the same ...
- assertThat(altima1, is(altima2));
- assertThat(altima1, is(sameInstance(altima2)));
- assertThat(altima2.isNew(), is(false));
-
- // The new child should still exist ...
- assertThat(hybrid.hasNode("child"), is(true));
- }
-
- @Test
- public void shouldSaveChanges() throws Exception {
- AbstractJcrNode altima1 = cache.findJcrNode(null, path("/Cars/Hybrid/Nissan Altima"));
- assertMatchesStore(altima1);
- assertThat(altima1.isNew(), is(false));
-
- // Add the child ...
- AbstractJcrNode hybrid = cache.findJcrNode(null, path("/Cars/Hybrid"));
- javax.jcr.Node child = hybrid.addNode("child");
- assertThat(hybrid.isModified(), is(true));
- assertThat(child.isNew(), is(true));
- assertThat(hybrid.hasNode("child"), is(true));
-
- cache.save();
- AbstractJcrNode altima2 = cache.findJcrNode(null, path("/Cars/Hybrid/Nissan Altima"));
- assertMatchesStore(altima2);
-
- // The objects should no longer be the same ...
- assertThat(altima1, is(altima2));
- assertThat(altima1, is(not(sameInstance(altima2))));
- assertThat(altima2.isNew(), is(false));
-
- // The new child should still exist ...
- assertThat(hybrid.hasNode("child"), is(true));
- }
-
- protected void assertProperty( AbstractJcrProperty property,
- javax.jcr.Node node,
- String name,
- int propertyType,
- Object... values ) throws Exception {
- assertThat(property.getName(), is(name));
- assertThat(property.getType(), is(propertyType));
- assertThat(property.getParent(), is(node));
- if (values.length > 1) {
- int i = 0;
- for (Value actual : property.getValues()) {
- String actualString = actual.getString();
- String expectedString = context.getValueFactories().getStringFactory().create(values[i]);
- assertThat(actualString, is(expectedString));
- assertCanObtainValue(actual, propertyType);
- ++i;
- }
- // Getting the single value should result in an error ...
- try {
- property.getValue();
- fail("Should not be able to call Property.getValue() on multi-valued properties");
- } catch (ValueFormatException e) {
- // expected ...
- }
- } else {
- String actualString = property.getValue().getString();
- String expectedString = context.getValueFactories().getStringFactory().create(values[0]);
- assertThat(actualString, is(expectedString));
- assertThat(actualString, is(property.getString()));
- assertCanObtainValue(property.getValue(), propertyType);
- // Getting the multiple values should result in an error ...
- try {
- property.getValues();
- fail("Should not be able to call Property.getValues() on single-valued properties");
- } catch (ValueFormatException e) {
- // expected ...
- }
- // Check resolving the reference ...
- if (propertyType == PropertyType.REFERENCE) {
- javax.jcr.Node referenced = property.getNode();
- assertThat(referenced, is(notNullValue()));
- }
+ // Walk the infos for nodes under the root (this is recursive) ...
+ walkInfosForNodesUnder(root, sw);
+ System.out.println("Statistics for walking nodes using SessionCache: " + sw.getSimpleStatistics() + " -> "
+ + super.numberOfConnections);
}
}
-
- protected void assertCanObtainValue( Value value,
- int expectedType ) throws Exception {
- switch (expectedType) {
- case PropertyType.BINARY:
- InputStream stream = value.getStream();
- assertThat(stream, is(notNullValue()));
- try {
- stream.read();
- } finally {
- stream.close();
- }
- break;
- case PropertyType.BOOLEAN:
- assertThat(value.getBoolean() || !value.getBoolean(), is(true));
- break;
- case PropertyType.DATE:
- Calendar cal = value.getDate();
- assertThat(cal, is(notNullValue()));
- break;
- case PropertyType.DOUBLE:
- double doubleValue = value.getDouble();
- assertThat(doubleValue < 0.0d || doubleValue >= -1.0d, is(true));
- break;
- case PropertyType.LONG:
- long longValue = value.getLong();
- assertThat(longValue < 0L || longValue >= 0L, is(true));
- break;
- case PropertyType.NAME:
- context.getValueFactories().getNameFactory().create(value.getString());
- break;
- case PropertyType.PATH:
- context.getValueFactories().getPathFactory().create(value.getString());
- break;
- case PropertyType.REFERENCE:
- UUID uuid = context.getValueFactories().getUuidFactory().create(value.getString());
- assertThat(uuid, is(notNullValue()));
- break;
- case PropertyType.STRING:
- value.getString();
- break;
- }
- }
-
- protected void assertMatchesStore( AbstractJcrNode jcrNode ) throws RepositoryException {
- // Find the corresponding session node ...
- Node<JcrNodePayload, JcrPropertyPayload> nodeInfo = cache.findNode(jcrNode.nodeId, jcrNode.path());
- // And the graph node ...
- org.jboss.dna.graph.Node dnaNode = store.getNodeAt(jcrNode.location);
-
- assertThat(nodeInfo.getLocation(), is(dnaNode.getLocation()));
- Set<Name> propertyNames = nodeInfo.getPropertyNames();
- for (Name propertyName : propertyNames) {
- PropertyInfo<JcrPropertyPayload> info = nodeInfo.getProperty(propertyName);
- assertThat(info.getName(), is(propertyName));
- assertThat(info.getProperty().getName(), is(propertyName));
- Property actual = dnaNode.getProperty(propertyName);
- if (actual != null) {
- assertThat(info.getProperty().size(), is(actual.size()));
- assertThat(info.getProperty().getValuesAsArray(), is(actual.getValuesAsArray()));
- } else {
- if (propertyName.equals(JcrLexicon.UUID)) {
- // check for a DNA UUID property ...
- actual = dnaNode.getProperty(DnaLexicon.UUID);
- if (actual != null) {
- assertThat(info.getProperty().size(), is(actual.size()));
- assertThat(info.getProperty().getValuesAsArray(), is(actual.getValuesAsArray()));
- } else {
- fail("missing property \"" + propertyName + "\" on " + dnaNode);
- }
- } else if (propertyName.equals(JcrLexicon.PRIMARY_TYPE)) {
- // This is okay
- } else if (propertyName.equals(DnaIntLexicon.MULTI_VALUED_PROPERTIES)) {
- // This is okay
- } else {
- fail("missing property \"" + propertyName + "\" on " + dnaNode);
- }
- }
- }
- }
}
16 years, 6 months
DNA SVN: r1082 - in trunk: dna-graph/src/main/java/org/jboss/dna/graph/property and 10 other directories.
by dna-commits@lists.jboss.org
Author: rhauch
Date: 2009-07-09 12:26:04 -0400 (Thu, 09 Jul 2009)
New Revision: 1082
Added:
trunk/dna-graph/src/test/java/org/jboss/dna/graph/session/GraphSessionTest.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/CorrespondenceId.java
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/SessionCacheTest2.java
Removed:
trunk/dna-graph/src/test/java/org/jboss/dna/graph/session/GraphCacheTest.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/PropertyId.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/ChangedChildren.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/ChangedNodeInfo.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/ChildNode.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/Children.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/EmptyChildren.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/ImmutableChildren.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/ImmutableNodeInfo.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/InternalChildren.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/NewNodeInfo.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/NodeInfo.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/PropertyInfo.java
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/cache/AbstractChildrenTest.java
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/cache/ChangedChildrenTest.java
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/cache/ChangedNodeInfoTest.java
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/cache/ImmutableChildrenTest.java
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/cache/IsNodeInfoWithChildrenHavingNames.java
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/cache/IsNodeInfoWithChildrenHavingUuids.java
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/cache/NewNodeInfoTest.java
Modified:
trunk/dna-graph/src/main/java/org/jboss/dna/graph/Graph.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/GraphI18n.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/Location.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/Results.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/property/Path.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/property/basic/AbstractPath.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/property/basic/RootPath.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/session/GraphSession.java
trunk/dna-graph/src/main/resources/org/jboss/dna/graph/GraphI18n.properties
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/AbstractJcrNode.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/AbstractJcrProperty.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrChildNodeIterator.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrContentHandler.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrI18n.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrMultiValueProperty.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNode.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNodeType.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrPropertyDefinition.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrRootNode.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrSession.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrSingleValueProperty.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrWorkspace.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/SessionCache.java
trunk/dna-jcr/src/main/resources/org/jboss/dna/jcr/JcrI18n.properties
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/AbstractJcrNodeTest.java
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/AbstractJcrPropertyTest.java
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/AbstractJcrTest.java
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrChildNodeIteratorTest.java
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrMultiValuePropertyTest.java
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrNodeTest.java
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrRootNodeTest.java
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrSessionTest.java
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrSingleValuePropertyTest.java
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/SessionCacheTest.java
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/Vehicles.java
trunk/dna-jcr/src/test/resources/cars.xml
Log:
DNA-466 Completed major rewrite of how the JCR implementation manages session state. The previous implementation did everything by UUIDs, but this was a major problem when the JCR implementation used connectors that don't support UUIDs. There are a few outstanding unit tests that still don't complete successfully, but most of those are related to the XML import (which has not yet been fixed to use the new approach). However, most of the JCR unit tests (including most of the JCR API/TCK unit tests) do pass.
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/Graph.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/Graph.java 2009-07-09 16:23:09 UTC (rev 1081)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/Graph.java 2009-07-09 16:26:04 UTC (rev 1082)
@@ -2611,9 +2611,11 @@
Locations from,
Location into,
Name copyName ) {
- String workspaceName = fromWorkspaceName != null ? fromWorkspaceName : getCurrentWorkspaceName();
+
+ String intoWorkspaceName = getCurrentWorkspaceName();
+ if ( fromWorkspaceName == null ) fromWorkspaceName = intoWorkspaceName;
do {
- requestQueue.copyBranch(from.getLocation(), workspaceName, into, workspaceName, copyName, null);
+ requestQueue.copyBranch(from.getLocation(), fromWorkspaceName, into, intoWorkspaceName, copyName, null);
} while ((from = from.next()) != null);
return and();
}
@@ -5440,8 +5442,11 @@
@Immutable
class BatchResults implements Results {
private final Map<Path, BatchResultsNode> nodes = new HashMap<Path, BatchResultsNode>();
+ private final List<Request> requests;
/*package*/BatchResults( List<Request> requests ) {
+ this.requests = Collections.unmodifiableList(requests);
+ // Now create the results ...
for (Request request : requests) {
if (request instanceof ReadAllPropertiesRequest) {
ReadAllPropertiesRequest read = (ReadAllPropertiesRequest)request;
@@ -5479,6 +5484,8 @@
}
/*package*/BatchResults( Request request ) {
+ this.requests = Collections.singletonList(request);
+ // Now create the results ...
if (request instanceof ReadAllPropertiesRequest) {
ReadAllPropertiesRequest read = (ReadAllPropertiesRequest)request;
DateTime expires = computeExpirationTime(read);
@@ -5513,9 +5520,19 @@
}
}
- /*package*/BatchResults() {
+ BatchResults() {
+ this.requests = Collections.emptyList();
}
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.graph.Results#getRequests()
+ */
+ public List<Request> getRequests() {
+ return requests;
+ }
+
private BatchResultsNode getOrCreateNode( Location location,
DateTime expirationTime ) {
BatchResultsNode node = nodes.get(location);
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-07-09 16:23:09 UTC (rev 1081)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/GraphI18n.java 2009-07-09 16:26:04 UTC (rev 1082)
@@ -124,7 +124,10 @@
/* Session */
public static I18n unableToRefreshBranchBecauseChangesDependOnChangesToNodesOutsideOfBranch;
public static I18n unableToSaveBranchBecauseChangesDependOnChangesToNodesOutsideOfBranch;
+ public static I18n unableToSaveNodeThatWasCreatedSincePreviousSave;
public static I18n nodeHasAlreadyBeenRemovedFromThisSession;
+ public static I18n unableToMoveNodeToBeChildOfDecendent;
+ public static I18n childNotFound;
static {
try {
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/Location.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/Location.java 2009-07-09 16:23:09 UTC (rev 1081)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/Location.java 2009-07-09 16:26:04 UTC (rev 1082)
@@ -247,7 +247,7 @@
*/
public static Location create( List<Property> idProperties ) {
CheckArg.isNotEmpty(idProperties, "idProperties");
- return new LocationWithPathAndProperties(null, idProperties);
+ return new LocationWithProperties(idProperties);
}
/**
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/Results.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/Results.java 2009-07-09 16:23:09 UTC (rev 1081)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/Results.java 2009-07-09 16:26:04 UTC (rev 1082)
@@ -23,8 +23,10 @@
*/
package org.jboss.dna.graph;
+import java.util.List;
import net.jcip.annotations.Immutable;
import org.jboss.dna.graph.property.Path;
+import org.jboss.dna.graph.request.Request;
/**
* A set of nodes returned from a {@link Graph graph}, with methods to access the properties and children of the nodes in the
@@ -90,4 +92,11 @@
*/
boolean includes( Location location );
+ /**
+ * Get the requests that were executed as part of these results.
+ *
+ * @return the requests; never null, but possibly empty if there were no results when execute was called
+ */
+ List<Request> getRequests();
+
}
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/property/Path.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/property/Path.java 2009-07-09 16:23:09 UTC (rev 1081)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/property/Path.java 2009-07-09 16:26:04 UTC (rev 1082)
@@ -287,8 +287,8 @@
public boolean isAbsolute();
/**
- * Return whether this path is normalized and contains no "." segments and as few ".." segments as possible. For example, the
- * path "../a" is normalized, while "/a/b/c/../d" is not normalized.
+ * Return whether this path is normalized and contains no unnecessary "." segments and as few ".." segments as possible. For
+ * example, the path "../a" is normalized, while "/a/b/c/../d" is not normalized.
*
* @return true if this path is normalized, or false otherwise
*/
@@ -312,6 +312,14 @@
public Path getCanonicalPath();
/**
+ * Obtain a path that is relative to the root node. This is equivalent to calling {@link #relativeTo(Path)} with the root
+ * path.
+ *
+ * @return the relative path from the root node; never null
+ */
+ public Path relativeToRoot();
+
+ /**
* Get a relative path from the supplied path to this path.
*
* @param startingPath the path specifying the starting point for the new relative path; may not be null
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/property/basic/AbstractPath.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/property/basic/AbstractPath.java 2009-07-09 16:23:09 UTC (rev 1081)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/property/basic/AbstractPath.java 2009-07-09 16:26:04 UTC (rev 1082)
@@ -432,13 +432,26 @@
/**
* {@inheritDoc}
+ *
+ * @see org.jboss.dna.graph.property.Path#relativeToRoot()
*/
+ public Path relativeToRoot() {
+ return new BasicPath(getSegmentsList(), false);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
public Path relativeTo( Path startingPath ) {
CheckArg.isNotNull(startingPath, "to");
if (!this.isAbsolute()) {
String msg = GraphI18n.pathIsNotAbsolute.text(this);
throw new InvalidPathException(msg);
}
+ if (startingPath.isRoot()) {
+ // We just want a relative path containing the same segments ...
+ return relativeToRoot();
+ }
if (!startingPath.isAbsolute()) {
String msg = GraphI18n.pathIsNotAbsolute.text(startingPath);
throw new InvalidPathException(msg);
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/property/basic/RootPath.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/property/basic/RootPath.java 2009-07-09 16:23:09 UTC (rev 1081)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/property/basic/RootPath.java 2009-07-09 16:26:04 UTC (rev 1082)
@@ -124,6 +124,16 @@
/**
* {@inheritDoc}
*
+ * @see org.jboss.dna.graph.property.basic.AbstractPath#relativeToRoot()
+ */
+ @Override
+ public Path relativeToRoot() {
+ return BasicPath.SELF_PATH;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
* @see org.jboss.dna.graph.property.basic.AbstractPath#resolve(org.jboss.dna.graph.property.Path)
*/
@Override
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/session/GraphSession.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/session/GraphSession.java 2009-07-09 16:23:09 UTC (rev 1081)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/session/GraphSession.java 2009-07-09 16:26:04 UTC (rev 1082)
@@ -34,14 +34,12 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
-import java.util.UUID;
import net.jcip.annotations.Immutable;
import net.jcip.annotations.NotThreadSafe;
import net.jcip.annotations.ThreadSafe;
import org.jboss.dna.common.collection.ReadOnlyIterator;
import org.jboss.dna.common.i18n.I18n;
import org.jboss.dna.common.util.CheckArg;
-import org.jboss.dna.common.util.HashCode;
import org.jboss.dna.common.util.StringUtil;
import org.jboss.dna.graph.ExecutionContext;
import org.jboss.dna.graph.Graph;
@@ -58,9 +56,10 @@
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.request.BatchRequestBuilder;
import org.jboss.dna.graph.request.ChangeRequest;
-import org.jboss.dna.graph.request.CreateNodeRequest;
+import org.jboss.dna.graph.request.CopyBranchRequest;
import org.jboss.dna.graph.request.InvalidWorkspaceException;
import org.jboss.dna.graph.request.Request;
import org.jboss.dna.graph.session.GraphSession.Authorizer.Action;
@@ -148,7 +147,7 @@
} else {
this.workspaceName = this.store.getCurrentWorkspaceName();
}
- this.nodeOperations = nodeOperations != null ? nodeOperations : new SimpleNodeOperations<Payload, PropertyPayload>();
+ this.nodeOperations = nodeOperations != null ? nodeOperations : new NodeOperations<Payload, PropertyPayload>();
this.pathFactory = context.getValueFactories().getPathFactory();
this.authorizer = authorizer != null ? authorizer : new NoOpAuthorizer();
// Create the NodeId factory ...
@@ -171,6 +170,22 @@
this.operations = this.store.batch(this.requestBuilder);
}
+ final String readable( Name name ) {
+ return name.getString(context.getNamespaceRegistry());
+ }
+
+ final String readable( Path.Segment segment ) {
+ return segment.getString(context.getNamespaceRegistry());
+ }
+
+ final String readable( Path path ) {
+ return path.getString(context.getNamespaceRegistry());
+ }
+
+ final String readable( Location location ) {
+ return location.getString(context.getNamespaceRegistry());
+ }
+
/**
* Get the subgraph depth that is read when a node is loaded from the persistence store. By default, this value is 1.
*
@@ -211,6 +226,26 @@
}
/**
+ * Find in the session the node with the supplied location. If the location does not have a path, this method must first query
+ * the actual persistent store, even if the session already has loaded the node. Thus, this method may not be the most
+ * efficient technique to find a node.
+ *
+ * @param location the location of the node
+ * @return the cached node at the supplied location
+ * @throws PathNotFoundException if the node at the supplied location does not exist
+ * @throws AccessControlException if the user does not have permission to read the node given by the supplied location
+ * @throws IllegalArgumentException if the location is null
+ */
+ public Node<Payload, PropertyPayload> findNodeWith( Location location ) throws PathNotFoundException, AccessControlException {
+ if (!location.hasPath()) {
+ // Query for the actual location ...
+ location = store.getNodeAt(location).getLocation();
+ }
+ assert location.hasPath();
+ return findNodeWith(null, location.getPath());
+ }
+
+ /**
* Find in the session the node with the supplied identifier.
*
* @param id the identifier of the node
@@ -236,11 +271,13 @@
public Node<Payload, PropertyPayload> findNodeWith( NodeId id,
Path path ) throws PathNotFoundException, AccessControlException {
if (id == null && path == null) {
- CheckArg.isNotNull(path, "path and id");
+ CheckArg.isNotNull(id, "id");
+ CheckArg.isNotNull(path, "path");
}
Node<Payload, PropertyPayload> result = nodes.get(id); // if found, the user should have read privilege since it was
// already in the cache
- if (result == null && path != null) {
+ if (result == null || result.isStale()) {
+ assert path != null;
result = findNodeWith(path);
}
return result;
@@ -257,10 +294,29 @@
*/
public Node<Payload, PropertyPayload> findNodeWith( Path path ) throws PathNotFoundException, AccessControlException {
if (path.isRoot()) return getRoot();
- return findNodeRelativeTo(root, path.relativeTo(root.getPath()));
+ return findNodeRelativeTo(root, path.relativeTo(root.getPath()), true);
}
/**
+ * Find the node with the supplied path. This node quickly finds the node if it exists in the cache, or if it is not in the
+ * cache, it loads the nodes down the supplied path. However, if <code>loadIfRequired</code> is <code>false</code>, then any
+ * node along the path that is not loaded will result in this method returning null.
+ *
+ * @param path the path to the node
+ * @param loadIfRequired true if any missing nodes should be loaded, or false if null should be returned if any nodes along
+ * the path are not loaded
+ * @return the node information
+ * @throws PathNotFoundException if the node at the supplied path does not exist
+ * @throws AccessControlException if the user does not have permission to read the nodes given by the supplied path
+ */
+ protected Node<Payload, PropertyPayload> findNodeWith( Path path,
+ boolean loadIfRequired )
+ throws PathNotFoundException, AccessControlException {
+ if (path.isRoot()) return getRoot();
+ return findNodeRelativeTo(root, path.relativeTo(root.getPath()), loadIfRequired);
+ }
+
+ /**
* Find the node with the supplied path relative to another node. This node quickly finds the node by walking the supplied
* relative path starting at the supplied node. As soon as a cached node is found to not be fully loaded, the persistent
* information for that node and all remaining nodes along the relative path are read from the persistent store and inserted
@@ -273,10 +329,32 @@
* @throws PathNotFoundException if the node at the supplied path does not exist
* @throws AccessControlException if the user does not have permission to read the nodes given by the supplied path
*/
- @SuppressWarnings( "synthetic-access" )
public Node<Payload, PropertyPayload> findNodeRelativeTo( Node<Payload, PropertyPayload> startingPoint,
Path relativePath )
throws PathNotFoundException, AccessControlException {
+ return findNodeRelativeTo(startingPoint, relativePath, true);
+ }
+
+ /**
+ * Find the node with the supplied path relative to another node. This node quickly finds the node by walking the supplied
+ * relative path starting at the supplied node. As soon as a cached node is found to not be fully loaded, the persistent
+ * information for that node and all remaining nodes along the relative path are read from the persistent store and inserted
+ * into the cache.
+ *
+ * @param startingPoint the node from which the path is relative
+ * @param relativePath the relative path from the designated starting point to the desired node; may not be null and may not
+ * be an {@link Path#isAbsolute() absolute} path
+ * @param loadIfRequired true if any missing nodes should be loaded, or false if null should be returned if any nodes along
+ * the path are not loaded
+ * @return the node information, or null if the node was not yet loaded (and <code>loadRequired</code> was false)
+ * @throws PathNotFoundException if the node at the supplied path does not exist
+ * @throws AccessControlException if the user does not have permission to read the nodes given by the supplied path
+ */
+ @SuppressWarnings( "synthetic-access" )
+ protected Node<Payload, PropertyPayload> findNodeRelativeTo( Node<Payload, PropertyPayload> startingPoint,
+ Path relativePath,
+ boolean loadIfRequired )
+ throws PathNotFoundException, AccessControlException {
Node<Payload, PropertyPayload> node = startingPoint;
if (!relativePath.isRoot()) {
// Find the absolute path, which ensures that the relative path is well-formed ...
@@ -301,6 +379,7 @@
// The child is the next node we need to process ...
node = node.getChild(segment);
} else {
+ if (!loadIfRequired) return null;
// The node has not yet been loaded into the cache, so read this node
// from the store as well as all nodes along the path to the node we're really
// interested in. We'll do this in a batch, so first create this batch ...
@@ -351,7 +430,7 @@
node = previousNode;
}
}
- nodeOperations.update(persistentNode, previousNode);
+ nodeOperations.materialize(persistentNode, previousNode);
previousPath = path;
}
}
@@ -383,21 +462,29 @@
}
/**
- * Move this node from its current location so that is is a child of the supplied parent, but do so immediately without
- * enqueuing the operation within the session's operations.
+ * Move this node from its current location so that is is a child of the supplied parent, doing so immediately without
+ * enqueuing the operation within the session's operations. The current session is modified immediately to reflect the move
+ * result.
*
- * @param nodeToMove the node that is to be moved; may not be null
- * @param newParent the new parent for this node; may not be null
- * @param newName the new name for the node, or null if the node is not to be renamed
- * @throws RepositorySourceException if the parent node is to be loaded but a problem is encountered while doing so
+ * @param nodeToMove the path to the node that is to be moved; may not be null
+ * @param destination the desired new path; may not be null
* @throws IllegalArgumentException if the node being moved is the root node
+ * @throws AccessControlException if the caller does not have the permission to perform the operation
+ * @throws RepositorySourceException if any error resulting while performing the operation
*/
- public void immediateMove( Node<Payload, PropertyPayload> nodeToMove,
- Node<Payload, PropertyPayload> newParent,
- Name newName ) {
+ public void immediateMove( Path nodeToMove,
+ Path destination ) throws AccessControlException, RepositorySourceException {
CheckArg.isNotNull(nodeToMove, "nodeToMove");
- CheckArg.isNotNull(newParent, "newParent");
- nodeToMove.moveTo(newParent, newName, false);
+ CheckArg.isNotNull(destination, "destination");
+
+ Path newParentPath = destination.getParent();
+ Name newName = destination.getLastSegment().getName();
+
+ // Check authorization ...
+ authorizer.checkPermissions(newParentPath, Action.ADD_NODE);
+ authorizer.checkPermissions(nodeToMove.getParent(), Action.REMOVE);
+
+ store.move(nodeToMove).as(newName).into(newParentPath);
}
/**
@@ -410,11 +497,13 @@
* </p>
*
* @param source the path to the node that is to be copied; may not be null
- * @param destination the path where the copy is to be placed; may not be null index
+ * @param destination the path where the copy is to be placed; may not be null
* @throws IllegalArgumentException either path is null or invalid
+ * @throws AccessControlException if the caller does not have the permission to perform the operation
+ * @throws RepositorySourceException if any error resulting while performing the operation
*/
public void immediateCopy( Path source,
- Path destination ) {
+ Path destination ) throws AccessControlException, RepositorySourceException {
immediateCopy(source, workspaceName, destination);
}
@@ -430,55 +519,73 @@
* @param source the path to the node that is to be copied; may not be null
* @param sourceWorkspace the name of the workspace where the source node is to be found, or null if the current workspace
* should be used
- * @param destination the path where the copy is to be placed; may not be null index
+ * @param destination the path where the copy is to be placed; may not be null
* @throws IllegalArgumentException either path is null or invalid
+ * @throws PathNotFoundException if the node being copied or the parent of the destination path do not exist
* @throws InvalidWorkspaceException if the source workspace name is invalid or does not exist
+ * @throws AccessControlException if the caller does not have the permission to perform the operation
+ * @throws RepositorySourceException if any error resulting while performing the operation
*/
public void immediateCopy( Path source,
String sourceWorkspace,
- Path destination ) {
+ Path destination )
+ throws InvalidWorkspaceException, AccessControlException, PathNotFoundException, RepositorySourceException {
CheckArg.isNotNull(source, "source");
CheckArg.isNotNull(destination, "destination");
if (sourceWorkspace == null) sourceWorkspace = workspaceName;
+ // Check authorization ...
+ authorizer.checkPermissions(destination, Action.ADD_NODE);
+ authorizer.checkPermissions(source, Action.READ);
+
// Perform the copy operation, but use the "to" form (not the "into", which takes the parent), but
// but use a batch so that we can read the latest list of children ...
- Results results = store.batch()
- .copy(source)
- .fromWorkspace(sourceWorkspace)
- .to(destination)
- .and()
- .readChildren()
- .of(destination.getParent())
- .execute();
+ Results results = store.batch().copy(source).fromWorkspace(sourceWorkspace).to(destination).execute();
- // Now get the children of the destination's parent ...
- Location parentLocation = results.getNode(destination).getLocation();
+ // Find the copy request to get the actual location of the copy ...
+ CopyBranchRequest request = (CopyBranchRequest)results.getRequests().get(0);
+ Location locationOfCopy = request.getActualLocationAfter();
+
// Find the parent node in the session ...
- Node<Payload, PropertyPayload> parent = this.findNodeWith(parentLocation.getPath());
- if (parent.isLoaded()) {
+ Node<Payload, PropertyPayload> parent = this.findNodeWith(locationOfCopy.getPath().getParent(), false);
+ if (parent != null && parent.isLoaded()) {
// Update the children to make them match the latest snapshot from the store ...
- List<Location> newChildren = results.getNode(parentLocation).getChildren();
- parent.synchronize(newChildren);
+ parent.synchronizeWithNewlyPersistedNode(locationOfCopy);
}
}
/**
* Clone the supplied source branch and place into the destination location, optionally removing any existing copy that
- * already exists in the destination location.
+ * already exists in the destination location, doing so immediately without enqueuing the operation within the session's
+ * operations. The current session is modified immediately to reflect the clone result.
*
- * @param source
- * @param sourceWorkspace
- * @param destination
+ * @param source the path to the node that is to be cloned; may not be null
+ * @param sourceWorkspace the name of the workspace where the source node is to be found, or null if the current workspace
+ * should be used
+ * @param destination the path for the new cloned copy; may not be null index
* @param removeExisting true if the original should be removed, or false if the original should be left
+ * @throws IllegalArgumentException either path is null or invalid
+ * @throws InvalidWorkspaceException if the source workspace name is invalid or does not exist
* @throws UuidAlreadyExistsException if copy could not be completed because the current workspace already includes at least
* one of the nodes at or below the <code>source</code> branch in the source workspace
+ * @throws PathNotFoundException if the node being clone or the destination node do not exist
+ * @throws AccessControlException if the caller does not have the permission to perform the operation
+ * @throws RepositorySourceException if any error resulting while performing the operation
*/
public void immediateClone( Path source,
String sourceWorkspace,
Path destination,
- boolean removeExisting ) {
+ boolean removeExisting )
+ throws InvalidWorkspaceException, AccessControlException, UuidAlreadyExistsException, PathNotFoundException,
+ RepositorySourceException {
+ CheckArg.isNotNull(source, "source");
+ CheckArg.isNotNull(destination, "destination");
+ if (sourceWorkspace == null) sourceWorkspace = workspaceName;
+ // Check authorization ...
+ authorizer.checkPermissions(destination.getParent(), Action.ADD_NODE);
+ authorizer.checkPermissions(source, Action.READ);
+
// Perform the copy operation, but use the "to" form (not the "into", which takes the parent), but
// but use a batch so that we can read the latest list of children ...
Graph.Batch batch = store.batch();
@@ -494,14 +601,15 @@
// Now execute these two operations ...
Results results = batch.execute();
- // Now get the children of the destination's parent ...
- Location parentLocation = results.getNode(destination).getLocation();
+ // Find the copy request to get the actual location of the copy ...
+ CopyBranchRequest request = (CopyBranchRequest)results.getRequests().get(0);
+ Location locationOfCopy = request.getActualLocationAfter();
+
// Find the parent node in the session ...
- Node<Payload, PropertyPayload> parent = this.findNodeWith(parentLocation.getPath());
- if (parent.isLoaded()) {
+ Node<Payload, PropertyPayload> parent = this.findNodeWith(locationOfCopy.getPath().getParent(), false);
+ if (parent != null && parent.isLoaded()) {
// Update the children to make them match the latest snapshot from the store ...
- List<Location> newChildren = results.getNode(parentLocation).getChildren();
- parent.synchronize(newChildren);
+ parent.synchronizeWithNewlyPersistedNode(locationOfCopy);
}
}
@@ -528,9 +636,10 @@
requests.clear();
changeDependencies.clear();
// And force the root node to be 'unloaded' (in an efficient way) ...
- root.changed = false;
+ root.status = Status.UNCHANGED;
root.childrenByName = null;
root.expirationTime = Long.MAX_VALUE;
+ root.changedBelow = false;
}
}
@@ -571,7 +680,11 @@
}
// Execute the reads. No modifications have been made to the cache, so it is not a problem
// if this throws a repository exception.
- readResults = batch.execute();
+ try {
+ readResults = batch.execute();
+ } catch (org.jboss.dna.graph.property.PathNotFoundException e) {
+ throw new InvalidStateException(e.getLocalizedMessage(), e);
+ }
}
// Phase 2: update the cache by unloading or refreshing the nodes ...
@@ -609,19 +722,33 @@
*/
public void save() throws PathNotFoundException, ValidationException, InvalidStateException {
if (!operations.isExecuteRequired()) return;
- assert root.isChanged(true);
+ if (!root.isChanged(true)) {
+ // Then a bunch of changes could have been made and rolled back manually, so recompute the change state ...
+ root.recomputeChangedBelow();
+ if (!root.isChanged(true)) {
+ // If still no changes, then simply do a refresh ...
+ refresh(false);
+ return;
+ }
+ }
// Make sure that each of the changed node is valid. This process requires that all children of
// all changed nodes are loaded, so in this process load all unloaded children in one batch ...
root.onChangedNodes(new LoadAllChildrenVisitor() {
@Override
protected void finishParentAfterLoading( Node<Payload, PropertyPayload> node ) {
- nodeOperations.validate(node);
+ nodeOperations.preSave(node);
}
});
// Execute the batched operations ...
- operations.execute();
+ try {
+ operations.execute();
+ } catch (org.jboss.dna.graph.property.PathNotFoundException e) {
+ throw new InvalidStateException(e.getLocalizedMessage(), e);
+ } catch (RuntimeException e) {
+ throw new RepositorySourceException(e.getLocalizedMessage(), e);
+ }
// Create a new batch for future operations ...
// LinkedList<Request> oldRequests = this.requests;
@@ -659,6 +786,11 @@
I18n msg = GraphI18n.nodeHasAlreadyBeenRemovedFromThisSession;
throw new InvalidStateException(msg.text(readableLocation, workspaceName));
}
+ if (node.isNew()) {
+ String path = readable(node.getPath());
+ throw new RepositorySourceException(GraphI18n.unableToSaveNodeThatWasCreatedSincePreviousSave.text(path,
+ workspaceName));
+ }
if (!node.isChanged(true)) {
// There are no changes within this branch
return;
@@ -668,7 +800,7 @@
if (!node.containsChangesWithExternalDependencies()) {
I18n msg = GraphI18n.unableToSaveBranchBecauseChangesDependOnChangesToNodesOutsideOfBranch;
String path = node.getPath().getString(context.getNamespaceRegistry());
- throw new InvalidStateException(msg.text(path, workspaceName));
+ throw new ValidationException(msg.text(path, workspaceName));
}
// Make sure that each of the changed node is valid. This process requires that all children of
@@ -676,7 +808,7 @@
root.onChangedNodes(new LoadAllChildrenVisitor() {
@Override
protected void finishParentAfterLoading( Node<Payload, PropertyPayload> node ) {
- nodeOperations.validate(node);
+ nodeOperations.preSave(node);
}
});
@@ -687,22 +819,11 @@
Path path = node.getPath();
LinkedList<Request> branchRequests = new LinkedList<Request>();
LinkedList<Request> nonBranchRequests = new LinkedList<Request>();
- Set<UUID> branchUuids = new HashSet<UUID>();
for (Request request : this.requests) {
assert request instanceof ChangeRequest;
ChangeRequest change = (ChangeRequest)request;
if (change.changes(workspaceName, path)) {
branchRequests.add(request);
- // Record the UUID of the node being saved now ...
- UUID changedUuid = null;
- if (change instanceof CreateNodeRequest) {
- // We want the parent UUID ...
- changedUuid = ((CreateNodeRequest)change).under().getUuid();
- } else {
- changedUuid = change.changedLocation().getUuid();
- }
- assert changedUuid != null;
- branchUuids.add(changedUuid);
} else {
nonBranchRequests.add(request);
}
@@ -711,7 +832,13 @@
// Now execute the branch ...
Graph.Batch branchBatch = store.batch(new BatchRequestBuilder(branchRequests));
- branchBatch.execute();
+ try {
+ branchBatch.execute();
+ } catch (org.jboss.dna.graph.property.PathNotFoundException e) {
+ throw new InvalidStateException(e.getLocalizedMessage(), e);
+ } catch (RuntimeException e) {
+ throw new RepositorySourceException(e.getLocalizedMessage(), e);
+ }
// Still have non-branch related requests that we haven't executed ...
this.requests = nonBranchRequests;
@@ -795,8 +922,8 @@
* @param persistentNode the persistent node that should be converted into a node info; never null
* @param node the session's node representation that is to be updated; never null
*/
- void update( org.jboss.dna.graph.Node persistentNode,
- Node<NodePayload, PropertyPayload> node );
+ void materialize( org.jboss.dna.graph.Node persistentNode,
+ Node<NodePayload, PropertyPayload> node );
/**
* Signal that the node's {@link GraphSession.Node#getLocation() location} has been changed
@@ -804,16 +931,124 @@
* @param node the node with the new location
* @param oldLocation the old location of the node
*/
- void updateLocation( Node<NodePayload, PropertyPayload> node,
- Location oldLocation );
+ void postUpdateLocation( Node<NodePayload, PropertyPayload> node,
+ Location oldLocation );
+ void preSetProperty( Node<NodePayload, PropertyPayload> node,
+ Name propertyName,
+ PropertyInfo<PropertyPayload> newProperty ) throws ValidationException;
+
+ void postSetProperty( Node<NodePayload, PropertyPayload> node,
+ Name propertyName,
+ PropertyInfo<PropertyPayload> oldProperty );
+
+ void preRemoveProperty( Node<NodePayload, PropertyPayload> node,
+ Name propertyName ) throws ValidationException;
+
+ void postRemoveProperty( Node<NodePayload, PropertyPayload> node,
+ Name propertyName,
+ PropertyInfo<PropertyPayload> oldProperty );
+
/**
+ * Notify that a new child with the supplied path segment is about to be created. When this method is called, the child
+ * has not yet been added to the parent node.
+ *
+ * @param parentNode the parent node; never null
+ * @param newChild the path segment for the new child; never null
+ * @param properties the initial properties for the new child, which can be manipulated directly; never null
+ * @throws ValidationException if the parent may not have a child with the supplied name and the creation of the new node
+ * should be aborted
+ */
+ void preCreateChild( Node<NodePayload, PropertyPayload> parentNode,
+ Path.Segment newChild,
+ Map<Name, PropertyInfo<PropertyPayload>> properties ) throws ValidationException;
+
+ /**
+ * Notify that a new child has been added to the supplied parent node. The child may have an initial set of properties
+ * specified at creation time, although none of the PropertyInfo objects will have a
+ * {@link GraphSession.PropertyInfo#getPayload() payload}.
+ *
+ * @param parentNode the parent node; never null
+ * @param newChild the child that was just added to the parent node; never null
+ * @param properties the properties of the child, which can be manipulated directly; never null
+ * @throws ValidationException if the parent and child are not valid and the creation of the new node should be aborted
+ */
+ void postCreateChild( Node<NodePayload, PropertyPayload> parentNode,
+ Node<NodePayload, PropertyPayload> newChild,
+ Map<Name, PropertyInfo<PropertyPayload>> properties ) throws ValidationException;
+
+ /**
+ * Notify that an existing child will be moved from its current parent and placed under the supplied parent. When this
+ * method is called, the child node has not yet been moved.
+ *
+ * @param nodeToBeMoved the existing node that is to be moved from its current parent to the supplied parent; never null
+ * @param newParentNode the new parent node; never null
+ * @throws ValidationException if the child should not be moved
+ */
+ void preMove( Node<NodePayload, PropertyPayload> nodeToBeMoved,
+ Node<NodePayload, PropertyPayload> newParentNode ) throws ValidationException;
+
+ /**
+ * Notify that an existing child has been moved from the supplied previous parent into its new location. When this method
+ * is called, the child node has been moved and any same-name-siblings that were after the child in the old parent have
+ * had their SNS indexes adjusted.
+ *
+ * @param movedNode the existing node that is was moved; never null
+ * @param oldParentNode the old parent node; never null
+ */
+ void postMove( Node<NodePayload, PropertyPayload> movedNode,
+ Node<NodePayload, PropertyPayload> oldParentNode );
+
+ /**
+ * Notify that an existing child will be copied with the new copy being placed under the supplied parent. When this method
+ * is called, the copy has not yet been performed.
+ *
+ * @param original the existing node that is to be copied; never null
+ * @param newParentNode the parent node where the copy is to be placed; never null
+ * @throws ValidationException if the copy is not valid
+ */
+ void preCopy( Node<NodePayload, PropertyPayload> original,
+ Node<NodePayload, PropertyPayload> newParentNode ) throws ValidationException;
+
+ /**
+ * Notify that an existing child will be copied with the new copy being placed under the supplied parent. When this method
+ * is called, the copy has been performed, but the new copy will not be loaded nor will be capable of being loaded.
+ *
+ * @param original the original node that was copied; never null
+ * @param copy the new copy that was made; never null
+ */
+ void postCopy( Node<NodePayload, PropertyPayload> original,
+ Node<NodePayload, PropertyPayload> copy );
+
+ /**
+ * Notify that an existing child will be removed from the supplied parent. When this method is called, the child node has
+ * not yet been removed.
+ *
+ * @param parentNode the parent node; never null
+ * @param child the child that is to be removed from the parent node; never null
+ * @throws ValidationException if the child should not be removed from the parent node
+ */
+ void preRemoveChild( Node<NodePayload, PropertyPayload> parentNode,
+ Node<NodePayload, PropertyPayload> child ) throws ValidationException;
+
+ /**
+ * Notify that an existing child has been removed from the supplied parent. When this method is called, the child node has
+ * been removed and any same-name-siblings following the child have had their SNS indexes adjusted. Additionally, the
+ * removed child no longer has a parent and is considered {@link GraphSession.Node#isStale() stale}.
+ *
+ * @param parentNode the parent node; never null
+ * @param removedChild the child that is to be removed from the parent node; never null
+ */
+ void postRemoveChild( Node<NodePayload, PropertyPayload> parentNode,
+ Node<NodePayload, PropertyPayload> removedChild );
+
+ /**
* Validate a node for consistency and well-formedness.
*
* @param node the node to be validated
* @throws ValidationException if there is a problem during validation
*/
- void validate( Node<NodePayload, PropertyPayload> node ) throws ValidationException;
+ void preSave( Node<NodePayload, PropertyPayload> node ) throws ValidationException;
}
@ThreadSafe
@@ -859,22 +1094,29 @@
}
}
+ /**
+ * A default implementation of {@link GraphSession.Operations} that provides all the basic functionality required by a graph
+ * session. In this implementation, only the {@link GraphSession.NodeOperations#materialize(org.jboss.dna.graph.Node, Node)
+ * materialize(...)} method does something.
+ *
+ * @param <Payload> the type of node payload object
+ * @param <PropertyPayload> the type of property payload object
+ */
@ThreadSafe
- protected static class SimpleNodeOperations<Payload, PropertyPayload> implements Operations<Payload, PropertyPayload> {
+ public static class NodeOperations<Payload, PropertyPayload> implements Operations<Payload, PropertyPayload> {
/**
* {@inheritDoc}
*
- * @see GraphSession.Operations#update(org.jboss.dna.graph.Node, GraphSession.Node)
+ * @see GraphSession.Operations#materialize(org.jboss.dna.graph.Node, GraphSession.Node)
*/
- public void update( org.jboss.dna.graph.Node persistentNode,
- Node<Payload, PropertyPayload> node ) {
+ public void materialize( org.jboss.dna.graph.Node persistentNode,
+ Node<Payload, PropertyPayload> node ) {
// Create the map of property info objects ...
Map<Name, PropertyInfo<PropertyPayload>> properties = new HashMap<Name, PropertyInfo<PropertyPayload>>();
for (Property property : persistentNode.getProperties()) {
Name propertyName = property.getName();
- PropertyId id = new PropertyId(node.getNodeId(), propertyName);
- PropertyInfo<PropertyPayload> info = new PropertyInfo<PropertyPayload>(id, property, property.isMultiple(),
- PropertyStatus.UNCHANGED, null);
+ PropertyInfo<PropertyPayload> info = new PropertyInfo<PropertyPayload>(property, property.isMultiple(),
+ Status.UNCHANGED, null);
properties.put(propertyName, info);
}
// Set only the children ...
@@ -884,21 +1126,150 @@
/**
* {@inheritDoc}
*
- * @see GraphSession.Operations#updateLocation(GraphSession.Node, org.jboss.dna.graph.Location)
+ * @see GraphSession.Operations#postUpdateLocation(GraphSession.Node, org.jboss.dna.graph.Location)
*/
- public void updateLocation( Node<Payload, PropertyPayload> node,
- Location oldLocation ) {
+ public void postUpdateLocation( Node<Payload, PropertyPayload> node,
+ Location oldLocation ) {
// do nothing here
}
/**
* {@inheritDoc}
*
- * @see GraphSession.Operations#validate(GraphSession.Node)
+ * @see GraphSession.Operations#preSave(GraphSession.Node)
*/
- public void validate( Node<Payload, PropertyPayload> node ) {
+ public void preSave( Node<Payload, PropertyPayload> node ) throws ValidationException {
// do nothing here
}
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.graph.session.GraphSession.Operations#preSetProperty(Node, Name, PropertyInfo)
+ */
+ public void preSetProperty( Node<Payload, PropertyPayload> node,
+ Name propertyName,
+ PropertyInfo<PropertyPayload> newProperty ) throws ValidationException {
+ // do nothing here
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.graph.session.GraphSession.Operations#postSetProperty(Node, Name, PropertyInfo)
+ */
+ public void postSetProperty( Node<Payload, PropertyPayload> node,
+ Name propertyName,
+ PropertyInfo<PropertyPayload> oldProperty ) {
+ // do nothing here
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.graph.session.GraphSession.Operations#preRemoveProperty(Node, Name)
+ */
+ public void preRemoveProperty( Node<Payload, PropertyPayload> node,
+ Name propertyName ) throws ValidationException {
+ // do nothing here
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.graph.session.GraphSession.Operations#postRemoveProperty(Node, Name, PropertyInfo)
+ */
+ public void postRemoveProperty( Node<Payload, PropertyPayload> node,
+ Name propertyName,
+ PropertyInfo<PropertyPayload> oldProperty ) {
+ // do nothing here
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.graph.session.GraphSession.Operations#preCreateChild(org.jboss.dna.graph.session.GraphSession.Node,
+ * org.jboss.dna.graph.property.Path.Segment, java.util.Map)
+ */
+ public void preCreateChild( Node<Payload, PropertyPayload> parent,
+ Segment newChild,
+ Map<Name, PropertyInfo<PropertyPayload>> properties ) throws ValidationException {
+ // do nothing here
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.graph.session.GraphSession.Operations#postCreateChild(org.jboss.dna.graph.session.GraphSession.Node,
+ * org.jboss.dna.graph.session.GraphSession.Node, java.util.Map)
+ */
+ public void postCreateChild( Node<Payload, PropertyPayload> parent,
+ Node<Payload, PropertyPayload> childChild,
+ Map<Name, PropertyInfo<PropertyPayload>> properties ) throws ValidationException {
+ // do nothing here
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.graph.session.GraphSession.Operations#preCopy(org.jboss.dna.graph.session.GraphSession.Node,
+ * org.jboss.dna.graph.session.GraphSession.Node)
+ */
+ public void preCopy( Node<Payload, PropertyPayload> original,
+ Node<Payload, PropertyPayload> newParent ) throws ValidationException {
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.graph.session.GraphSession.Operations#postCopy(org.jboss.dna.graph.session.GraphSession.Node,
+ * org.jboss.dna.graph.session.GraphSession.Node)
+ */
+ public void postCopy( Node<Payload, PropertyPayload> original,
+ Node<Payload, PropertyPayload> copy ) throws ValidationException {
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.graph.session.GraphSession.Operations#preMove(org.jboss.dna.graph.session.GraphSession.Node,
+ * org.jboss.dna.graph.session.GraphSession.Node)
+ */
+ public void preMove( Node<Payload, PropertyPayload> nodeToBeMoved,
+ Node<Payload, PropertyPayload> newParent ) throws ValidationException {
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.graph.session.GraphSession.Operations#postMove(org.jboss.dna.graph.session.GraphSession.Node,
+ * org.jboss.dna.graph.session.GraphSession.Node)
+ */
+ public void postMove( Node<Payload, PropertyPayload> movedNode,
+ Node<Payload, PropertyPayload> oldParent ) {
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.graph.session.GraphSession.Operations#preRemoveChild(org.jboss.dna.graph.session.GraphSession.Node,
+ * org.jboss.dna.graph.session.GraphSession.Node)
+ */
+ public void preRemoveChild( Node<Payload, PropertyPayload> parent,
+ Node<Payload, PropertyPayload> newChild ) throws ValidationException {
+ // do nothing here
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.graph.session.GraphSession.Operations#postRemoveChild(org.jboss.dna.graph.session.GraphSession.Node,
+ * org.jboss.dna.graph.session.GraphSession.Node)
+ */
+ public void postRemoveChild( Node<Payload, PropertyPayload> parent,
+ Node<Payload, PropertyPayload> oldChild ) {
+ // do nothing here
+ }
}
@NotThreadSafe
@@ -908,16 +1279,16 @@
private Node<Payload, PropertyPayload> parent;
private long expirationTime = Long.MAX_VALUE;
private Location location;
- private boolean changed;
+ private Status status = Status.UNCHANGED;
private boolean changedBelow;
private Map<Name, PropertyInfo<PropertyPayload>> properties;
private ListMultimap<Name, Node<Payload, PropertyPayload>> childrenByName;
private Payload payload;
- protected Node( GraphSession<Payload, PropertyPayload> cache,
- Node<Payload, PropertyPayload> parent,
- NodeId nodeId,
- Location location ) {
+ public Node( GraphSession<Payload, PropertyPayload> cache,
+ Node<Payload, PropertyPayload> parent,
+ NodeId nodeId,
+ Location location ) {
this.cache = cache;
this.parent = parent;
this.nodeId = nodeId;
@@ -929,6 +1300,15 @@
}
/**
+ * Get the session to which this node belongs.
+ *
+ * @return the session; never null
+ */
+ public GraphSession<Payload, PropertyPayload> getSession() {
+ return cache;
+ }
+
+ /**
* Get the time when this node expires.
*
* @return the time in milliseconds past the epoch when this node's cached information expires, or {@link Long#MAX_VALUE
@@ -937,7 +1317,6 @@
* @see #isLoaded()
*/
public final long getExpirationTimeInMillis() {
- assert !isStale();
return expirationTime;
}
@@ -975,11 +1354,19 @@
/**
* Method that causes the information for this node to be read from the store and loaded into the cache
*
+ * @throws AccessControlException if the caller does not have the permission to perform the operation
* @throws RepositorySourceException if there is a problem reading the store
*/
protected final void load() throws RepositorySourceException {
if (isLoaded()) return;
assert !isStale();
+ // If this node is new, then there's nothing to read ...
+ if (status == Status.NEW) {
+ this.childrenByName = cache.NO_CHILDREN;
+ this.properties = cache.NO_PROPERTIES;
+ return;
+ }
+
// Check authorization before reading ...
Path path = getPath();
cache.authorizer.checkPermissions(path, Action.READ);
@@ -994,7 +1381,7 @@
this.location = actualLocation;
}
// Update the persistent information ...
- cache.nodeOperations.update(persistentNode, this);
+ cache.nodeOperations.materialize(persistentNode, this);
} else {
// Then read the node from the store ...
Subgraph subgraph = cache.store.getSubgraphOfDepth(depth).at(getLocation());
@@ -1004,7 +1391,7 @@
this.location = actualLocation;
}
// Update the persistent information ...
- cache.nodeOperations.update(subgraph.getRoot(), this);
+ cache.nodeOperations.materialize(subgraph.getRoot(), this);
// Now update any nodes below this node ...
for (org.jboss.dna.graph.Node persistentNode : subgraph) {
// Find the node at the path ...
@@ -1012,7 +1399,7 @@
Node<Payload, PropertyPayload> node = cache.findNodeRelativeTo(this, relativePath);
if (!node.isLoaded()) {
// Update the persistent information ...
- cache.nodeOperations.update(persistentNode, node);
+ cache.nodeOperations.materialize(persistentNode, node);
}
}
}
@@ -1023,7 +1410,7 @@
*/
protected final void unload() {
assert !isStale();
- assert !changed;
+ assert status == Status.UNCHANGED;
assert !changedBelow;
if (!isLoaded()) return;
cache.recordUnloaded(this);
@@ -1084,8 +1471,8 @@
protected final void refreshPhase2( RefreshState<Payload, PropertyPayload> refreshState,
Results persistentInfoForRefreshedNodes ) {
assert !isStale();
- if (this.changed) {
- // There's nothing to do ...
+ if (this.status != Status.UNCHANGED) {
+ // There are changes, so nothing to do ...
return;
}
if (refreshState.requiresRefresh(this)) {
@@ -1121,15 +1508,15 @@
return;
}
// This node can be unloaded (since it has no changes and isn't above a node with changes) ...
- unload();
+ if (!this.changedBelow) unload();
}
/**
* Define the persistent child information that this node is to be populated with. This method does not cause the node's
* information to be read from the store.
* <p>
- * This method is intended to be called by the {@link GraphSession.Operations#update(org.jboss.dna.graph.Node, Node)}, and
- * should not be called by other components.
+ * This method is intended to be called by the {@link GraphSession.Operations#materialize(org.jboss.dna.graph.Node, Node)}
+ * , and should not be called by other components.
* </p>
*
* @param children the children for this node; may not be null
@@ -1177,11 +1564,14 @@
protected void updateLocation( Path.Segment segment ) {
assert !isStale();
Path newPath = null;
+ Path currentPath = getPath();
if (segment != null) {
+ if (segment.equals(currentPath.getLastSegment())) return;
// Recompute the path based upon the parent path ...
Path parentPath = getParent().getPath();
newPath = cache.pathFactory.create(parentPath, segment);
} else {
+ if (this.isRoot()) return;
// This must be the root ...
newPath = cache.pathFactory.createRootPath();
assert this.isRoot();
@@ -1190,7 +1580,7 @@
if (newLocation != this.location) {
Location oldLocation = this.location;
this.location = newLocation;
- cache.nodeOperations.updateLocation(this, oldLocation);
+ cache.nodeOperations.postUpdateLocation(this, oldLocation);
}
if (isLoaded() && childrenByName != cache.NO_CHILDREN) {
@@ -1206,19 +1596,61 @@
}
}
- protected void synchronize( List<Location> actualChildren ) {
- if (!isLoaded()) return;
- for (Location actualChild : actualChildren) {
- Path.Segment actualSegment = actualChild.getPath().getLastSegment();
- Node<Payload, PropertyPayload> existingChild = parent.getChild(actualSegment);
- if (existingChild == null) {
- // The child doesn't exist yet ...
- NodeId nodeId = cache.idFactory.create();
- Node<Payload, PropertyPayload> newChild = cache.createNode(this, nodeId, actualChild);
- parent.childrenByName.put(actualSegment.getName(), newChild);
+ /**
+ * This method is used to adjust the existing children by adding a child that was recently added to the persistent store
+ * (via clone or copy). The new child will appear at the end of the existing children, but before any children that were
+ * added to, moved into, created under this parent.
+ *
+ * @param newChild the new child that was added
+ */
+ protected void synchronizeWithNewlyPersistedNode( Location newChild ) {
+ if (!this.isLoaded()) return;
+ Path childPath = newChild.getPath();
+ Name childName = childPath.getLastSegment().getName();
+ if (this.childrenByName.isEmpty()) {
+ // Just have to add the child ...
+ this.childrenByName = Multimaps.newLinkedListMultimap();
+ if (childPath.getLastSegment().hasIndex()) {
+ // The child has a SNS index, but this is an only child ...
+ newChild = newChild.with(cache.pathFactory.create(childPath.getParent(), childName));
}
+ Node<Payload, PropertyPayload> child = cache.createNode(this, cache.idFactory.create(), newChild);
+ this.childrenByName.put(childName, child);
+ return;
}
+ // Unfortunately, there is no efficient way to insert into the multi-map, so we need to recreate it ...
+ ListMultimap<Name, Node<Payload, PropertyPayload>> children = Multimaps.newLinkedListMultimap();
+ boolean added = false;
+ for (Node<Payload, PropertyPayload> child : this.childrenByName.values()) {
+ if (!added && child.isNew()) {
+ // Add the new child here ...
+ Node<Payload, PropertyPayload> newChildNode = cache.createNode(this, cache.idFactory.create(), newChild);
+ children.put(childName, newChildNode);
+ added = true;
+ }
+ children.put(child.getName(), child);
+ }
+ if (!added) {
+ Node<Payload, PropertyPayload> newChildNode = cache.createNode(this, cache.idFactory.create(), newChild);
+ children.put(childName, newChildNode);
+ }
+
+ // Replace the children ...
+ this.childrenByName = children;
+
+ // Adjust the SNS indexes for those children with the same name as 'childToBeMoved' ...
+ List<Node<Payload, PropertyPayload>> childrenWithName = childrenByName.get(childName);
+ int snsIndex = 1;
+ for (Node<Payload, PropertyPayload> sns : childrenWithName) {
+ if (sns.getSegment().getIndex() != snsIndex) {
+ // The SNS index is not correct, so fix it and update the location ...
+ Path.Segment newSegment = cache.pathFactory.createSegment(childName, snsIndex);
+ sns.updateLocation(newSegment);
+ sns.markAsChanged();
+ }
+ ++snsIndex;
+ }
}
/**
@@ -1228,11 +1660,21 @@
* @return true if there are changes in the specified scope, or false otherwise
*/
public final boolean isChanged( boolean recursive ) {
- assert !isStale();
- return recursive ? this.changed || this.changedBelow : this.changed;
+ if (this.status == Status.UNCHANGED) return recursive && this.changedBelow;
+ return true;
}
/**
+ * Determine whether this node has been created since the last save. If this method returns true, then by definition the
+ * parent node will be marked as having {@link #isChanged(boolean) changed}.
+ *
+ * @return true if this node is new, or false otherwise
+ */
+ public final boolean isNew() {
+ return this.status == Status.NEW;
+ }
+
+ /**
* This method determines whether this node, or any nodes below it, contain changes that depend on nodes that are outside
* of this branch.
*
@@ -1295,8 +1737,8 @@
*/
public void clearChanges() {
assert !isStale();
- if (this.changed) {
- this.changed = false;
+ if (this.status != Status.UNCHANGED) {
+ this.status = Status.UNCHANGED;
this.changedBelow = false;
unload();
} else {
@@ -1317,13 +1759,33 @@
* Mark this node as having changes.
*
* @see #clearChanges()
+ * @see #markAsNew()
*/
public final void markAsChanged() {
assert !isStale();
- this.changed = true;
+ if (this.status == Status.NEW) return;
+ this.status = Status.CHANGED;
if (this.parent != null) this.parent.markAsChangedBelow();
}
+ public final void markAsCopied() {
+ assert !isStale();
+ this.status = Status.COPIED;
+ if (this.parent != null) this.parent.markAsChangedBelow();
+ }
+
+ /**
+ * Mark this node has having been created and not yet saved.
+ *
+ * @see #clearChanges()
+ * @see #markAsChanged()
+ */
+ public final void markAsNew() {
+ assert !isStale();
+ this.status = Status.NEW;
+ if (this.parent != null) this.parent.markAsChanged();
+ }
+
protected final void markAsChangedBelow() {
if (!this.changedBelow) {
this.changedBelow = true;
@@ -1378,15 +1840,25 @@
* @param newNodeName the new name for the node, or null if the node should keep the same name
* @param useBatch true if this operation should be performed using the session's current batch operation and executed
* upon {@link GraphSession#save()}, or false if the move should be performed immediately
+ * @throws ValidationException if the supplied parent node is a decendant of this node
* @throws RepositorySourceException if the parent node is to be loaded but a problem is encountered while doing so
* @throws IllegalArgumentException if this is the root node
+ * @throws AccessControlException if the caller does not have the permission to perform the operation
*/
protected void moveTo( Node<Payload, PropertyPayload> parent,
Name newNodeName,
boolean useBatch ) {
final Node<Payload, PropertyPayload> child = this;
assert !parent.isStale();
- assert child.parent != this;
+ // Make sure the parent is not a decendant of the child ...
+ if (parent.isAtOrBelow(child)) {
+ String path = getPath().getString(cache.context.getNamespaceRegistry());
+ String parentPath = parent.getPath().getString(cache.context.getNamespaceRegistry());
+ String workspaceName = cache.workspaceName;
+ String msg = GraphI18n.unableToMoveNodeToBeChildOfDecendent.text(path, parentPath, workspaceName);
+ throw new ValidationException(msg);
+ }
+
assert !child.isRoot();
if (newNodeName == null) newNodeName = getName();
@@ -1395,13 +1867,9 @@
cache.authorizer.checkPermissions(child.getPath().getParent(), Action.REMOVE);
parent.load();
- if (parent.childrenByName == cache.NO_CHILDREN) {
- parent.childrenByName = Multimaps.newLinkedListMultimap();
- }
- Name childName = child.getName();
- List<Node<Payload, PropertyPayload>> currentChildren = parent.childrenByName.get(childName);
- currentChildren.add(child);
- parent.markAsChanged();
+
+ cache.nodeOperations.preMove(child, parent);
+
// Remove the child from it's existing parent ...
final Node<Payload, PropertyPayload> oldParent = child.parent;
// Record the operation ...
@@ -1418,25 +1886,46 @@
cache.store.move(child.getLocation()).as(newNodeName).into(parent.getLocation());
}
}
- cache.recordMove(child, oldParent, parent);
+ // Remove the child from the current location (even if its the same node; there's cleanup to do) ...
child.remove();
- // Set the new parent to this node ...
+ // Now add the child ...
+ if (parent.childrenByName == cache.NO_CHILDREN) {
+ parent.childrenByName = Multimaps.newLinkedListMultimap();
+ }
+ parent.childrenByName.put(newNodeName, child);
child.parent = parent;
+ parent.markAsChanged();
// Update the new child with the correct location ...
- Path.Segment segment = cache.pathFactory.createSegment(childName, currentChildren.size());
+ int snsIndex = parent.childrenByName.get(newNodeName).size();
+ Path.Segment segment = cache.pathFactory.createSegment(newNodeName, snsIndex);
child.updateLocation(segment);
+ cache.recordMove(child, oldParent, parent);
+
+ cache.nodeOperations.postMove(child, oldParent);
}
/**
+ * Rename this node to have a different name.
+ *
+ * @param newNodeName
+ */
+ public void rename( Name newNodeName ) {
+ moveTo(this.parent, newNodeName, true);
+ }
+
+ /**
* Copy this node (and all nodes below it) and place the copy under the supplied parent location. The new copy will be
* appended to any existing children of the supplied parent node, and will be given the appropriate same-name-sibling
- * index.
+ * index. This method may not be called on the root node.
*
* @param parent the new parent for the new copy; may not be null
* @throws RepositorySourceException if the parent node is to be loaded but a problem is encountered while doing so
- * @throws IllegalArgumentException if this is the root node
+ * @throws IllegalArgumentException if the parent is null, or if this is the root node
+ * @throws AccessControlException if the caller does not have the permission to perform the operation
*/
public void copyTo( Node<Payload, PropertyPayload> parent ) {
+ CheckArg.isNotNull(parent, "parent");
+ CheckArg.isEquals(this.isRoot(), "this.isRoot()", false, "false");
final Node<Payload, PropertyPayload> child = this;
assert !parent.isStale();
assert child.parent != this;
@@ -1450,17 +1939,24 @@
if (parent.childrenByName == cache.NO_CHILDREN) {
parent.childrenByName = Multimaps.newLinkedListMultimap();
}
+
+ cache.nodeOperations.preCopy(this, parent);
+
Name childName = child.getName();
// Figure out the name and SNS of the new copy ...
List<Node<Payload, PropertyPayload>> currentChildren = parent.childrenByName.get(childName);
- Location copyLocation = Location.create(cache.pathFactory.create(parent.getPath(), childName, currentChildren.size()));
+ Location copyLocation = Location.create(cache.pathFactory.create(parent.getPath(),
+ childName,
+ currentChildren.size() + 1));
// Perform the copy ...
cache.operations.copy(child.getLocation()).to(copyLocation);
// Add the child to the parent ...
- cache.createNode(parent, cache.idFactory.create(), copyLocation);
- parent.markAsChanged();
+ Node<Payload, PropertyPayload> copy = cache.createNode(parent, cache.idFactory.create(), copyLocation);
+ copy.markAsCopied(); // marks parent as changed
+
+ cache.nodeOperations.postCopy(this, copy);
}
/**
@@ -1477,6 +1973,68 @@
}
/**
+ * Move the specified child to be located immediately before the other supplied node.
+ *
+ * @param childToBeMoved the path segment specifying the child that is to be moved
+ * @param before the path segment of the node before which the {@code childToBeMoved} should be placed, or null if the
+ * child should be moved to the end
+ * @throws PathNotFoundException if the <code>childToBeMoved</code> or <code>before</code> segments do not specify an
+ * existing child
+ * @throws IllegalArgumentException if either segment is null or does not specify an existing node
+ */
+ public void orderChildBefore( Path.Segment childToBeMoved,
+ Path.Segment before ) throws PathNotFoundException {
+ CheckArg.isNotNull(childToBeMoved, "childToBeMoved");
+
+ // Check authorization ...
+ cache.authorizer.checkPermissions(getPath(), Action.REMOVE);
+ cache.authorizer.checkPermissions(getPath(), Action.ADD_NODE);
+
+ // Find the node to be moved ...
+ Node<Payload, PropertyPayload> nodeToBeMoved = getChild(childToBeMoved);
+ Node<Payload, PropertyPayload> beforeNode = before != null ? getChild(before) : null;
+
+ if (beforeNode == null) {
+ // Moving the node into its parent will remove it from its current spot in the child list and re-add it to the end
+ cache.operations.move(nodeToBeMoved.getLocation()).into(this.location);
+ } else {
+ // Record the move ...
+ cache.operations.move(nodeToBeMoved.getLocation()).before(beforeNode.getLocation());
+ }
+
+ // Unfortunately, there is no efficient way to insert into the multi-map, so we need to recreate it ...
+ ListMultimap<Name, Node<Payload, PropertyPayload>> children = Multimaps.newLinkedListMultimap();
+ for (Node<Payload, PropertyPayload> child : childrenByName.values()) {
+ if (child == nodeToBeMoved) continue;
+ if (before != null && child.getSegment().equals(before)) {
+ children.put(nodeToBeMoved.getName(), nodeToBeMoved);
+ }
+ children.put(child.getName(), child);
+ }
+ if (before == null) {
+ children.put(nodeToBeMoved.getName(), nodeToBeMoved);
+ }
+
+ // Replace the children ...
+ this.childrenByName = children;
+ this.markAsChanged();
+
+ // Adjust the SNS indexes for those children with the same name as 'childToBeMoved' ...
+ Name movedName = nodeToBeMoved.getName();
+ List<Node<Payload, PropertyPayload>> childrenWithName = childrenByName.get(movedName);
+ int snsIndex = 1;
+ for (Node<Payload, PropertyPayload> sns : childrenWithName) {
+ if (sns.getSegment().getIndex() != snsIndex) {
+ // The SNS index is not correct, so fix it and update the location ...
+ Path.Segment newSegment = cache.pathFactory.createSegment(movedName, snsIndex);
+ sns.updateLocation(newSegment);
+ sns.markAsChanged();
+ }
+ ++snsIndex;
+ }
+ }
+
+ /**
* Remove this node from it's parent. Note that locations are <i>not</i> updated, since they will be updated if this node
* is added to a different parent. However, the locations of same-name-siblings under the parent <i>are</i> updated.
*/
@@ -1487,6 +2045,7 @@
assert this.parent.childrenByName != null;
assert this.parent.childrenByName != cache.NO_CHILDREN;
this.parent.markAsChanged();
+ this.markAsChanged();
Name name = getName();
List<Node<Payload, PropertyPayload>> childrenWithSameName = this.parent.childrenByName.get(name);
this.parent = null;
@@ -1514,15 +2073,21 @@
/**
* Remove this node from it's parent and destroy it's contents. The location of sibling nodes with the same name will be
* updated, and the node and all nodes below it will be destroyed and removed from the cache.
+ *
+ * @throws AccessControlException if the caller does not have the permission to perform the operation
*/
public void destroy() {
assert !isStale();
// Check authorization ...
cache.authorizer.checkPermissions(getPath(), Action.REMOVE);
+
+ final Node<Payload, PropertyPayload> parent = this.parent;
+ cache.nodeOperations.preRemoveChild(parent, this);
// Remove the node from its parent ...
remove();
// This node was successfully removed, so now remove it from the cache ...
cache.recordDelete(this);
+ cache.nodeOperations.postRemoveChild(parent, this);
}
public final boolean isRoot() {
@@ -1549,7 +2114,7 @@
*
* @return the parent node
*/
- public final Node<Payload, PropertyPayload> getParent() {
+ public Node<Payload, PropertyPayload> getParent() {
assert !isStale();
return parent;
}
@@ -1566,7 +2131,7 @@
*
* @return the name; never null
*/
- public final Name getName() {
+ public Name getName() {
return location.getPath().getLastSegment().getName();
}
@@ -1598,6 +2163,161 @@
}
/**
+ * Create a new child node with the supplied name. The same-name-sibling index will be determined based upon the existing
+ * children.
+ *
+ * @param name the name of the new child node
+ * @return the new child node
+ * @throws IllegalArgumentException if the name is null
+ * @throws RepositorySourceException if this node must be loaded but doing so results in a problem
+ */
+ public Node<Payload, PropertyPayload> createChild( Name name ) {
+ CheckArg.isNotNull(name, "name");
+ return doCreateChild(name, null, null);
+ }
+
+ /**
+ * Create a new child node with the supplied name and one initial property. The same-name-sibling index will be determined
+ * based upon the existing children.
+ *
+ * @param name the name of the new child node
+ * @param property a property for the new node
+ * @return the new child node
+ * @throws IllegalArgumentException if the name or identification property is null
+ * @throws RepositorySourceException if this node must be loaded but doing so results in a problem
+ */
+ public Node<Payload, PropertyPayload> createChild( Name name,
+ Property property ) {
+ CheckArg.isNotNull(name, "name");
+ CheckArg.isNotNull(property, "property");
+ return doCreateChild(name, property, null);
+ }
+
+ /**
+ * Create a new child node with the supplied name and multiple initial properties. The same-name-sibling index will be
+ * determined based upon the existing children.
+ *
+ * @param name the name of the new child node
+ * @param firstProperty the first identification property for the new node
+ * @param remainingProperties the remaining identification properties for the new node
+ * @return the new child node
+ * @throws IllegalArgumentException if the name or properties are null
+ * @throws ValidationException if the new node is not valid as a child
+ * @throws RepositorySourceException if this node must be loaded but doing so results in a problem
+ */
+ public Node<Payload, PropertyPayload> createChild( Name name,
+ Property firstProperty,
+ Property... remainingProperties ) {
+ CheckArg.isNotNull(name, "name");
+ CheckArg.isNotNull(firstProperty, "firstProperty");
+ return doCreateChild(name, firstProperty, remainingProperties);
+ }
+
+ private Node<Payload, PropertyPayload> doCreateChild( Name name,
+ Property firstProperty,
+ Property[] remainingProperties ) throws ValidationException {
+ assert !isStale();
+
+ // Check permission here ...
+ Path path = getPath();
+ cache.authorizer.checkPermissions(path, Action.ADD_NODE);
+
+ // Now load if required ...
+ load();
+
+ // Figure out the name and SNS of the new copy ...
+ List<Node<Payload, PropertyPayload>> currentChildren = childrenByName.get(name);
+ Path newPath = cache.pathFactory.create(path, name, currentChildren.size() + 1);
+ Location newChild = Location.create(newPath);
+
+ // Create the properties ...
+ Map<Name, PropertyInfo<PropertyPayload>> newProperties = new HashMap<Name, PropertyInfo<PropertyPayload>>();
+ if (firstProperty != null) {
+ PropertyInfo<PropertyPayload> info = new PropertyInfo<PropertyPayload>(firstProperty, firstProperty.isMultiple(),
+ Status.NEW, null);
+ newProperties.put(info.getName(), info);
+ if (remainingProperties != null) {
+ for (Property property : remainingProperties) {
+ PropertyInfo<PropertyPayload> info2 = new PropertyInfo<PropertyPayload>(property, property.isMultiple(),
+ Status.NEW, null);
+ newProperties.put(info2.getName(), info2);
+ }
+ }
+ }
+
+ // Notify before the addition ...
+ cache.nodeOperations.preCreateChild(this, newPath.getLastSegment(), newProperties);
+
+ // Record the current state before any changes ...
+ Status statusBefore = this.status;
+ boolean changedBelowBefore = this.changedBelow;
+
+ // Add the child to the parent ...
+ Node<Payload, PropertyPayload> child = cache.createNode(this, cache.idFactory.create(), newChild);
+ child.markAsNew(); // marks parent as changed
+ if (childrenByName == cache.NO_CHILDREN) {
+ childrenByName = Multimaps.newLinkedListMultimap();
+ }
+ childrenByName.put(name, child);
+
+ // Set the properties on the new node, but in a private backdoor way ...
+ assert child.properties == null;
+ child.properties = newProperties;
+
+ try {
+ // The node has been changed, so try notifying before we record the creation (which can't be undone) ...
+ cache.nodeOperations.postCreateChild(this, child, child.properties);
+
+ // Notification was fine, so now do the create ...
+ Graph.Create<Graph.Batch> create = cache.operations.create(newChild.getPath());
+ if (!child.properties.isEmpty()) {
+ // Process the property infos (in case some were added during the pre- or post- operations ...
+ for (PropertyInfo<PropertyPayload> property : child.properties.values()) {
+ create.with(property.getProperty());
+ }
+ }
+ create.and();
+ } catch (ValidationException e) {
+ // Clean up the children ...
+ if (childrenByName.size() == 1) {
+ childrenByName = cache.NO_CHILDREN;
+ } else {
+ childrenByName.remove(child.getName(), child);
+ }
+ this.status = statusBefore;
+ this.changedBelow = changedBelowBefore;
+ throw e;
+ }
+ return child;
+ }
+
+ /**
+ * Determine whether this node has a child with the supplied name and SNS index.
+ *
+ * @param segment the segment of the child
+ * @return true if there is a child, or false if there is no such child
+ * @throws RepositorySourceException if there is a problem loading this node's information from the store
+ */
+ public boolean hasChild( Path.Segment segment ) {
+ return hasChild(segment.getName(), segment.getIndex());
+ }
+
+ /**
+ * Determine whether this node has a child with the supplied name and SNS index.
+ *
+ * @param name the name of the child
+ * @param sns the same-name-sibling index; must be 1 or more
+ * @return true if there is a child, or false if there is no such child
+ * @throws RepositorySourceException if there is a problem loading this node's information from the store
+ */
+ public boolean hasChild( Name name,
+ int sns ) {
+ load();
+ List<Node<Payload, PropertyPayload>> children = childrenByName.get(name); // never null
+ return children.size() >= sns; // SNS is 1-based, index is 0-based
+ }
+
+ /**
* Get the child with the supplied segment.
*
* @param segment the segment of the child
@@ -1727,28 +2447,34 @@
* @param isMultiValued true if the property is multi-valued
* @param payload the optional payload for this property; may be null
* @return the previous information for the property, or null if there was no previous property
+ * @throws AccessControlException if the caller does not have the permission to perform the operation
*/
public PropertyInfo<PropertyPayload> setProperty( Property property,
boolean isMultiValued,
PropertyPayload payload ) {
+ assert !isStale();
+ cache.authorizer.checkPermissions(getPath(), Action.SET_PROPERTY);
+
load();
- cache.authorizer.checkPermissions(getPath(), Action.SET_PROPERTY);
+ if (properties == cache.NO_PROPERTIES) {
+ properties = new HashMap<Name, PropertyInfo<PropertyPayload>>();
+ }
+
Name name = property.getName();
PropertyInfo<PropertyPayload> previous = properties.get(name);
- PropertyId id = null;
- PropertyStatus status = null;
+ Status status = null;
if (previous != null) {
- id = previous.getPropertyId();
status = previous.getStatus(); // keep NEW or CHANGED status, but UNCHANGED -> CHANGED
- if (status == PropertyStatus.UNCHANGED) status = PropertyStatus.CHANGED;
+ if (status == Status.UNCHANGED) status = Status.CHANGED;
} else {
- id = new PropertyId(getNodeId(), name);
- status = PropertyStatus.NEW;
+ status = Status.NEW;
}
- PropertyInfo<PropertyPayload> info = new PropertyInfo<PropertyPayload>(id, property, isMultiValued, status, payload);
+ PropertyInfo<PropertyPayload> info = new PropertyInfo<PropertyPayload>(property, isMultiValued, status, payload);
+ cache.nodeOperations.preSetProperty(this, property.getName(), info);
properties.put(name, info);
cache.operations.set(property).on(location);
markAsChanged();
+ cache.nodeOperations.postSetProperty(this, property.getName(), previous);
return previous;
}
@@ -1759,10 +2485,16 @@
* @return the previous information for the property, or null if there was no previous property
*/
public PropertyInfo<PropertyPayload> removeProperty( Name name ) {
+ assert !isStale();
+ cache.authorizer.checkPermissions(getPath(), Action.REMOVE);
+
load();
+ if (!properties.containsKey(name)) return null;
+ cache.nodeOperations.preRemoveProperty(this, name);
PropertyInfo<PropertyPayload> results = properties.remove(name);
markAsChanged();
cache.operations.remove(name).on(location);
+ cache.nodeOperations.postRemoveProperty(this, name, results);
return results;
}
@@ -1809,6 +2541,7 @@
* @return payload
*/
public Payload getPayload() {
+ load();
return payload;
}
@@ -1840,6 +2573,7 @@
if (obj == this) return true;
if (obj instanceof Node) {
Node<Payload, PropertyPayload> that = (Node<Payload, PropertyPayload>)obj;
+ if (this.isStale() || that.isStale()) return false;
if (!this.nodeId.equals(that.nodeId)) return false;
return this.location.equals(that.location);
}
@@ -1938,10 +2672,10 @@
Node<Payload, PropertyPayload> node = changedNodes.poll();
// Visit this node ...
boolean visitChildren = true;
- if (node.changed) {
+ if (node.isChanged(false)) {
visitChildren = visitor.visit(node);
}
- if (visitChildren && node.changedBelow) {
+ if (visitChildren && node.isChanged(true)) {
// Visit the children ...
int index = -1;
Iterator<Node<Payload, PropertyPayload>> iter = node.getChildren().iterator();
@@ -1977,29 +2711,26 @@
}
}
- public static enum PropertyStatus {
+ public static enum Status {
NEW,
CHANGED,
- UNCHANGED;
+ UNCHANGED,
+ COPIED;
}
@Immutable
public static final class PropertyInfo<PropertyPayload> {
- private final PropertyId propertyId;
private final Property property;
- private final PropertyStatus status;
+ private final Status status;
private final boolean multiValued;
private final PropertyPayload payload;
- protected PropertyInfo( PropertyId propertyId,
- Property property,
- boolean multiValued,
- PropertyStatus status,
- PropertyPayload payload ) {
- assert propertyId != null;
+ public PropertyInfo( Property property,
+ boolean multiValued,
+ Status status,
+ PropertyPayload payload ) {
assert property != null;
assert status != null;
- this.propertyId = propertyId;
this.property = property;
this.status = status;
this.multiValued = multiValued;
@@ -2011,17 +2742,35 @@
*
* @return the current status; never null
*/
- public PropertyStatus getStatus() {
+ public Status getStatus() {
return status;
}
/**
+ * Determine whether this property has been modified since it was last saved.
+ *
+ * @return true if the {@link #getStatus() status} is {@link Status#CHANGED changed}
+ */
+ public boolean isModified() {
+ return status != Status.UNCHANGED && status != Status.NEW;
+ }
+
+ /**
+ * Determine whether this property has been created since the last save.
+ *
+ * @return true if the {@link #getStatus() status} is {@link Status#NEW new}
+ */
+ public boolean isNew() {
+ return status == Status.NEW;
+ }
+
+ /**
* Get the name of the property.
*
* @return the propert name; never null
*/
public Name getName() {
- return propertyId.getPropertyName();
+ return property.getName();
}
/**
@@ -2034,15 +2783,6 @@
}
/**
- * Get the identifier for this property.
- *
- * @return the property identifier; never null
- */
- public PropertyId getPropertyId() {
- return propertyId;
- }
-
- /**
* Get the payload for this property.
*
* @return the payload; may be null if there is no payload
@@ -2067,7 +2807,7 @@
*/
@Override
public int hashCode() {
- return propertyId.hashCode();
+ return getName().hashCode();
}
/**
@@ -2080,7 +2820,7 @@
if (obj == this) return true;
if (obj instanceof PropertyInfo) {
PropertyInfo<?> that = (PropertyInfo<?>)obj;
- return propertyId.equals(that.getPropertyId());
+ return getName().equals(that.getName());
}
return false;
}
@@ -2093,7 +2833,7 @@
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
- sb.append(propertyId);
+ sb.append(getName());
if (payload != null) sb.append(payload);
if (property.isSingle()) {
sb.append(" with value ");
@@ -2148,7 +2888,7 @@
* @param node the node that should be loaded (if it is not already)
*/
protected void load( Node<Payload, PropertyPayload> node ) {
- if (node != null && !node.isLoaded()) {
+ if (node != null && !node.isLoaded() && !node.isNew()) {
nodesToLoad.add(node);
batch.read(node.getLocation());
}
@@ -2168,7 +2908,7 @@
// Now load all of the children into the correct node ...
for (Node<Payload, PropertyPayload> childToBeRead : nodesToLoad) {
org.jboss.dna.graph.Node persistentNode = results.getNode(childToBeRead.getLocation());
- nodeOperations.update(persistentNode, childToBeRead);
+ nodeOperations.materialize(persistentNode, childToBeRead);
finishNodeAfterLoading(childToBeRead);
}
}
@@ -2488,75 +3228,4 @@
}
}
- /**
- * An immutable identifier for a property on a node, used within the {@link GraphSession}.
- */
- @Immutable
- public final static class PropertyId {
- private final NodeId nodeId;
- private final Name propertyName;
- private final int hc;
-
- public PropertyId( NodeId nodeId,
- Name propertyName ) {
- this.nodeId = nodeId;
- this.propertyName = propertyName;
- this.hc = HashCode.compute(this.nodeId, this.propertyName);
- }
-
- /**
- * Get the identifier of the node on which the property exists.
- *
- * @return the node identifier; never null
- */
- public NodeId getNodeId() {
- return nodeId;
- }
-
- /**
- * Get the name of the property.
- *
- * @return the property name; never null
- */
- public Name getPropertyName() {
- return propertyName;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see java.lang.Object#hashCode()
- */
- @Override
- public int hashCode() {
- return hc;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see java.lang.Object#equals(java.lang.Object)
- */
- @Override
- public boolean equals( Object obj ) {
- if (obj == this) return true;
- if (obj instanceof PropertyId) {
- PropertyId that = (PropertyId)obj;
- if (this.hc != that.hc) return false;
- if (!this.nodeId.equals(that.nodeId)) return false;
- return this.propertyName.equals(that.propertyName);
- }
- return false;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see java.lang.Object#toString()
- */
- @Override
- public String toString() {
- return this.nodeId.toString() + '@' + this.propertyName.toString();
- }
- }
}
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-07-09 16:23:09 UTC (rev 1081)
+++ trunk/dna-graph/src/main/resources/org/jboss/dna/graph/GraphI18n.properties 2009-07-09 16:26:04 UTC (rev 1082)
@@ -111,4 +111,7 @@
# Session
unableToRefreshBranchBecauseChangesDependOnChangesToNodesOutsideOfBranch = Unable to refresh "{0}" in workspace "{1}" because it contains changes that depend on changes to nodes outside of this branch
unableToSaveBranchBecauseChangesDependOnChangesToNodesOutsideOfBranch = Unable to save "{0}" in workspace "{1}" because it contains changes that depend on changes to nodes outside of this branch
+unableToSaveNodeThatWasCreatedSincePreviousSave = Unable to save node "{0}" in workspace "{1}" because it was created since the last save
nodeHasAlreadyBeenRemovedFromThisSession = Node "{0}" in workspace "{1} has already been removed from this session
+unableToMoveNodeToBeChildOfDecendent = Node "{0}" in workspace "{2}" cannot be moved under a decendant node ("{1}")
+childNotFound = Child "{0}" could not be found under "{1}" in workspace "{2}"
Deleted: trunk/dna-graph/src/test/java/org/jboss/dna/graph/session/GraphCacheTest.java
===================================================================
--- trunk/dna-graph/src/test/java/org/jboss/dna/graph/session/GraphCacheTest.java 2009-07-09 16:23:09 UTC (rev 1081)
+++ trunk/dna-graph/src/test/java/org/jboss/dna/graph/session/GraphCacheTest.java 2009-07-09 16:26:04 UTC (rev 1082)
@@ -1,574 +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.graph.session;
-
-import static org.hamcrest.core.Is.is;
-import static org.hamcrest.core.IsNot.not;
-import static org.hamcrest.core.IsNull.notNullValue;
-import static org.hamcrest.core.IsSame.sameInstance;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.fail;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-import org.jboss.dna.graph.ExecutionContext;
-import org.jboss.dna.graph.Graph;
-import org.jboss.dna.graph.connector.RepositoryConnection;
-import org.jboss.dna.graph.connector.RepositoryConnectionFactory;
-import org.jboss.dna.graph.connector.RepositorySourceException;
-import org.jboss.dna.graph.connector.inmemory.InMemoryRepositorySource;
-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.session.GraphSession.Node;
-import org.jboss.dna.graph.session.GraphSession.Operations;
-import org.junit.Before;
-import org.junit.Test;
-
-/**
- *
- */
-public class GraphCacheTest {
-
- protected ExecutionContext context;
- protected InMemoryRepositorySource source;
- private Graph store;
- private GraphSession<Object, Object> cache;
- private PathFactory pathFactory;
- protected int numberOfConnections;
-
- @Before
- public void beforeEach() throws Exception {
- context = new ExecutionContext();
- pathFactory = context.getValueFactories().getPathFactory();
- source = new InMemoryRepositorySource();
- source.setName("store");
- // Use a connection factory so we can count the number of connections that were made
- RepositoryConnectionFactory connectionFactory = new RepositoryConnectionFactory() {
- public RepositoryConnection createConnection( String sourceName ) throws RepositorySourceException {
- if (source.getName().equals(sourceName)) {
- ++numberOfConnections;
- return source.getConnection();
- }
- return null;
- }
- };
- store = Graph.create(source.getName(), connectionFactory, context);
-
- // Load the store with content ...
- store.importXmlFrom(getClass().getClassLoader().getResourceAsStream("cars.xml")).into("/");
- numberOfConnections = 0; // reset the number of connections
-
- Operations<Object, Object> nodeOps = null; // use default
- String workspaceName = null; // use current
- cache = new GraphSession<Object, Object>(store, workspaceName, nodeOps);
- }
-
- @Test
- public void shouldHaveRootNodeWithCorrectNodeIdAndLocation() {
- Node<Object, Object> node = cache.getRoot();
- assertThat(node, is(notNullValue()));
- assertThat(node.getNodeId(), is(notNullValue()));
- assertThat(node.getLocation(), is(notNullValue()));
- assertNoMoreConnectionsUsed();
- assertNoChanges();
- }
-
- @Test
- public void shouldNotHaveAutomaticallyLoadedRootNode() {
- assertThat(cache.getRoot().isLoaded(), is(false));
- assertNoMoreConnectionsUsed();
- assertNoChanges();
- }
-
- @Test
- public void shouldHaveRootNodeWithChildren() {
- Node<Object, Object> node = cache.getRoot();
- assertChildren(node, "Cars");
- assertConnectionsUsed(1);
- assertNoChanges();
- }
-
- @Test
- public void shouldHaveNoExpirationIfSourceDoesNotHaveCachePolicy() {
- Node<Object, Object> node = cache.getRoot();
- node.load();
- assertThat(node.getExpirationTimeInMillis(), is(Long.MAX_VALUE));
- assertConnectionsUsed(1);
- assertNoChanges();
- }
-
- @Test
- public void shouldAutomaticallyLoadNodesWhenNavigatingToChildren() {
- Node<Object, Object> root = cache.getRoot();
- assertThat(root.isLoaded(), is(false));
- assertChildren(root, "Cars"); // causes loading of the root node
- assertThat(root.isLoaded(), is(true));
- assertConnectionsUsed(1);
-
- Node<Object, Object> cars = root.getChildren().iterator().next(); // only one child
- assertThat(cars.isLoaded(), is(false));
- assertChildren(cars, "Hybrid", "Sports", "Luxury", "Utility");
- assertConnectionsUsed(1);
- assertThat(cars.isLoaded(), is(true));
- assertThat(cars.getParent(), is(sameInstance(root)));
-
- Node<Object, Object> sports = cars.getChild(segment("Sports"));
- assertThat(sports.isLoaded(), is(false));
- assertChildren(sports, "Aston Martin DB9", "Infiniti G37");
- assertConnectionsUsed(1);
- assertThat(sports.isLoaded(), is(true));
- assertThat(sports.getParent(), is(sameInstance(cars)));
-
- Node<Object, Object> g37 = sports.getChild(segment("Infiniti G37"));
- assertThat(g37.isLoaded(), is(false));
- assertChildren(g37);
- assertConnectionsUsed(1);
- assertThat(g37.isLoaded(), is(true));
- assertThat(g37.isLeaf(), is(true));
- assertThat(g37.getParent(), is(sameInstance(sports)));
-
- // Try another branch ...
- Node<Object, Object> utility = cars.getChild(segment("Utility"));
- assertThat(utility.isLoaded(), is(false));
- assertChildren(utility, "Land Rover LR2", "Land Rover LR3", "Hummer H3", "Ford F-150");
- assertConnectionsUsed(1);
- assertThat(utility.isLoaded(), is(true));
- assertThat(utility.getParent(), is(sameInstance(cars)));
-
- Node<Object, Object> lr3 = utility.getChild(segment("Land Rover LR3"));
- assertThat(lr3.isLoaded(), is(false));
- assertChildren(lr3);
- assertConnectionsUsed(1);
- assertThat(lr3.isLoaded(), is(true));
- assertThat(lr3.isLeaf(), is(true));
- assertThat(lr3.getParent(), is(sameInstance(utility)));
-
- assertNoMoreConnectionsUsed();
- assertNoChanges();
- }
-
- @Test
- public void shouldFindNodesByPath() {
- Node<Object, Object> g37 = cache.findNodeWith(path("/Cars/Sports/Infiniti G37")); // loads the node and all parents
- assertConnectionsUsed(1);
- assertThat(g37.isLoaded(), is(true));
- assertChildren(g37);
- assertThat(g37.isLoaded(), is(true));
- assertThat(g37.isLeaf(), is(true));
-
- Node<Object, Object> sports = g37.getParent();
- assertThat(sports.isLoaded(), is(true));
- assertChildren(sports, "Aston Martin DB9", "Infiniti G37");
-
- Node<Object, Object> cars = sports.getParent();
- assertThat(cars.isLoaded(), is(true));
- assertChildren(cars, "Hybrid", "Sports", "Luxury", "Utility");
-
- Node<Object, Object> root = cars.getParent();
- assertThat(root, is(sameInstance(cache.getRoot())));
- assertThat(root.isLoaded(), is(true));
- assertChildren(root, "Cars"); // causes loading of the root node
-
- assertNoMoreConnectionsUsed();
-
- // Try another branch that should not be loaded...
- Node<Object, Object> utility = cars.getChild(segment("Utility"));
- assertThat(utility.isLoaded(), is(false));
- assertChildren(utility, "Land Rover LR2", "Land Rover LR3", "Hummer H3", "Ford F-150");
- assertConnectionsUsed(1);
- assertThat(utility.isLoaded(), is(true));
- assertThat(utility.getParent(), is(sameInstance(cars)));
-
- assertNoMoreConnectionsUsed();
- assertNoChanges();
- }
-
- @Test
- public void shouldFindNodesById() {
- cache.findNodeWith(path("/Cars/Sports/Infiniti G37")); // loads the node and all parents
- assertConnectionsUsed(1); // "Utility" was found because it is child of "Cars" loaded when "Sports" was loaded
-
- cache.getRoot().onCachedNodes(new GraphSession.NodeVisitor<Object, Object>() {
- @SuppressWarnings( "synthetic-access" )
- @Override
- public boolean visit( Node<Object, Object> node ) {
- assertThat(cache.findNodeWith(node.getNodeId(), null), is(sameInstance(node)));
- return true;
- }
- });
- }
-
- @Test
- public void shouldFindNodesByLocation() {
- cache.findNodeWith(path("/Cars/Sports/Infiniti G37")); // loads the node and all parents
- assertConnectionsUsed(1); // "Utility" was found because it is child of "Cars" loaded when "Sports" was loaded
-
- cache.getRoot().onCachedNodes(new GraphSession.NodeVisitor<Object, Object>() {
- @SuppressWarnings( "synthetic-access" )
- @Override
- public boolean visit( Node<Object, Object> node ) {
- assertThat(cache.findNodeWith(null, node.getLocation().getPath()), is(sameInstance(node)));
- return true;
- }
- });
- }
-
- @Test
- public void shouldFindNodesByIdAfterClearing() {
- Node<Object, Object> g37 = cache.findNodeWith(path("/Cars/Sports/Infiniti G37")); // loads the node and all parents
- assertConnectionsUsed(1);
- assertThat(g37.isLoaded(), is(true));
- assertChildren(g37);
- assertThat(g37.isLoaded(), is(true));
- assertThat(g37.isLeaf(), is(true));
-
- Node<Object, Object> sports = g37.getParent();
- Node<Object, Object> cars = sports.getParent();
- Node<Object, Object> root = cars.getParent();
-
- assertNoMoreConnectionsUsed();
-
- cache.getRoot().unload();
-
- Node<Object, Object> g37_b = cache.findNodeWith(g37.getNodeId(), g37.getPath());
- assertConnectionsUsed(1);
-
- Node<Object, Object> sports_b = g37_b.getParent();
- Node<Object, Object> cars_b = sports_b.getParent();
- Node<Object, Object> root_b = cars_b.getParent();
- assertThat(g37_b, is(not(sameInstance(g37))));
- assertThat(sports_b, is(not(sameInstance(sports))));
- assertThat(cars_b, is(not(sameInstance(cars))));
- assertThat(root_b, is(sameInstance(root)));
- assertThat(g37_b.isLeaf(), is(true));
- assertChildren(sports_b, "Aston Martin DB9", "Infiniti G37");
- assertChildren(cars_b, "Hybrid", "Sports", "Luxury", "Utility");
- assertChildren(root_b, "Cars");
-
- assertNoMoreConnectionsUsed();
- assertNoChanges();
- }
-
- @Test
- public void shouldMoveBranchAndRefresh() {
- Node<Object, Object> sports = cache.findNodeWith(path("/Cars/Sports"));
- Node<Object, Object> utility = cache.findNodeWith(path("/Cars/Utility"));
- assertConnectionsUsed(1); // "Utility" was found because it is child of "Cars" loaded when "Sports" was loaded
-
- sports.moveTo(utility);
- assertConnectionsUsed(1); // "Utility" was not fully loaded before
- assertNoMoreConnectionsUsed();
-
- Node<Object, Object> cars = cache.findNodeWith(path("/Cars"));
-
- for (int i = 0; i != 3; ++i) {
- assertChildren(cars, "Hybrid", "Luxury", "Utility");
- assertChildren(utility, "Land Rover LR2", "Land Rover LR3", "Hummer H3", "Ford F-150", "Sports");
- assertThat(sports.getParent(), is(utility));
- assertThat(utility.getParent(), is(cars));
-
- // Ensure that the changes were recorded appropriately ...
- assertThat(cars.isChanged(false), is(true));
- assertThat(sports.isChanged(false), is(false));
- assertThat(utility.isChanged(false), is(true));
- assertThat(cache.hasPendingChanges(), is(true));
- assertThat(cache.changeDependencies.size(), is(1));
- assertThat(cache.changeDependencies.get(sports.getNodeId()).getMovedFrom(), is(cars.getNodeId()));
- assertThat(cache.operations.isExecuteRequired(), is(true));
-
- if (i == 0) {
- // 1st time: Refreshing "Utility" shouldn't work because "/Cars" was involved in the same move ...
- try {
- cache.refresh(utility, false);
- fail("Expected exception from the call to refresh");
- } catch (InvalidStateException e) {
- // expected ...
- }
- } else if (i == 1) {
- // 2nd time: refresh "/Cars" but keep the changes ...
- cache.refresh(cars, true);
- } else if (i == 2) {
- // 3rd time:
- cache.refresh(cars, false);
- }
- }
-
- // Now the state should be back to the original representation, but we need to refind the nodes ...
- sports = cache.findNodeWith(path("/Cars/Sports"));
- utility = cache.findNodeWith(path("/Cars/Utility"));
- cars = cache.findNodeWith(path("/Cars"));
-
- assertChildren(cars, "Hybrid", "Sports", "Luxury", "Utility");
- assertChildren(utility, "Land Rover LR2", "Land Rover LR3", "Hummer H3", "Ford F-150");
- assertThat(sports.getParent(), is(cars));
- assertThat(utility.getParent(), is(cars));
-
- // Now there should be no changes ...
- assertNoChanges();
- System.out.println(cache.root.getSnapshot(false));
- }
-
- @Test
- public void shouldMoveBranchAndSaveBranch() {
- Node<Object, Object> sports = cache.findNodeWith(path("/Cars/Sports"));
- Node<Object, Object> utility = cache.findNodeWith(path("/Cars/Utility"));
- assertConnectionsUsed(1); // "Utility" was found because it is child of "Cars" loaded when "Sports" was loaded
-
- sports.moveTo(utility);
- assertConnectionsUsed(1); // "Utility" was not fully loaded before
- assertNoMoreConnectionsUsed();
-
- Node<Object, Object> cars = cache.findNodeWith(path("/Cars"));
- Node<Object, Object> root = cache.getRoot();
-
- for (int i = 0; i != 2; ++i) {
- assertChildren(cars, "Hybrid", "Luxury", "Utility");
- assertChildren(utility, "Land Rover LR2", "Land Rover LR3", "Hummer H3", "Ford F-150", "Sports");
- assertThat(sports.getParent(), is(utility));
- assertThat(utility.getParent(), is(cars));
-
- // Ensure that the changes were recorded appropriately ...
- assertThat(cars.isChanged(false), is(true));
- assertThat(sports.isChanged(false), is(false));
- assertThat(utility.isChanged(false), is(true));
- assertThat(cache.hasPendingChanges(), is(true));
- assertThat(cache.changeDependencies.size(), is(1));
- assertThat(cache.changeDependencies.get(sports.getNodeId()).getMovedFrom(), is(cars.getNodeId()));
- assertThat(cache.operations.isExecuteRequired(), is(true));
-
- if (i == 0) {
- // 1st time: Saving "Utility" shouldn't work because "/Cars" was involved in the same move ...
- try {
- cache.save(utility);
- fail("Expected exception from the call to save");
- } catch (InvalidStateException e) {
- // expected ...
- }
- } else if (i == 1) {
- // 2nd time: Save "/Cars" but keep the changes ...
- assertConnectionsUsed(0);
- cache.save(cars);
- assertConnectionsUsed(2); // 1 to load children required by validation, 1 to perform save
- }
- // i=2 do nothing
- }
-
- // The affected nodes should now be stale ...
- assertThat(sports.isStale(), is(true));
- assertThat(utility.isStale(), is(true));
- assertThat(cars.isStale(), is(false)); // not stale because it was unloaded
- assertThat(cars.isLoaded(), is(false));
- assertThat(root.isStale(), is(false)); // not touched during saves
-
- // Now the state should reflect our changes, but we need to refind the nodes ...
- sports = cache.findNodeWith(path("/Cars/Utility/Sports"));
- assertConnectionsUsed(1);
- utility = cache.findNodeWith(path("/Cars/Utility"));
- assertNoMoreConnectionsUsed();
-
- assertChildren(cars, "Hybrid", "Luxury", "Utility");
- assertChildren(utility, "Land Rover LR2", "Land Rover LR3", "Hummer H3", "Ford F-150", "Sports");
- assertThat(sports.getParent(), is(utility));
- assertThat(utility.getParent(), is(cars));
-
- // Now there should be no changes ...
- assertNoChanges();
-
- System.out.println(cache.root.getSnapshot(false));
- }
-
- @Test
- public void shouldMoveBranchAndSaveAll() {
- Node<Object, Object> sports = cache.findNodeWith(path("/Cars/Sports"));
- Node<Object, Object> utility = cache.findNodeWith(path("/Cars/Utility"));
- assertConnectionsUsed(1); // "Utility" was found because it is child of "Cars" loaded when "Sports" was loaded
-
- sports.moveTo(utility);
- assertConnectionsUsed(1); // "Utility" was not fully loaded before
- assertNoMoreConnectionsUsed();
-
- Node<Object, Object> cars = cache.findNodeWith(path("/Cars"));
- Node<Object, Object> root = cache.getRoot();
-
- assertChildren(cars, "Hybrid", "Luxury", "Utility");
- assertChildren(utility, "Land Rover LR2", "Land Rover LR3", "Hummer H3", "Ford F-150", "Sports");
- assertThat(sports.getParent(), is(utility));
- assertThat(utility.getParent(), is(cars));
-
- // Ensure that the changes were recorded appropriately ...
- assertThat(cars.isChanged(false), is(true));
- assertThat(sports.isChanged(false), is(false));
- assertThat(utility.isChanged(false), is(true));
- assertThat(cache.hasPendingChanges(), is(true));
- assertThat(cache.changeDependencies.size(), is(1));
- assertThat(cache.changeDependencies.get(sports.getNodeId()).getMovedFrom(), is(cars.getNodeId()));
- assertThat(cache.operations.isExecuteRequired(), is(true));
-
- // Save the changes ...
- assertConnectionsUsed(0);
- cache.save();
- assertConnectionsUsed(2); // 1 to load children required by validation, 1 to perform save
-
- // The affected nodes should now be stale ...
- assertThat(sports.isStale(), is(true));
- assertThat(utility.isStale(), is(true));
- assertThat(cars.isStale(), is(false)); // not stale because it was unloaded
- assertThat(cars.isLoaded(), is(false));
- assertThat(root.isStale(), is(false)); // not touched during saves
-
- // Now the state should reflect our changes, but we need to refind the nodes ...
- sports = cache.findNodeWith(path("/Cars/Utility/Sports"));
- assertConnectionsUsed(1);
- utility = cache.findNodeWith(path("/Cars/Utility"));
- assertNoMoreConnectionsUsed();
-
- assertChildren(cars, "Hybrid", "Luxury", "Utility");
- assertChildren(utility, "Land Rover LR2", "Land Rover LR3", "Hummer H3", "Ford F-150", "Sports");
- assertThat(sports.getParent(), is(utility));
- assertThat(utility.getParent(), is(cars));
-
- // Now there should be no changes ...
- assertNoChanges();
-
- // System.out.println(cache.root.getSnapshot(false));
- }
-
- @Test
- public void shouldLoadSubgraphs() {
- cache.setDepthForLoadingNodes(4);
- Node<Object, Object> cars = cache.findNodeWith(path("/Cars")); // loads the node and all parents
- assertChildren(cars, "Hybrid", "Sports", "Luxury", "Utility");
- assertConnectionsUsed(1);
-
- Node<Object, Object> sports = cache.findNodeWith(path("/Cars/Sports"));
- Node<Object, Object> g37 = cache.findNodeWith(path("/Cars/Sports/Infiniti G37"));
- Node<Object, Object> db9 = cache.findNodeWith(path("/Cars/Sports/Aston Martin DB9"));
- assertConnectionsUsed(0); // should have been loaded with sports subgraph
-
- assertThat(sports.isLoaded(), is(true));
- assertThat(g37.isLoaded(), is(true));
- assertThat(db9.isLoaded(), is(true));
- assertChildren(sports, "Aston Martin DB9", "Infiniti G37");
- assertChildren(g37);
- assertChildren(db9);
-
- assertNoMoreConnectionsUsed();
- assertNoChanges();
- }
-
- @Test
- public void shouldMarkAsChangedWhenSettingProperties() {
- Node<Object, Object> g37 = cache.findNodeWith(path("/Cars/Sports/Infiniti G37"));
- assertThat(g37.isChanged(false), is(false));
-
- // Set the new property ...
- Property newProperty = createProperty("something", "value1");
- g37.setProperty(newProperty, false, null);
- assertThat(g37.isChanged(false), is(true));
- assertThat(cache.getRoot().isChanged(true), is(true));
-
- // Save the changes ...
- cache.save();
- }
-
- @Test
- public void shouldClearPropertyChangesWhenRefreshing() {
- Node<Object, Object> g37 = cache.findNodeWith(path("/Cars/Sports/Infiniti G37"));
- assertThat(g37.isChanged(false), is(false));
-
- // Set the new property ...
- Property newProperty = createProperty("something", "value1");
- g37.setProperty(newProperty, false, null);
- assertThat(g37.isChanged(false), is(true));
- assertThat(cache.getRoot().isChanged(true), is(true));
-
- // Refresh the changes ...
- cache.refresh(g37, false);
-
- assertThat(g37.isChanged(true), is(false));
- assertThat(cache.getRoot().isChanged(true), is(false));
- assertNoChanges();
- }
-
- protected void assertChildren( Node<Object, Object> node,
- String... childNames ) {
- assertThat(node.getChildrenCount(), is(childNames.length));
- List<Path.Segment> segments = new LinkedList<Path.Segment>();
- for (String childName : childNames) {
- segments.add(pathFactory.createSegment(childName));
- }
- Iterator<Path.Segment> expectedIter = segments.iterator();
- Iterator<Node<Object, Object>> actualIter = node.getChildren().iterator();
- while (expectedIter.hasNext() && actualIter.hasNext()) {
- Node<Object, Object> actualNode = actualIter.next();
- Path actualPath = actualNode.getPath();
- Path.Segment actualSegment = actualPath.getLastSegment();
- Path.Segment expectedSegment = expectedIter.next();
- assertThat(actualSegment, is(expectedSegment));
- }
- assertThat(expectedIter.hasNext(), is(false));
- assertThat(actualIter.hasNext(), is(false));
- }
-
- protected Name name( String name ) {
- return context.getValueFactories().getNameFactory().create(name);
- }
-
- protected Path.Segment segment( String segment ) {
- return context.getValueFactories().getPathFactory().createSegment(segment);
- }
-
- protected Path path( String path ) {
- return context.getValueFactories().getPathFactory().create(path);
- }
-
- protected Property createProperty( String name,
- Object... values ) {
- return context.getPropertyFactory().create(name(name), values);
- }
-
- protected void assertChildrenNotLoaded( Node<Object, Object> node ) {
- for (Node<Object, Object> child : node.getChildren()) {
- assertThat(child.isLoaded(), is(false));
- }
- }
-
- protected void assertNoChanges() {
- assertThat(cache.hasPendingChanges(), is(false));
- assertThat(cache.changeDependencies.isEmpty(), is(true));
- assertThat(cache.operations.isExecuteRequired(), is(false));
- }
-
- protected void assertNoMoreConnectionsUsed() {
- assertThat(numberOfConnections, is(0));
- }
-
- protected void assertConnectionsUsed( int number ) {
- assertThat(numberOfConnections, is(number));
- numberOfConnections = 0;
- }
-
-}
Copied: trunk/dna-graph/src/test/java/org/jboss/dna/graph/session/GraphSessionTest.java (from rev 1081, trunk/dna-graph/src/test/java/org/jboss/dna/graph/session/GraphCacheTest.java)
===================================================================
--- trunk/dna-graph/src/test/java/org/jboss/dna/graph/session/GraphSessionTest.java (rev 0)
+++ trunk/dna-graph/src/test/java/org/jboss/dna/graph/session/GraphSessionTest.java 2009-07-09 16:26:04 UTC (rev 1082)
@@ -0,0 +1,752 @@
+/*
+ * 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.session;
+
+import static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.IsNot.not;
+import static org.hamcrest.core.IsNull.notNullValue;
+import static org.hamcrest.core.IsSame.sameInstance;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.fail;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import org.jboss.dna.common.statistic.Stopwatch;
+import org.jboss.dna.graph.ExecutionContext;
+import org.jboss.dna.graph.Graph;
+import org.jboss.dna.graph.connector.RepositoryConnection;
+import org.jboss.dna.graph.connector.RepositoryConnectionFactory;
+import org.jboss.dna.graph.connector.RepositorySourceException;
+import org.jboss.dna.graph.connector.inmemory.InMemoryRepositorySource;
+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.session.GraphSession.Node;
+import org.jboss.dna.graph.session.GraphSession.Operations;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ *
+ */
+public class GraphSessionTest {
+
+ private static final Stopwatch LOADING_STOPWATCH = new Stopwatch();
+
+ protected ExecutionContext context;
+ protected InMemoryRepositorySource source;
+ private Graph store;
+ private GraphSession<Object, Object> cache;
+ private PathFactory pathFactory;
+ protected int numberOfConnections;
+
+ @Before
+ public void beforeEach() throws Exception {
+ context = new ExecutionContext();
+ pathFactory = context.getValueFactories().getPathFactory();
+ source = new InMemoryRepositorySource();
+ source.setName("store");
+ // Use a connection factory so we can count the number of connections that were made
+ RepositoryConnectionFactory connectionFactory = new RepositoryConnectionFactory() {
+ public RepositoryConnection createConnection( String sourceName ) throws RepositorySourceException {
+ if (source.getName().equals(sourceName)) {
+ ++numberOfConnections;
+ return source.getConnection();
+ }
+ return null;
+ }
+ };
+ store = Graph.create(source.getName(), connectionFactory, context);
+
+ // Load the store with content ...
+ LOADING_STOPWATCH.start();
+ store.importXmlFrom(getClass().getClassLoader().getResourceAsStream("cars.xml")).into("/");
+ LOADING_STOPWATCH.stop();
+ numberOfConnections = 0; // reset the number of connections
+
+ Operations<Object, Object> nodeOps = null; // use default
+ String workspaceName = null; // use current
+ cache = new GraphSession<Object, Object>(store, workspaceName, nodeOps);
+ }
+
+ @AfterClass
+ public static void afterAll() {
+ System.out.println(LOADING_STOPWATCH);
+ }
+
+ @Test
+ public void shouldHaveRootNodeWithCorrectNodeIdAndLocation() {
+ Node<Object, Object> node = cache.getRoot();
+ assertThat(node, is(notNullValue()));
+ assertThat(node.getNodeId(), is(notNullValue()));
+ assertThat(node.getLocation(), is(notNullValue()));
+ assertNoMoreConnectionsUsed();
+ assertNoChanges();
+ }
+
+ @Test
+ public void shouldNotHaveAutomaticallyLoadedRootNode() {
+ assertThat(cache.getRoot().isLoaded(), is(false));
+ assertNoMoreConnectionsUsed();
+ assertNoChanges();
+ }
+
+ @Test
+ public void shouldHaveRootNodeWithChildren() {
+ Node<Object, Object> node = cache.getRoot();
+ assertChildren(node, "Cars");
+ assertConnectionsUsed(1);
+ assertNoChanges();
+ }
+
+ @Test
+ public void shouldHaveNoExpirationIfSourceDoesNotHaveCachePolicy() {
+ Node<Object, Object> node = cache.getRoot();
+ node.load();
+ assertThat(node.getExpirationTimeInMillis(), is(Long.MAX_VALUE));
+ assertConnectionsUsed(1);
+ assertNoChanges();
+ }
+
+ @Test
+ public void shouldAutomaticallyLoadNodesWhenNavigatingToChildren() {
+ Node<Object, Object> root = cache.getRoot();
+ assertThat(root.isLoaded(), is(false));
+ assertChildren(root, "Cars"); // causes loading of the root node
+ assertThat(root.isLoaded(), is(true));
+ assertConnectionsUsed(1);
+
+ Node<Object, Object> cars = root.getChildren().iterator().next(); // only one child
+ assertThat(cars.isLoaded(), is(false));
+ assertChildren(cars, "Hybrid", "Sports", "Luxury", "Utility");
+ assertConnectionsUsed(1);
+ assertThat(cars.isLoaded(), is(true));
+ assertThat(cars.getParent(), is(sameInstance(root)));
+
+ Node<Object, Object> sports = cars.getChild(segment("Sports"));
+ assertThat(sports.isLoaded(), is(false));
+ assertChildren(sports, "Aston Martin DB9", "Infiniti G37");
+ assertConnectionsUsed(1);
+ assertThat(sports.isLoaded(), is(true));
+ assertThat(sports.getParent(), is(sameInstance(cars)));
+
+ Node<Object, Object> g37 = sports.getChild(segment("Infiniti G37"));
+ assertThat(g37.isLoaded(), is(false));
+ assertChildren(g37);
+ assertConnectionsUsed(1);
+ assertThat(g37.isLoaded(), is(true));
+ assertThat(g37.isLeaf(), is(true));
+ assertThat(g37.getParent(), is(sameInstance(sports)));
+
+ // Try another branch ...
+ Node<Object, Object> utility = cars.getChild(segment("Utility"));
+ assertThat(utility.isLoaded(), is(false));
+ assertChildren(utility, "Land Rover LR2", "Land Rover LR3", "Hummer H3", "Ford F-150");
+ assertConnectionsUsed(1);
+ assertThat(utility.isLoaded(), is(true));
+ assertThat(utility.getParent(), is(sameInstance(cars)));
+
+ Node<Object, Object> lr3 = utility.getChild(segment("Land Rover LR3"));
+ assertThat(lr3.isLoaded(), is(false));
+ assertChildren(lr3);
+ assertConnectionsUsed(1);
+ assertThat(lr3.isLoaded(), is(true));
+ assertThat(lr3.isLeaf(), is(true));
+ assertThat(lr3.getParent(), is(sameInstance(utility)));
+
+ assertNoMoreConnectionsUsed();
+ assertNoChanges();
+ }
+
+ @Test
+ public void shouldFindNodesByPath() {
+ Node<Object, Object> g37 = cache.findNodeWith(path("/Cars/Sports/Infiniti G37")); // loads the node and all parents
+ assertConnectionsUsed(1);
+ assertThat(g37.isLoaded(), is(true));
+ assertChildren(g37);
+ assertThat(g37.isLoaded(), is(true));
+ assertThat(g37.isLeaf(), is(true));
+
+ Node<Object, Object> sports = g37.getParent();
+ assertThat(sports.isLoaded(), is(true));
+ assertChildren(sports, "Aston Martin DB9", "Infiniti G37");
+
+ Node<Object, Object> cars = sports.getParent();
+ assertThat(cars.isLoaded(), is(true));
+ assertChildren(cars, "Hybrid", "Sports", "Luxury", "Utility");
+
+ Node<Object, Object> root = cars.getParent();
+ assertThat(root, is(sameInstance(cache.getRoot())));
+ assertThat(root.isLoaded(), is(true));
+ assertChildren(root, "Cars"); // causes loading of the root node
+
+ assertNoMoreConnectionsUsed();
+
+ // Try another branch that should not be loaded...
+ Node<Object, Object> utility = cars.getChild(segment("Utility"));
+ assertThat(utility.isLoaded(), is(false));
+ assertChildren(utility, "Land Rover LR2", "Land Rover LR3", "Hummer H3", "Ford F-150");
+ assertConnectionsUsed(1);
+ assertThat(utility.isLoaded(), is(true));
+ assertThat(utility.getParent(), is(sameInstance(cars)));
+
+ assertNoMoreConnectionsUsed();
+ assertNoChanges();
+ }
+
+ @Test
+ public void shouldFindNodesById() {
+ cache.findNodeWith(path("/Cars/Sports/Infiniti G37")); // loads the node and all parents
+ assertConnectionsUsed(1); // "Utility" was found because it is child of "Cars" loaded when "Sports" was loaded
+
+ cache.getRoot().onCachedNodes(new GraphSession.NodeVisitor<Object, Object>() {
+ @SuppressWarnings( "synthetic-access" )
+ @Override
+ public boolean visit( Node<Object, Object> node ) {
+ assertThat(cache.findNodeWith(node.getNodeId(), null), is(sameInstance(node)));
+ return true;
+ }
+ });
+ }
+
+ @Test
+ public void shouldFindNodesByLocation() {
+ cache.findNodeWith(path("/Cars/Sports/Infiniti G37")); // loads the node and all parents
+ assertConnectionsUsed(1); // "Utility" was found because it is child of "Cars" loaded when "Sports" was loaded
+
+ cache.getRoot().onCachedNodes(new GraphSession.NodeVisitor<Object, Object>() {
+ @SuppressWarnings( "synthetic-access" )
+ @Override
+ public boolean visit( Node<Object, Object> node ) {
+ assertThat(cache.findNodeWith(null, node.getLocation().getPath()), is(sameInstance(node)));
+ return true;
+ }
+ });
+ }
+
+ @Test
+ public void shouldFindNodesByIdAfterClearing() {
+ Node<Object, Object> g37 = cache.findNodeWith(path("/Cars/Sports/Infiniti G37")); // loads the node and all parents
+ assertConnectionsUsed(1);
+ assertThat(g37.isLoaded(), is(true));
+ assertChildren(g37);
+ assertThat(g37.isLoaded(), is(true));
+ assertThat(g37.isLeaf(), is(true));
+
+ Node<Object, Object> sports = g37.getParent();
+ Node<Object, Object> cars = sports.getParent();
+ Node<Object, Object> root = cars.getParent();
+
+ assertNoMoreConnectionsUsed();
+
+ cache.getRoot().unload();
+
+ Node<Object, Object> g37_b = cache.findNodeWith(g37.getNodeId(), g37.getPath());
+ assertConnectionsUsed(1);
+
+ Node<Object, Object> sports_b = g37_b.getParent();
+ Node<Object, Object> cars_b = sports_b.getParent();
+ Node<Object, Object> root_b = cars_b.getParent();
+ assertThat(g37_b, is(not(sameInstance(g37))));
+ assertThat(sports_b, is(not(sameInstance(sports))));
+ assertThat(cars_b, is(not(sameInstance(cars))));
+ assertThat(root_b, is(sameInstance(root)));
+ assertThat(g37_b.isLeaf(), is(true));
+ assertChildren(sports_b, "Aston Martin DB9", "Infiniti G37");
+ assertChildren(cars_b, "Hybrid", "Sports", "Luxury", "Utility");
+ assertChildren(root_b, "Cars");
+
+ assertNoMoreConnectionsUsed();
+ assertNoChanges();
+ }
+
+ @Test
+ public void shouldMoveBranchAndRefresh() {
+ Node<Object, Object> sports = cache.findNodeWith(path("/Cars/Sports"));
+ Node<Object, Object> utility = cache.findNodeWith(path("/Cars/Utility"));
+ assertConnectionsUsed(1); // "Utility" was found because it is child of "Cars" loaded when "Sports" was loaded
+
+ sports.moveTo(utility);
+ assertConnectionsUsed(1); // "Utility" was not fully loaded before
+ assertNoMoreConnectionsUsed();
+
+ Node<Object, Object> cars = cache.findNodeWith(path("/Cars"));
+
+ for (int i = 0; i != 3; ++i) {
+ assertChildren(cars, "Hybrid", "Luxury", "Utility");
+ assertChildren(utility, "Land Rover LR2", "Land Rover LR3", "Hummer H3", "Ford F-150", "Sports");
+ assertThat(sports.getParent(), is(utility));
+ assertThat(utility.getParent(), is(cars));
+
+ // Ensure that the changes were recorded appropriately ...
+ assertThat(cars.isChanged(false), is(true)); // 'sports' removed as child
+ assertThat(utility.isChanged(false), is(true)); // 'sports' added as child
+ assertThat(sports.isChanged(false), is(true)); // path has changed
+ assertThat(cache.hasPendingChanges(), is(true));
+ assertThat(cache.changeDependencies.size(), is(1));
+ assertThat(cache.changeDependencies.get(sports.getNodeId()).getMovedFrom(), is(cars.getNodeId()));
+ assertThat(cache.operations.isExecuteRequired(), is(true));
+
+ if (i == 0) {
+ // 1st time: Refreshing "Utility" shouldn't work because "/Cars" was involved in the same move ...
+ try {
+ cache.refresh(utility, false);
+ fail("Expected exception from the call to refresh");
+ } catch (InvalidStateException e) {
+ // expected ...
+ }
+ } else if (i == 1) {
+ // 2nd time: refresh "/Cars" but keep the changes ...
+ cache.refresh(cars, true);
+ } else if (i == 2) {
+ // 3rd time:
+ cache.refresh(cars, false);
+ }
+ }
+
+ // Now the state should be back to the original representation, but we need to refind the nodes ...
+ sports = cache.findNodeWith(path("/Cars/Sports"));
+ utility = cache.findNodeWith(path("/Cars/Utility"));
+ cars = cache.findNodeWith(path("/Cars"));
+
+ assertChildren(cars, "Hybrid", "Sports", "Luxury", "Utility");
+ assertChildren(utility, "Land Rover LR2", "Land Rover LR3", "Hummer H3", "Ford F-150");
+ assertThat(sports.getParent(), is(cars));
+ assertThat(utility.getParent(), is(cars));
+
+ // Now there should be no changes ...
+ assertNoChanges();
+ System.out.println(cache.root.getSnapshot(false));
+ }
+
+ @Test
+ public void shouldMoveBranchAndSaveBranch() {
+ Node<Object, Object> sports = cache.findNodeWith(path("/Cars/Sports"));
+ Node<Object, Object> utility = cache.findNodeWith(path("/Cars/Utility"));
+ assertConnectionsUsed(1); // "Utility" was found because it is child of "Cars" loaded when "Sports" was loaded
+
+ sports.moveTo(utility);
+ assertConnectionsUsed(1); // "Utility" was not fully loaded before
+ assertNoMoreConnectionsUsed();
+
+ Node<Object, Object> cars = cache.findNodeWith(path("/Cars"));
+ Node<Object, Object> root = cache.getRoot();
+
+ for (int i = 0; i != 2; ++i) {
+ assertChildren(cars, "Hybrid", "Luxury", "Utility");
+ assertChildren(utility, "Land Rover LR2", "Land Rover LR3", "Hummer H3", "Ford F-150", "Sports");
+ assertThat(sports.getParent(), is(utility));
+ assertThat(utility.getParent(), is(cars));
+
+ // Ensure that the changes were recorded appropriately ...
+ assertThat(cars.isChanged(false), is(true)); // 'sports' removed as child
+ assertThat(utility.isChanged(false), is(true)); // 'sports' added as child
+ assertThat(sports.isChanged(false), is(true)); // path has changed
+ assertThat(cache.hasPendingChanges(), is(true));
+ assertThat(cache.changeDependencies.size(), is(1));
+ assertThat(cache.changeDependencies.get(sports.getNodeId()).getMovedFrom(), is(cars.getNodeId()));
+ assertThat(cache.operations.isExecuteRequired(), is(true));
+
+ if (i == 0) {
+ // 1st time: Saving "Utility" shouldn't work because "/Cars" was involved in the same move ...
+ try {
+ cache.save(utility);
+ fail("Expected exception from the call to save");
+ } catch (InvalidStateException e) {
+ // expected ...
+ }
+ } else if (i == 1) {
+ // 2nd time: Save "/Cars" but keep the changes ...
+ assertConnectionsUsed(0);
+ cache.save(cars);
+ assertConnectionsUsed(2); // 1 to load children required by validation, 1 to perform save
+ }
+ // i=2 do nothing
+ }
+
+ // The affected nodes should now be stale ...
+ assertThat(sports.isStale(), is(true));
+ assertThat(utility.isStale(), is(true));
+ assertThat(cars.isStale(), is(false)); // not stale because it was unloaded
+ assertThat(cars.isLoaded(), is(false));
+ assertThat(root.isStale(), is(false)); // not touched during saves
+
+ // Now the state should reflect our changes, but we need to refind the nodes ...
+ sports = cache.findNodeWith(path("/Cars/Utility/Sports"));
+ assertConnectionsUsed(1);
+ utility = cache.findNodeWith(path("/Cars/Utility"));
+ assertNoMoreConnectionsUsed();
+
+ assertChildren(cars, "Hybrid", "Luxury", "Utility");
+ assertChildren(utility, "Land Rover LR2", "Land Rover LR3", "Hummer H3", "Ford F-150", "Sports");
+ assertThat(sports.getParent(), is(utility));
+ assertThat(utility.getParent(), is(cars));
+
+ // Now there should be no changes ...
+ assertNoChanges();
+
+ System.out.println(cache.root.getSnapshot(false));
+ }
+
+ @Test
+ public void shouldMoveBranchAndSaveAll() {
+ Node<Object, Object> sports = cache.findNodeWith(path("/Cars/Sports"));
+ Node<Object, Object> utility = cache.findNodeWith(path("/Cars/Utility"));
+ assertConnectionsUsed(1); // "Utility" was found because it is child of "Cars" loaded when "Sports" was loaded
+
+ sports.moveTo(utility);
+ assertConnectionsUsed(1); // "Utility" was not fully loaded before
+ assertNoMoreConnectionsUsed();
+
+ Node<Object, Object> cars = cache.findNodeWith(path("/Cars"));
+ Node<Object, Object> root = cache.getRoot();
+
+ assertChildren(cars, "Hybrid", "Luxury", "Utility");
+ assertChildren(utility, "Land Rover LR2", "Land Rover LR3", "Hummer H3", "Ford F-150", "Sports");
+ assertThat(sports.getParent(), is(utility));
+ assertThat(utility.getParent(), is(cars));
+
+ // Ensure that the changes were recorded appropriately ...
+ assertThat(cars.isChanged(false), is(true)); // 'sports' removed as child
+ assertThat(utility.isChanged(false), is(true)); // 'sports' added as child
+ assertThat(sports.isChanged(false), is(true)); // path has changed
+ assertThat(cache.hasPendingChanges(), is(true));
+ assertThat(cache.changeDependencies.size(), is(1));
+ assertThat(cache.changeDependencies.get(sports.getNodeId()).getMovedFrom(), is(cars.getNodeId()));
+ assertThat(cache.operations.isExecuteRequired(), is(true));
+
+ // Save the changes ...
+ assertConnectionsUsed(0);
+ cache.save();
+ assertConnectionsUsed(2); // 1 to load children required by validation, 1 to perform save
+
+ // The affected nodes should now be stale ...
+ assertThat(sports.isStale(), is(true));
+ assertThat(utility.isStale(), is(true));
+ assertThat(cars.isStale(), is(false)); // not stale because it was unloaded
+ assertThat(cars.isLoaded(), is(false));
+ assertThat(root.isStale(), is(false)); // not touched during saves
+
+ // Now the state should reflect our changes, but we need to refind the nodes ...
+ sports = cache.findNodeWith(path("/Cars/Utility/Sports"));
+ assertConnectionsUsed(1);
+ utility = cache.findNodeWith(path("/Cars/Utility"));
+ assertNoMoreConnectionsUsed();
+
+ assertChildren(cars, "Hybrid", "Luxury", "Utility");
+ assertChildren(utility, "Land Rover LR2", "Land Rover LR3", "Hummer H3", "Ford F-150", "Sports");
+ assertThat(sports.getParent(), is(utility));
+ assertThat(utility.getParent(), is(cars));
+
+ // Now there should be no changes ...
+ assertNoChanges();
+
+ // System.out.println(cache.root.getSnapshot(false));
+ }
+
+ @Test
+ public void shouldRenameNodeByRemovingAndAddingAtEndOfChildren() {
+ Node<Object, Object> sports = cache.findNodeWith(path("/Cars/Sports"));
+ assertConnectionsUsed(1); // "Utility" was found because it is child of "Cars" loaded when "Sports" was loaded
+
+ sports.rename(name("non-sports")); // "Sports" was already loaded, as was "Cars"
+ assertNoMoreConnectionsUsed();
+
+ Node<Object, Object> cars = cache.findNodeWith(path("/Cars"));
+
+ assertChildren(cars, "Hybrid", "Luxury", "Utility", "non-sports");
+ assertThat(sports.getParent(), is(cars));
+
+ // Ensure that the changes were recorded appropriately ...
+ assertThat(cars.isChanged(false), is(true)); // 'sports' renamed as child
+ assertThat(sports.isChanged(false), is(true)); // path has changed
+ assertThat(cache.hasPendingChanges(), is(true));
+ assertThat(cache.operations.isExecuteRequired(), is(true));
+
+ // Save "/Cars" but keep the changes ...
+ assertConnectionsUsed(0);
+ cache.save(cars);
+ assertConnectionsUsed(2); // 1 to load children required by validation, 1 to perform save
+
+ // Now the state should reflect our changes, but we need to refind the nodes ...
+ Node<Object, Object> nonSports = cache.findNodeWith(path("/Cars/non-sports"));
+ assertConnectionsUsed(1);
+ assertNoMoreConnectionsUsed();
+
+ assertChildren(cars, "Hybrid", "Luxury", "Utility", "non-sports");
+ assertThat(nonSports.getParent(), is(cars));
+
+ // Now there should be no changes ...
+ assertNoChanges();
+
+ System.out.println(cache.root.getSnapshot(false));
+ }
+
+ @Test
+ public void shouldRenameNodeByRemovingAndAddingAtEndOfChildrenEvenWithSameNameSiblings() {
+ Node<Object, Object> sports = cache.findNodeWith(path("/Cars/Sports"));
+ assertConnectionsUsed(1); // "Utility" was found because it is child of "Cars" loaded when "Sports" was loaded
+
+ sports.rename(name("Utility")); // "Sports" was already loaded, as was "Cars"
+ assertNoMoreConnectionsUsed();
+
+ Node<Object, Object> cars = cache.findNodeWith(path("/Cars"));
+
+ assertChildren(cars, "Hybrid", "Luxury", "Utility", "Utility[2]");
+ assertThat(sports.getParent(), is(cars));
+
+ // Ensure that the changes were recorded appropriately ...
+ assertThat(cars.isChanged(false), is(true)); // 'sports' renamed as child
+ assertThat(sports.isChanged(false), is(true)); // path has changed
+ assertThat(cache.hasPendingChanges(), is(true));
+ assertThat(cache.operations.isExecuteRequired(), is(true));
+
+ // Save "/Cars" but keep the changes ...
+ assertConnectionsUsed(0);
+ cache.save(cars);
+ assertConnectionsUsed(2); // 1 to load children required by validation, 1 to perform save
+
+ // Now the state should reflect our changes, but we need to refind the nodes ...
+ Node<Object, Object> utility2 = cache.findNodeWith(path("/Cars/Utility[2]"));
+ assertConnectionsUsed(1);
+ assertNoMoreConnectionsUsed();
+
+ assertChildren(cars, "Hybrid", "Luxury", "Utility", "Utility[2]");
+ assertThat(utility2.getParent(), is(cars));
+
+ // Now there should be no changes ...
+ assertNoChanges();
+
+ System.out.println(cache.root.getSnapshot(false));
+ }
+
+ @Test
+ public void shouldReorderChildWithNoSnsIndexes() {
+ Node<Object, Object> sports = cache.findNodeWith(path("/Cars/Sports"));
+ Node<Object, Object> utility = cache.findNodeWith(path("/Cars/Utility"));
+ Node<Object, Object> cars = cache.findNodeWith(path("/Cars"));
+ assertConnectionsUsed(1); // "Utility" was found because it is child of "Cars" loaded when "Sports" was loaded
+
+ cars.orderChildBefore(utility.getSegment(), sports.getSegment());
+ assertNoMoreConnectionsUsed();
+
+ Node<Object, Object> root = cache.getRoot();
+
+ assertChildren(cars, "Hybrid", "Utility", "Sports", "Luxury");
+ assertThat(sports.getParent(), is(cars));
+ assertThat(utility.getParent(), is(cars));
+
+ // Save the changes ...
+ assertConnectionsUsed(0);
+ cache.save();
+ assertConnectionsUsed(2); // 1 to load children required by validation, 1 to perform save
+
+ // The affected nodes should now be stale ...
+ assertThat(sports.isStale(), is(true));
+ assertThat(utility.isStale(), is(true));
+ assertThat(cars.isStale(), is(false)); // not stale because it was unloaded
+ assertThat(cars.isLoaded(), is(false));
+ assertThat(root.isStale(), is(false)); // not touched during saves
+
+ // Now the state should reflect our changes ...
+ assertChildren(cars, "Hybrid", "Utility", "Sports", "Luxury");
+
+ // Now there should be no changes ...
+ assertNoChanges();
+ }
+
+ @Test
+ public void shouldReorderChildWithSnsIndexes() {
+ Node<Object, Object> sports = cache.findNodeWith(path("/Cars/Sports"));
+ Node<Object, Object> cars = cache.findNodeWith(path("/Cars"));
+ assertConnectionsUsed(1); // "Utility" was found because it is child of "Cars" loaded when "Sports" was loaded
+
+ Node<Object, Object> exp1 = cars.createChild(name("Experimental"));
+ Node<Object, Object> exp2 = cars.createChild(name("Experimental"));
+ Node<Object, Object> exp3 = cars.createChild(name("Experimental"));
+ assertThat(cache.hasPendingChanges(), is(true));
+ assertThat(exp1.getSegment().getIndex(), is(1));
+ assertThat(exp2.getSegment().getIndex(), is(2));
+ assertThat(exp3.getSegment().getIndex(), is(3));
+ assertChildren(cars, "Hybrid", "Sports", "Luxury", "Utility", "Experimental", "Experimental[2]", "Experimental[3]");
+
+ cars.orderChildBefore(exp3.getSegment(), sports.getSegment());
+ assertNoMoreConnectionsUsed();
+
+ assertThat(exp1.getSegment().getIndex(), is(2));
+ assertThat(exp2.getSegment().getIndex(), is(3));
+ assertThat(exp3.getSegment().getIndex(), is(1));
+ assertChildren(cars, "Hybrid", "Experimental", "Sports", "Luxury", "Utility", "Experimental[2]", "Experimental[3]");
+
+ // Save the changes ...
+ assertConnectionsUsed(0);
+ cache.save();
+ assertConnectionsUsed(2); // 1 to load children required by validation, 1 to perform save
+
+ // Now the state should reflect our changes ...
+ assertChildren(cars, "Hybrid", "Experimental", "Sports", "Luxury", "Utility", "Experimental[2]", "Experimental[3]");
+
+ // Now there should be no changes ...
+ assertNoChanges();
+ }
+
+ @Test
+ public void shouldLoadSubgraphs() {
+ cache.setDepthForLoadingNodes(4);
+ Node<Object, Object> cars = cache.findNodeWith(path("/Cars")); // loads the node and all parents
+ assertChildren(cars, "Hybrid", "Sports", "Luxury", "Utility");
+ assertConnectionsUsed(1);
+
+ Node<Object, Object> sports = cache.findNodeWith(path("/Cars/Sports"));
+ Node<Object, Object> g37 = cache.findNodeWith(path("/Cars/Sports/Infiniti G37"));
+ Node<Object, Object> db9 = cache.findNodeWith(path("/Cars/Sports/Aston Martin DB9"));
+ assertConnectionsUsed(0); // should have been loaded with sports subgraph
+
+ assertThat(sports.isLoaded(), is(true));
+ assertThat(g37.isLoaded(), is(true));
+ assertThat(db9.isLoaded(), is(true));
+ assertChildren(sports, "Aston Martin DB9", "Infiniti G37");
+ assertChildren(g37);
+ assertChildren(db9);
+
+ assertNoMoreConnectionsUsed();
+ assertNoChanges();
+ }
+
+ @Test
+ public void shouldMarkAsChangedWhenSettingProperties() {
+ Node<Object, Object> g37 = cache.findNodeWith(path("/Cars/Sports/Infiniti G37"));
+ assertThat(g37.isChanged(false), is(false));
+
+ // Set the new property ...
+ Property newProperty = createProperty("something", "value1");
+ g37.setProperty(newProperty, false, null);
+ assertThat(g37.isChanged(false), is(true));
+ assertThat(cache.getRoot().isChanged(true), is(true));
+
+ // Save the changes ...
+ cache.save();
+ }
+
+ @Test
+ public void shouldClearPropertyChangesWhenRefreshing() {
+ Node<Object, Object> g37 = cache.findNodeWith(path("/Cars/Sports/Infiniti G37"));
+ assertThat(g37.isChanged(false), is(false));
+
+ // Set the new property ...
+ Property newProperty = createProperty("something", "value1");
+ g37.setProperty(newProperty, false, null);
+ assertThat(g37.isChanged(false), is(true));
+ assertThat(cache.getRoot().isChanged(true), is(true));
+
+ // Refresh the changes ...
+ cache.refresh(g37, false);
+
+ assertThat(g37.isChanged(true), is(false));
+ assertThat(cache.getRoot().isChanged(true), is(false));
+ assertNoChanges();
+ }
+
+ @Test
+ public void shouldCreateChildren() {
+ Node<Object, Object> cars = cache.findNodeWith(path("/Cars")); // loads the node and all parents
+ assertChildren(cars, "Hybrid", "Sports", "Luxury", "Utility");
+ assertConnectionsUsed(1);
+
+ Node<Object, Object> experimental = cars.createChild(name("Experimental"));
+ assertThat(experimental.getParent(), is(sameInstance(cars)));
+ assertChildren(cars, "Hybrid", "Sports", "Luxury", "Utility", "Experimental");
+ assertThat(cars.isChanged(false), is(true));
+ assertThat(experimental.isNew(), is(true));
+ assertNoMoreConnectionsUsed();
+
+ Node<Object, Object> experimental2 = cars.createChild(name("Experimental"));
+ assertThat(experimental2.getParent(), is(sameInstance(cars)));
+ assertChildren(cars, "Hybrid", "Sports", "Luxury", "Utility", "Experimental[1]", "Experimental[2]");
+ assertThat(cars.isChanged(false), is(true));
+ assertThat(experimental2.isNew(), is(true));
+ assertNoMoreConnectionsUsed();
+ }
+
+ protected void assertChildren( Node<Object, Object> node,
+ String... childNames ) {
+ assertThat(node.getChildrenCount(), is(childNames.length));
+ List<Path.Segment> segments = new LinkedList<Path.Segment>();
+ for (String childName : childNames) {
+ segments.add(pathFactory.createSegment(childName));
+ }
+ Iterator<Path.Segment> expectedIter = segments.iterator();
+ Iterator<Node<Object, Object>> actualIter = node.getChildren().iterator();
+ while (expectedIter.hasNext() && actualIter.hasNext()) {
+ Node<Object, Object> actualNode = actualIter.next();
+ Path actualPath = actualNode.getPath();
+ Path.Segment actualSegment = actualPath.getLastSegment();
+ Path.Segment expectedSegment = expectedIter.next();
+ assertThat(actualSegment, is(expectedSegment));
+ }
+ assertThat(expectedIter.hasNext(), is(false));
+ assertThat(actualIter.hasNext(), is(false));
+ }
+
+ protected Name name( String name ) {
+ return context.getValueFactories().getNameFactory().create(name);
+ }
+
+ protected Path.Segment segment( String segment ) {
+ return context.getValueFactories().getPathFactory().createSegment(segment);
+ }
+
+ protected Path path( String path ) {
+ return context.getValueFactories().getPathFactory().create(path);
+ }
+
+ protected Property createProperty( String name,
+ Object... values ) {
+ return context.getPropertyFactory().create(name(name), values);
+ }
+
+ protected void assertChildrenNotLoaded( Node<Object, Object> node ) {
+ for (Node<Object, Object> child : node.getChildren()) {
+ assertThat(child.isLoaded(), is(false));
+ }
+ }
+
+ protected void assertNoChanges() {
+ assertThat(cache.hasPendingChanges(), is(false));
+ assertThat(cache.changeDependencies.isEmpty(), is(true));
+ assertThat(cache.operations.isExecuteRequired(), is(false));
+ }
+
+ protected void assertNoMoreConnectionsUsed() {
+ assertThat(numberOfConnections, is(0));
+ }
+
+ protected void assertConnectionsUsed( int number ) {
+ assertThat(numberOfConnections, is(number));
+ numberOfConnections = 0;
+ }
+
+}
Property changes on: trunk/dna-graph/src/test/java/org/jboss/dna/graph/session/GraphSessionTest.java
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/AbstractJcrNode.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/AbstractJcrNode.java 2009-07-09 16:23:09 UTC (rev 1081)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/AbstractJcrNode.java 2009-07-09 16:26:04 UTC (rev 1082)
@@ -24,7 +24,6 @@
package org.jboss.dna.jcr;
import java.io.InputStream;
-import java.security.AccessControlException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
@@ -43,7 +42,6 @@
import javax.jcr.ItemNotFoundException;
import javax.jcr.ItemVisitor;
import javax.jcr.NoSuchWorkspaceException;
-import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.PathNotFoundException;
import javax.jcr.Property;
@@ -66,7 +64,8 @@
import net.jcip.annotations.Immutable;
import org.jboss.dna.common.i18n.I18n;
import org.jboss.dna.common.util.CheckArg;
-import org.jboss.dna.graph.Graph;
+import org.jboss.dna.graph.Location;
+import org.jboss.dna.graph.connector.RepositorySourceException;
import org.jboss.dna.graph.property.Binary;
import org.jboss.dna.graph.property.DateTime;
import org.jboss.dna.graph.property.Name;
@@ -74,81 +73,80 @@
import org.jboss.dna.graph.property.Path;
import org.jboss.dna.graph.property.PathFactory;
import org.jboss.dna.graph.property.ValueFactories;
+import org.jboss.dna.graph.session.GraphSession.Node;
+import org.jboss.dna.graph.session.GraphSession.NodeId;
+import org.jboss.dna.graph.session.GraphSession.PropertyInfo;
+import org.jboss.dna.jcr.SessionCache.JcrNodePayload;
+import org.jboss.dna.jcr.SessionCache.JcrPropertyPayload;
import org.jboss.dna.jcr.SessionCache.NodeEditor;
-import org.jboss.dna.jcr.cache.ChildNode;
-import org.jboss.dna.jcr.cache.Children;
-import org.jboss.dna.jcr.cache.NodeInfo;
/**
- * An abstract implementation of the JCR {@link Node} interface. Instances of this class are created and managed by the
- * {@link SessionCache}. Each instance references the {@link NodeInfo node information} also managed by the SessionCache, and
- * finds and operates against this information with each method call.
+ * An abstract implementation of the JCR {@link javax.jcr.Node} interface. Instances of this class are created and managed by the
+ * {@link SessionCache}. Each instance indirectly references the {@link javax.jcr.Node node information} also managed by the
+ * SessionCache, and finds and operates against this information with each method call.
*/
@Immutable
-abstract class AbstractJcrNode extends AbstractJcrItem implements Node {
+abstract class AbstractJcrNode extends AbstractJcrItem implements javax.jcr.Node {
private static final NodeType[] EMPTY_NODE_TYPES = new NodeType[] {};
- protected final UUID nodeUuid;
+ protected final NodeId nodeId;
+ protected final Location location;
AbstractJcrNode( SessionCache cache,
- UUID nodeUuid ) {
+ NodeId nodeId,
+ Location location ) {
super(cache);
- this.nodeUuid = nodeUuid;
+ this.nodeId = nodeId;
+ this.location = location;
}
abstract boolean isRoot();
public abstract AbstractJcrNode getParent() throws ItemNotFoundException, RepositoryException;
- final UUID internalUuid() {
- return nodeUuid;
+ final NodeId internalId() {
+ return nodeId;
}
final Name name() throws RepositoryException {
- return cache.getNameOf(nodeUuid);
+ return nodeInfo().getName();
}
- final NodeInfo nodeInfo() throws ItemNotFoundException, RepositoryException {
- return cache.findNodeInfo(nodeUuid);
+ final Path.Segment segment() throws RepositoryException {
+ return nodeInfo().getSegment();
}
+ final Node<JcrNodePayload, JcrPropertyPayload> nodeInfo()
+ throws ItemNotFoundException, AccessDeniedException, RepositoryException {
+ return cache.findNode(nodeId, location.getPath());
+ }
+
final NodeEditor editorForParent() throws RepositoryException {
try {
- return cache.getEditorFor(nodeInfo().getParent());
+ Node<JcrNodePayload, JcrPropertyPayload> parent = nodeInfo().getParent();
+ return cache.getEditorFor(parent);
} catch (ItemNotFoundException err) {
- String msg = JcrI18n.nodeHasAlreadyBeenRemovedFromThisSession.text(nodeUuid, cache.workspaceName());
+ String msg = JcrI18n.nodeHasAlreadyBeenRemovedFromThisSession.text(nodeId, cache.workspaceName());
throw new RepositoryException(msg);
} catch (InvalidItemStateException err) {
- String msg = JcrI18n.nodeHasAlreadyBeenRemovedFromThisSession.text(nodeUuid, cache.workspaceName());
+ String msg = JcrI18n.nodeHasAlreadyBeenRemovedFromThisSession.text(nodeId, cache.workspaceName());
throw new RepositoryException(msg);
}
}
final NodeEditor editor() throws RepositoryException {
try {
- return cache.getEditorFor(nodeUuid);
+ return cache.getEditorFor(nodeId, location.getPath());
} catch (ItemNotFoundException err) {
- String msg = JcrI18n.nodeHasAlreadyBeenRemovedFromThisSession.text(nodeUuid, cache.workspaceName());
+ String msg = JcrI18n.nodeHasAlreadyBeenRemovedFromThisSession.text(nodeId, cache.workspaceName());
throw new RepositoryException(msg);
} catch (InvalidItemStateException err) {
- String msg = JcrI18n.nodeHasAlreadyBeenRemovedFromThisSession.text(nodeUuid, cache.workspaceName());
+ String msg = JcrI18n.nodeHasAlreadyBeenRemovedFromThisSession.text(nodeId, cache.workspaceName());
throw new RepositoryException(msg);
}
}
- final NodeEditor editorFor( Graph.Batch operations ) throws RepositoryException {
- try {
- return cache.getEditorFor(nodeUuid, operations);
- } catch (ItemNotFoundException err) {
- String msg = JcrI18n.nodeHasAlreadyBeenRemovedFromThisSession.text(nodeUuid, cache.workspaceName());
- throw new RepositoryException(msg);
- } catch (InvalidItemStateException err) {
- String msg = JcrI18n.nodeHasAlreadyBeenRemovedFromThisSession.text(nodeUuid, cache.workspaceName());
- throw new RepositoryException(msg);
- }
- }
-
final JcrValue valueFrom( int propertyType,
Object value ) {
return new JcrValue(cache.factories(), cache, propertyType, value);
@@ -166,7 +164,7 @@
return new JcrValue(factories, cache, PropertyType.DATE, binary);
}
- final JcrValue valueFrom( Node value ) throws UnsupportedRepositoryOperationException, RepositoryException {
+ final JcrValue valueFrom( javax.jcr.Node value ) throws UnsupportedRepositoryOperationException, RepositoryException {
ValueFactories factories = cache.factories();
String uuid = factories.getStringFactory().create(value.getUUID());
return new JcrValue(factories, cache, PropertyType.REFERENCE, uuid);
@@ -188,21 +186,31 @@
@Override
Path path() throws RepositoryException {
- return cache.getPathFor(nodeInfo());
+ // Don't use the path in the location, since it may no longer be valid
+ return nodeInfo().getPath();
}
+ boolean isReferenceable() throws RepositoryException {
+ return isNodeType(JcrMixLexicon.REFERENCEABLE);
+ }
+
/**
* {@inheritDoc}
*
* @see javax.jcr.Node#getUUID()
*/
- public final String getUUID() throws RepositoryException {
+ public String getUUID() throws RepositoryException {
// Return "jcr:uuid" only if node is referenceable
- String referenceableTypeName = JcrMixLexicon.REFERENCEABLE.getString(namespaces());
- if (!isNodeType(referenceableTypeName)) {
+ if (!isReferenceable()) {
throw new UnsupportedRepositoryOperationException();
}
- return nodeUuid.toString();
+ PropertyInfo<JcrPropertyPayload> uuidProp = nodeInfo().getProperty(JcrLexicon.UUID);
+ if (uuidProp == null) {
+ uuidProp = nodeInfo().getProperty(DnaLexicon.UUID);
+ }
+ assert uuidProp != null;
+ assert !uuidProp.getProperty().isEmpty();
+ return context().getValueFactories().getStringFactory().create(uuidProp.getProperty().getFirstValue());
}
/**
@@ -222,19 +230,30 @@
* @see javax.jcr.Node#isNodeType(java.lang.String)
*/
public boolean isNodeType( String nodeTypeName ) throws RepositoryException {
- NodeType nodeType = getPrimaryNodeType();
+ return isNodeType(nameFrom(nodeTypeName));
+ }
+ /**
+ * Determine whether this node's primary type or any of the mixins are or extend the node type with the supplied name. This
+ * method is semantically equivalent to but slightly more efficient than the {@link #isNodeType(String) equivalent in the JCR
+ * API}, especially when the node type name is already a {@link Name} object.
+ *
+ * @param nodeTypeName the name of the node type
+ * @return true if this node is of the node type given by the supplied name, or false otherwise
+ * @throws RepositoryException if there is an exception
+ */
+ public final boolean isNodeType( Name nodeTypeName ) throws RepositoryException {
+ JcrNodeType nodeType = getPrimaryNodeType();
if (nodeType.isNodeType(nodeTypeName)) {
return true;
}
-
- NodeType[] mixinNodeTypes = getMixinNodeTypes();
- for (int i = 0; i < mixinNodeTypes.length; i++) {
- if (mixinNodeTypes[i].isNodeType(nodeTypeName)) {
+ JcrNodeTypeManager nodeTypes = session().nodeTypeManager();
+ for (Name mixinTypeName : getMixinTypeNames()) {
+ JcrNodeType mixinType = nodeTypes.getNodeType(mixinTypeName);
+ if (mixinType.isNodeType(nodeTypeName)) {
return true;
}
}
-
return false;
}
@@ -244,7 +263,7 @@
* @see javax.jcr.Node#getDefinition()
*/
public NodeDefinition getDefinition() throws RepositoryException {
- NodeDefinitionId definitionId = nodeInfo().getDefinitionId();
+ NodeDefinitionId definitionId = nodeInfo().getPayload().getDefinitionId();
return session().nodeTypeManager().getNodeDefinition(definitionId);
}
@@ -254,12 +273,11 @@
* @see javax.jcr.Node#getPrimaryNodeType()
*/
public JcrNodeType getPrimaryNodeType() throws RepositoryException {
- Name primaryTypeName = nodeInfo().getPrimaryTypeName();
- return session().nodeTypeManager().getNodeType(primaryTypeName);
+ return session().nodeTypeManager().getNodeType(getPrimaryTypeName());
}
Name getPrimaryTypeName() throws RepositoryException {
- return nodeInfo().getPrimaryTypeName();
+ return nodeInfo().getPayload().getPrimaryTypeName();
}
/**
@@ -281,7 +299,7 @@
}
List<Name> getMixinTypeNames() throws RepositoryException {
- return nodeInfo().getMixinTypeNames();
+ return nodeInfo().getPayload().getMixinTypeNames();
}
/**
@@ -306,7 +324,7 @@
getPath(),
cache.workspaceName()));
}
- return cache.findJcrItem(nodeUuid, primaryItemPath);
+ return cache.findJcrItem(nodeId, location.getPath(), primaryItemPath);
} catch (ValueFormatException error) {
I18n msg = JcrI18n.primaryItemNameForPrimaryTypeIsNotValid;
throw new ItemNotFoundException(msg.text(primaryType.getName(),
@@ -331,9 +349,22 @@
@Override
public boolean isSame( Item otherItem ) throws RepositoryException {
CheckArg.isNotNull(otherItem, "otherItem");
- if (super.isSame(otherItem) && otherItem instanceof Node) {
+ if (super.isSame(otherItem) && otherItem instanceof javax.jcr.Node) {
if (otherItem instanceof AbstractJcrNode) {
- return internalUuid().equals(((AbstractJcrNode)otherItem).internalUuid());
+ AbstractJcrNode that = (AbstractJcrNode)otherItem;
+ if (this.isReferenceable() && that.isReferenceable()) {
+ // Both are referenceable, so compare the UUIDs ...
+ return getUUID().equals(((AbstractJcrNode)otherItem).getUUID());
+ }
+
+ // One or both are not referenceable, so find the nearest ancestor that is referenceable.
+ // The correspondence identifier (per Section 4.10.2 of JSR-170, version 1.0.1) for a
+ // non-referenceable node is the pair of the UUID of the nearest referenceable ancestor and
+ // the relative path from that referenceable ancestor. Per Section 6.2.8, two non-referenceable
+ // nodes are the same if they have the same correspondence identifier.
+ CorrespondenceId thisId = this.getCorrespondenceId();
+ CorrespondenceId thatId = that.getCorrespondenceId();
+ return thisId.equals(thatId);
}
// If not our implementation, let the other item figure out whether we are the same.
return otherItem.isSame(this);
@@ -341,13 +372,31 @@
return false;
}
+ public CorrespondenceId getCorrespondenceId() throws RepositoryException {
+ if (this.isReferenceable()) return new CorrespondenceId(getUUID());
+ assert !this.isRoot(); // the root must be referenceable
+
+ // Find the nearest ancestor that is referenceable ...
+ Path currentPath = path();
+ AbstractJcrNode node = this.getParent();
+ int beginIndex = currentPath.size() - 1;
+ while (!node.isRoot() && !node.isReferenceable()) {
+ node = node.getParent();
+ --beginIndex;
+ }
+ // Get the relative path from the ancestor to this node ...
+ Path relativePath = currentPath.relativeTo(node.path());
+ assert !relativePath.isAbsolute();
+ return new CorrespondenceId(node.getUUID(), relativePath);
+ }
+
/**
* {@inheritDoc}
*
* @see javax.jcr.Node#hasProperties()
*/
public final boolean hasProperties() throws RepositoryException {
- return nodeInfo().hasProperties();
+ return nodeInfo().getPropertyCount() > 0;
}
/**
@@ -369,16 +418,20 @@
if (relativePath.equals(".")) return false;
if (relativePath.equals("..")) return false;
// Otherwise it should be a property on this node ...
- return cache.findPropertyInfo(new PropertyId(nodeUuid, nameFrom(relativePath))) != null;
+ return nodeInfo().getProperty(nameFrom(relativePath)) != null;
}
+ public final boolean hasProperty( Name name ) throws RepositoryException {
+ return nodeInfo().getProperty(name) != null;
+ }
+
/**
* {@inheritDoc}
*
* @see javax.jcr.Node#getProperties()
*/
public final PropertyIterator getProperties() throws RepositoryException {
- return new JcrPropertyIterator(cache.findJcrPropertiesFor(nodeUuid));
+ return new JcrPropertyIterator(cache.findJcrPropertiesFor(nodeId, location.getPath()));
}
/**
@@ -390,7 +443,7 @@
CheckArg.isNotNull(namePattern, "namePattern");
namePattern = namePattern.trim();
if (namePattern.length() == 0) return new JcrEmptyPropertyIterator();
- Collection<AbstractJcrProperty> properties = cache.findJcrPropertiesFor(nodeUuid);
+ Collection<AbstractJcrProperty> properties = cache.findJcrPropertiesFor(nodeId, location.getPath());
if ("*".equals(namePattern)) return new JcrPropertyIterator(properties);
// Figure out the patterns for each of the different disjunctions in the supplied pattern ...
@@ -433,7 +486,7 @@
if (true) throw new UnsupportedOperationException();
// This implementation is just wrong.
// Iterate through the properties to see which ones have a REFERENCE type ...
- Collection<AbstractJcrProperty> properties = cache.findJcrPropertiesFor(nodeUuid);
+ Collection<AbstractJcrProperty> properties = cache.findJcrPropertiesFor(nodeId, location.getPath());
Collection<AbstractJcrProperty> references = new LinkedList<AbstractJcrProperty>();
Iterator<AbstractJcrProperty> iter = properties.iterator();
while (iter.hasNext()) {
@@ -452,7 +505,7 @@
* @throws RepositoryException if there is an error finding the property with the supplied name
*/
public final Property getProperty( Name propertyName ) throws RepositoryException {
- return cache.findJcrProperty(new PropertyId(nodeUuid, propertyName));
+ return cache.findJcrProperty(nodeId, location.getPath(), propertyName);
}
/**
@@ -468,19 +521,30 @@
// Not a relative path ...
throw new IllegalArgumentException(JcrI18n.invalidPathParameter.text(relativePath, "relativePath"));
}
+ Name propertyName = null;
if (indexOfFirstSlash != -1) {
// We know it's a relative path with more than one segment ...
Path path = pathFrom(relativePath).getNormalizedPath();
- AbstractJcrItem item = cache.findJcrItem(nodeUuid, path);
- if (item instanceof Property) {
- return (Property)item;
+ if (path.size() > 1) {
+ try {
+ AbstractJcrItem item = cache.findJcrItem(nodeId, location.getPath(), path);
+ if (item instanceof Property) {
+ return (Property)item;
+ }
+ } catch (ItemNotFoundException e) {
+ I18n msg = JcrI18n.propertyNotFoundAtPathRelativeToReferenceNode;
+ throw new PathNotFoundException(msg.text(relativePath, getPath(), cache.workspaceName()));
+ }
+ I18n msg = JcrI18n.propertyNotFoundAtPathRelativeToReferenceNode;
+ throw new PathNotFoundException(msg.text(relativePath, getPath(), cache.workspaceName()));
}
- I18n msg = JcrI18n.propertyNotFoundAtPathRelativeToReferenceNode;
- throw new PathNotFoundException(msg.text(relativePath, getPath(), cache.workspaceName()));
+ propertyName = path.getLastSegment().getName();
+ } else {
+ propertyName = nameFrom(relativePath);
}
// It's just a name, so look for it directly ...
- Property property = getProperty(nameFrom(relativePath));
- if (property != null) return property;
+ Property result = getProperty(propertyName);
+ if (result != null) return result;
I18n msg = JcrI18n.pathNotFoundRelativeTo;
throw new PathNotFoundException(msg.text(relativePath, getPath(), cache.workspaceName()));
}
@@ -503,16 +567,19 @@
if (indexOfFirstSlash != -1) {
Path path = pathFrom(relativePath).getNormalizedPath();
try {
- AbstractJcrNode item = cache.findJcrNode(nodeUuid, path);
+ AbstractJcrNode item = cache.findJcrNode(nodeId, location.getPath(), path);
return item != null;
} catch (PathNotFoundException e) {
return false;
}
}
// It's just a name, so look for a child ...
- Path.Segment segment = segmentFrom(relativePath);
- ChildNode child = nodeInfo().getChildren().getChild(segment);
- return child != null;
+ try {
+ Path.Segment segment = segmentFrom(relativePath);
+ return nodeInfo().getChild(segment) != null;
+ } catch (org.jboss.dna.graph.property.PathNotFoundException e) {
+ return false;
+ }
}
/**
@@ -521,7 +588,7 @@
* @see javax.jcr.Node#hasNodes()
*/
public final boolean hasNodes() throws RepositoryException {
- return nodeInfo().getChildren().size() > 0;
+ return nodeInfo().getChildrenCount() > 0;
}
/**
@@ -530,7 +597,7 @@
* @throws IllegalArgumentException if <code>relativePath</code> is empty or <code>null</code>.
* @see javax.jcr.Node#getNode(java.lang.String)
*/
- public final Node getNode( String relativePath ) throws RepositoryException {
+ public final javax.jcr.Node getNode( String relativePath ) throws RepositoryException {
CheckArg.isNotEmpty(relativePath, "relativePath");
if (relativePath.equals(".")) return this;
if (relativePath.equals("..")) return this.getParent();
@@ -539,24 +606,36 @@
// Not a relative path ...
throw new IllegalArgumentException(JcrI18n.invalidPathParameter.text(relativePath, "relativePath"));
}
+ Path.Segment segment = null;
if (indexOfFirstSlash != -1) {
// We know it's a relative path with more than one segment ...
Path path = pathFrom(relativePath).getNormalizedPath();
- AbstractJcrItem item = cache.findJcrItem(nodeUuid, path);
- if (item instanceof Node) {
- return (Node)item;
+ if (path.size() == 1) {
+ if (path.getLastSegment().isSelfReference()) return this;
+ if (path.getLastSegment().isParentReference()) return this.getParent();
}
- I18n msg = JcrI18n.nodeNotFoundAtPathRelativeToReferenceNode;
- throw new PathNotFoundException(msg.text(relativePath, getPath(), cache.workspaceName()));
+ // We know it's a resolved relative path with more than one segment ...
+ if (path.size() > 1) {
+ AbstractJcrItem item = cache.findJcrNode(nodeId, location.getPath(), path);
+ if (item instanceof javax.jcr.Node) {
+ return (javax.jcr.Node)item;
+ }
+ I18n msg = JcrI18n.nodeNotFoundAtPathRelativeToReferenceNode;
+ throw new PathNotFoundException(msg.text(relativePath, getPath(), cache.workspaceName()));
+ }
+ segment = path.getLastSegment();
+ } else {
+ segment = segmentFrom(relativePath);
}
// It's just a name, so look for a child ...
- Path.Segment segment = segmentFrom(relativePath);
- ChildNode child = nodeInfo().getChildren().getChild(segment);
- if (child != null) {
- return cache.findJcrNode(child.getUuid());
+ try {
+ return nodeInfo().getChild(segment).getPayload().getJcrNode();
+ } catch (org.jboss.dna.graph.property.PathNotFoundException e) {
+ String msg = JcrI18n.childNotFoundUnderNode.text(segment, getPath(), cache.workspaceName());
+ throw new PathNotFoundException(msg);
+ } catch (RepositorySourceException e) {
+ throw new RepositoryException(e.getLocalizedMessage(), e);
}
- String msg = JcrI18n.childNotFoundUnderNode.text(segment, getPath(), cache.workspaceName());
- throw new PathNotFoundException(msg);
}
/**
@@ -565,11 +644,15 @@
* @see javax.jcr.Node#getNodes()
*/
public final NodeIterator getNodes() throws RepositoryException {
- Children children = nodeInfo().getChildren();
- if (children.size() == 0) {
+ int childCount = nodeInfo().getChildrenCount();
+ if (childCount == 0) {
return new JcrEmptyNodeIterator();
}
- return new JcrChildNodeIterator(cache, children, children.size());
+ List<AbstractJcrNode> matchingChildren = new LinkedList<AbstractJcrNode>();
+ for (Node<JcrNodePayload, JcrPropertyPayload> child : nodeInfo().getChildren()) {
+ matchingChildren.add(child.getPayload().getJcrNode());
+ }
+ return new JcrChildNodeIterator(matchingChildren, childCount);
}
/**
@@ -585,11 +668,10 @@
List<Object> patterns = createPatternsFor(namePattern);
// Implementing exact-matching only for now to prototype types as properties
- Children children = nodeInfo().getChildren();
- List<ChildNode> matchingChildren = new LinkedList<ChildNode>();
+ List<AbstractJcrNode> matchingChildren = new LinkedList<AbstractJcrNode>();
NamespaceRegistry registry = namespaces();
boolean foundMatch = false;
- for (ChildNode child : children) {
+ for (Node<JcrNodePayload, JcrPropertyPayload> child : nodeInfo().getChildren()) {
String childName = child.getName().getString(registry);
for (Object patternOrMatch : patterns) {
if (patternOrMatch instanceof Pattern) {
@@ -601,12 +683,12 @@
}
if (foundMatch) {
foundMatch = false;
- matchingChildren.add(child);
+ matchingChildren.add(child.getPayload().getJcrNode());
break;
}
}
}
- return new JcrChildNodeIterator(cache, matchingChildren, matchingChildren.size());
+ return new JcrChildNodeIterator(matchingChildren, matchingChildren.size());
}
/**
@@ -685,8 +767,10 @@
// Check for any existing properties based on residual definitions that conflict
// ------------------------------------------------------------------------------
for (JcrPropertyDefinition propertyDefinition : mixinCandidateType.propertyDefinitions()) {
- AbstractJcrProperty existingProp = cache.findJcrProperty(new PropertyId(nodeUuid,
- propertyDefinition.getInternalName()));
+ if (!hasProperty(propertyDefinition.getInternalName())) continue;
+ AbstractJcrProperty existingProp = cache.findJcrProperty(nodeId,
+ location.getPath(),
+ propertyDefinition.getInternalName());
if (existingProp != null) {
if (propertyDefinition.isMultiple()) {
if (!propertyDefinition.canCastToTypeAndSatisfyConstraints(existingProp.getValues())) {
@@ -710,14 +794,12 @@
for (Name nodeName : mixinChildNodeNames) {
// Need to figure out if the child node requires an SNS definition
- int snsCount = nodeInfo().getChildren().getCountOfSameNameSiblingsWithName(nodeName);
-
- for (Iterator<ChildNode> iter = nodeInfo().getChildren().getChildren(nodeName); iter.hasNext();) {
- AbstractJcrNode childNode = cache.findJcrNode(iter.next().getUuid());
+ int snsCount = nodeInfo().getChildrenCount(nodeName);
+ for (Node<JcrNodePayload, JcrPropertyPayload> child : nodeInfo().getChildren(nodeName)) {
JcrNodeDefinition match = this.cache.nodeTypes().findChildNodeDefinition(mixinCandidateType.getInternalName(),
Collections.<Name>emptyList(),
nodeName,
- childNode.getPrimaryNodeType().getInternalName(),
+ child.getPayload().getPrimaryTypeName(),
snsCount,
false);
@@ -860,7 +942,7 @@
for (NodeIterator iter = getNodes(); iter.hasNext();) {
AbstractJcrNode node = (AbstractJcrNode)iter.nextNode();
Name childNodeName = cache.nameFactory.create(node.getName());
- int snsCount = node.nodeInfo().getChildren().getCountOfSameNameSiblingsWithName(childNodeName);
+ int snsCount = node.nodeInfo().getChildrenCount(childNodeName);
if (mixinName.equals(node.getDefinition().getDeclaringNodeType().getName())) {
// Only the residual definition would work - if there were any other definition for this name,
// the mixin type would not have been added due to the conflict
@@ -877,8 +959,7 @@
}
}
- cache.findJcrProperty(editor().setProperty(JcrLexicon.MIXIN_TYPES, newMixinValues, PropertyType.NAME, false));
-
+ editor().setProperty(JcrLexicon.MIXIN_TYPES, newMixinValues, PropertyType.NAME, false);
}
/**
@@ -886,10 +967,10 @@
*
* @see javax.jcr.Node#addNode(java.lang.String)
*/
- public final Node addNode( String relPath )
+ public final javax.jcr.Node addNode( String relPath )
throws ItemExistsException, PathNotFoundException, VersionException, ConstraintViolationException, LockException,
RepositoryException {
- return addNode(relPath, null);
+ return addNode(relPath, null, null);
}
/**
@@ -897,8 +978,8 @@
*
* @see javax.jcr.Node#addNode(java.lang.String, java.lang.String)
*/
- public final Node addNode( String relPath,
- String primaryNodeTypeName )
+ public final javax.jcr.Node addNode( String relPath,
+ String primaryNodeTypeName )
throws ItemExistsException, PathNotFoundException, VersionException, ConstraintViolationException, LockException,
RepositoryException {
return this.addNode(relPath, primaryNodeTypeName, null);
@@ -940,17 +1021,17 @@
if (path.getLastSegment().getIndex() > 1 || relPath.endsWith("]")) {
throw new RepositoryException(JcrI18n.invalidPathParameter.text(relPath, "relPath"));
}
- if (path.size() != 1) {
+ if (path.size() > 1) {
// The only segment in the path is the child name ...
- NodeInfo parentInfo = null;
Path parentPath = path.getParent();
try {
- parentInfo = cache.findNodeInfo(nodeUuid, parentPath); // throws PathNotFoundException
- editor = cache.getEditorFor(parentInfo.getUuid());
- } catch (PathNotFoundException e) {
+ // Find the parent node ...
+ Node<JcrNodePayload, JcrPropertyPayload> parentOfNewNode = cache.findNode(nodeId, location.getPath(), parentPath);
+ editor = cache.getEditorFor(parentOfNewNode);
+ } catch (RepositoryException e) {
// We're going to throw an exception ... the question is which one ...
try {
- NodeInfo grandparentInfo;
+ Node<JcrNodePayload, JcrPropertyPayload> grandparent;
if (parentPath.size() > 1) {
// Per the TCK, if relPath references a property, then we have to throw a ConstraintViolationException
// So, if we can't find the parent, try for the parent's parent and see if the last segment of the
@@ -959,12 +1040,13 @@
Path grandparentPath = parentPath.getParent();
assert grandparentPath != null;
- grandparentInfo = cache.findNodeInfo(nodeUuid, grandparentPath); // throws PathNotFoundException
+ grandparent = cache.findNode(nodeId, location.getPath(), grandparentPath); // throws
+ // PathNotFoundException
} else {
- grandparentInfo = this.nodeInfo();
+ grandparent = this.nodeInfo();
}
- if (grandparentInfo.getProperty(parentPath.getLastSegment().getName()) != null) {
+ if (grandparent.getProperty(parentPath.getLastSegment().getName()) != null) {
// Need to throw a ConstraintViolationException since the request was to add a child to
// a property ...
throw new ConstraintViolationException(JcrI18n.invalidPathParameter.text(relPath, "relPath"));
@@ -994,13 +1076,11 @@
}
// Create the child ...
- ChildNode child = editor.createChild(childName, desiredUuid, childPrimaryTypeName);
- return cache.findJcrNode(child.getUuid());
+ return editor.createChild(childName, desiredUuid, childPrimaryTypeName);
}
protected final Property removeExistingValuedProperty( String name ) throws ConstraintViolationException, RepositoryException {
- PropertyId id = new PropertyId(nodeUuid, nameFrom(name));
- AbstractJcrProperty property = cache.findJcrProperty(id);
+ AbstractJcrProperty property = cache.findJcrProperty(nodeId, location.getPath(), nameFrom(name));
if (property != null) {
property.remove();
return property;
@@ -1017,7 +1097,7 @@
public final Property setProperty( String name,
boolean value )
throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException {
- return cache.findJcrProperty(editor().setProperty(nameFrom(name), valueFrom(PropertyType.BOOLEAN, value)));
+ return editor().setProperty(nameFrom(name), valueFrom(PropertyType.BOOLEAN, value));
}
/**
@@ -1033,7 +1113,7 @@
return removeExistingValuedProperty(name);
}
- return cache.findJcrProperty(editor().setProperty(nameFrom(name), valueFrom(value)));
+ return editor().setProperty(nameFrom(name), valueFrom(value));
}
/**
@@ -1044,7 +1124,7 @@
public final Property setProperty( String name,
double value )
throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException {
- return cache.findJcrProperty(editor().setProperty(nameFrom(name), valueFrom(PropertyType.DOUBLE, value)));
+ return editor().setProperty(nameFrom(name), valueFrom(PropertyType.DOUBLE, value));
}
/**
@@ -1059,7 +1139,7 @@
return removeExistingValuedProperty(name);
}
- return cache.findJcrProperty(editor().setProperty(nameFrom(name), valueFrom(value)));
+ return editor().setProperty(nameFrom(name), valueFrom(value));
}
/**
@@ -1070,7 +1150,7 @@
public final Property setProperty( String name,
long value )
throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException {
- return cache.findJcrProperty(editor().setProperty(nameFrom(name), valueFrom(PropertyType.LONG, value)));
+ return editor().setProperty(nameFrom(name), valueFrom(PropertyType.LONG, value));
}
/**
@@ -1079,13 +1159,13 @@
* @see javax.jcr.Node#setProperty(java.lang.String, javax.jcr.Node)
*/
public final Property setProperty( String name,
- Node value )
+ javax.jcr.Node value )
throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException {
if (value == null) {
return removeExistingValuedProperty(name);
}
- return cache.findJcrProperty(editor().setProperty(nameFrom(name), valueFrom(value)));
+ return editor().setProperty(nameFrom(name), valueFrom(value));
}
/**
@@ -1100,7 +1180,7 @@
return removeExistingValuedProperty(name);
}
- return cache.findJcrProperty(editor().setProperty(nameFrom(name), valueFrom(PropertyType.STRING, value)));
+ return editor().setProperty(nameFrom(name), valueFrom(PropertyType.STRING, value));
}
/**
@@ -1116,7 +1196,7 @@
return removeExistingValuedProperty(name);
}
- return cache.findJcrProperty(editor().setProperty(nameFrom(name), valueFrom(type, value)));
+ return editor().setProperty(nameFrom(name), valueFrom(type, value));
}
/**
@@ -1131,9 +1211,7 @@
return removeExistingValuedProperty(name);
}
- return cache.findJcrProperty(editor().setProperty(nameFrom(name),
- valuesFrom(PropertyType.STRING, values),
- PropertyType.UNDEFINED));
+ return editor().setProperty(nameFrom(name), valuesFrom(PropertyType.STRING, values), PropertyType.UNDEFINED);
}
/**
@@ -1149,7 +1227,7 @@
return removeExistingValuedProperty(name);
}
- return cache.findJcrProperty(editor().setProperty(nameFrom(name), valuesFrom(type, values), PropertyType.UNDEFINED));
+ return editor().setProperty(nameFrom(name), valuesFrom(type, values), PropertyType.UNDEFINED);
}
/**
@@ -1164,7 +1242,7 @@
return removeExistingValuedProperty(name);
}
- return cache.findJcrProperty(editor().setProperty(nameFrom(name), (JcrValue)value));
+ return editor().setProperty(nameFrom(name), (JcrValue)value);
}
/**
@@ -1180,7 +1258,7 @@
return removeExistingValuedProperty(name);
}
- return cache.findJcrProperty(editor().setProperty(nameFrom(name), ((JcrValue)value).asType(type)));
+ return editor().setProperty(nameFrom(name), ((JcrValue)value).asType(type));
}
/**
@@ -1214,7 +1292,7 @@
}
// Set the value, perhaps to an empty array ...
- return cache.findJcrProperty(editor().setProperty(nameFrom(name), values, type));
+ return editor().setProperty(nameFrom(name), values, type);
}
/**
@@ -1305,7 +1383,9 @@
*/
public final boolean isModified() {
try {
- return nodeInfo().isModified();
+ Node<JcrNodePayload, JcrPropertyPayload> node = nodeInfo();
+ // Considered modified if *not* new but changed
+ return !node.isNew() && node.isChanged(true);
} catch (RepositoryException re) {
throw new IllegalStateException(re);
}
@@ -1356,68 +1436,41 @@
}
/**
- * Obtain the corresponding node path from the supplied workspace name.
+ * {@inheritDoc}
*
- * @param workspaceName
- * @return the path of the corresponding node in the supplied workspace
- * @throws NoSuchWorkspaceException if the workspace does not exist
- * @throws ItemNotFoundException if there is no corresponding node in the supplied workspace
- * @throws RepositoryException if there is another problem
+ * @see javax.jcr.Node#getCorrespondingNodePath(java.lang.String)
*/
- final Path correspondingNodePathFrom( String workspaceName )
+ public final String getCorrespondingNodePath( String workspaceName )
throws NoSuchWorkspaceException, ItemNotFoundException, RepositoryException {
-
- assert workspaceName != null;
-
+ CheckArg.isNotNull(workspaceName, "workspace name");
NamespaceRegistry namespaces = this.context().getNamespaceRegistry();
+ // Find the closest ancestor (including this node) that is referenceable ...
AbstractJcrNode referenceableRoot = this;
while (!referenceableRoot.isNodeType(JcrMixLexicon.REFERENCEABLE.getString(namespaces))) {
referenceableRoot = referenceableRoot.getParent();
}
- UUID uuid = referenceableRoot.internalUuid();
+ // Find the relative path from the nearest referenceable node to this node (or null if this node is referenceable) ...
Path relativePath = path().equals(referenceableRoot.path()) ? null : path().relativeTo(referenceableRoot.path());
-
- Path correspondingPath = this.cache.getPathFor(workspaceName, uuid, relativePath);
-
- try {
- this.session().checkPermission(workspaceName, correspondingPath, "read");
- } catch (AccessControlException ace) {
- throw new AccessDeniedException(ace);
- }
-
- return correspondingPath;
+ UUID uuid = UUID.fromString(referenceableRoot.getUUID());
+ return this.cache.getPathForCorrespondingNode(workspaceName, uuid, relativePath).getString(namespaces);
}
/**
* {@inheritDoc}
*
- * @see javax.jcr.Node#getCorrespondingNodePath(java.lang.String)
- */
- public final String getCorrespondingNodePath( String workspaceName )
- throws NoSuchWorkspaceException, ItemNotFoundException, RepositoryException {
-
- CheckArg.isNotNull(workspaceName, "workspace name");
- return correspondingNodePathFrom(workspaceName).getString(this.namespaces());
- }
-
- /**
- * {@inheritDoc}
- *
* @see javax.jcr.Node#update(java.lang.String)
*/
public final void update( String srcWorkspaceName ) throws NoSuchWorkspaceException, RepositoryException {
CheckArg.isNotNull(srcWorkspaceName, "workspace name");
- Path correspondingPath;
-
if (session().hasPendingChanges()) {
throw new InvalidItemStateException(JcrI18n.noPendingChangesAllowed.text());
}
try {
- correspondingPath = correspondingNodePathFrom(srcWorkspaceName);
+ getCorrespondingNodePath(srcWorkspaceName);
} catch (ItemNotFoundException infe) {
return;
}
@@ -1507,27 +1560,23 @@
}
PathFactory pathFactory = this.cache.pathFactory();
-
Path srcPath = pathFactory.create(srcChildRelPath);
- ChildNode source;
-
if (srcPath.isAbsolute() || srcPath.size() != 1) {
throw new ItemNotFoundException();
}
// getLastSegment should return the only segment, since we verified that size() == 1
Path.Segment sourceSegment = srcPath.getLastSegment();
- source = nodeInfo().getChildren().getChild(sourceSegment);
- if (source == null) {
+ try {
+ nodeInfo().getChild(sourceSegment);
+ } catch (org.jboss.dna.graph.property.PathNotFoundException e) {
String workspaceName = this.cache.session().getWorkspace().getName();
throw new ItemNotFoundException(JcrI18n.pathNotFound.text(srcPath, workspaceName));
}
- Path destPath = null;
Path.Segment destSegment = null;
- ChildNode destination = null;
if (destChildRelPath != null) {
- destPath = pathFactory.create(destChildRelPath);
+ Path destPath = pathFactory.create(destChildRelPath);
if (destPath.isAbsolute() || destPath.size() != 1) {
throw new ItemNotFoundException();
}
@@ -1535,15 +1584,15 @@
destSegment = destPath.getLastSegment();
// getLastSegment should return the only segment, since we verified that size() == 1
- destination = nodeInfo().getChildren().getChild(destSegment);
- if (destination == null) {
+ try {
+ nodeInfo().getChild(destSegment);
+ } catch (org.jboss.dna.graph.property.PathNotFoundException e) {
String workspaceName = this.cache.session().getWorkspace().getName();
throw new ItemNotFoundException(JcrI18n.pathNotFound.text(destPath, workspaceName));
}
}
this.editor().orderChildBefore(sourceSegment, destSegment);
-
}
protected static List<Object> createPatternsFor( String namePattern ) throws RepositoryException {
@@ -1609,7 +1658,7 @@
* @see javax.jcr.Item#refresh(boolean)
*/
public void refresh( boolean keepChanges ) throws RepositoryException {
- this.cache.refresh(this.nodeUuid, keepChanges);
+ this.cache.refresh(this.nodeId, keepChanges);
}
/**
@@ -1618,7 +1667,7 @@
* @see javax.jcr.Item#save()
*/
public void save() throws RepositoryException {
- cache.save(nodeUuid);
+ cache.save(nodeId, location.getPath());
}
@Override
@@ -1636,4 +1685,20 @@
return re.getMessage();
}
}
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals( Object obj ) {
+ if (obj == this) return true;
+ if (obj instanceof AbstractJcrNode) {
+ AbstractJcrNode that = (AbstractJcrNode)obj;
+ if (this.cache != that.cache) return false;
+ return this.location.equals(that.location);
+ }
+ return false;
+ }
}
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/AbstractJcrProperty.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/AbstractJcrProperty.java 2009-07-09 16:23:09 UTC (rev 1081)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/AbstractJcrProperty.java 2009-07-09 16:26:04 UTC (rev 1082)
@@ -39,26 +39,31 @@
import org.jboss.dna.common.util.CheckArg;
import org.jboss.dna.graph.property.Name;
import org.jboss.dna.graph.property.Path;
+import org.jboss.dna.graph.session.GraphSession.PropertyInfo;
+import org.jboss.dna.jcr.SessionCache.JcrPropertyPayload;
import org.jboss.dna.jcr.SessionCache.NodeEditor;
-import org.jboss.dna.jcr.cache.PropertyInfo;
/**
* @author jverhaeg
*/
@NotThreadSafe
-abstract class AbstractJcrProperty extends AbstractJcrItem implements Property {
+abstract class AbstractJcrProperty extends AbstractJcrItem implements Property, Comparable<Property> {
- protected final PropertyId propertyId;
+ protected final AbstractJcrNode node;
+ protected final Name name;
AbstractJcrProperty( SessionCache cache,
- PropertyId propertyId ) {
+ AbstractJcrNode node,
+ Name name ) {
super(cache);
- assert propertyId != null;
- this.propertyId = propertyId;
+ assert node != null;
+ assert name != null;
+ this.node = node;
+ this.name = name;
}
final NodeEditor editor() throws ItemNotFoundException, InvalidItemStateException, RepositoryException {
- return cache.getEditorFor(propertyId.getNodeId());
+ return node.editor();
}
abstract boolean isMultiple();
@@ -74,20 +79,24 @@
visitor.visit(this);
}
- final PropertyInfo propertyInfo() throws PathNotFoundException, RepositoryException {
- return cache.findPropertyInfo(propertyId);
+ final PropertyInfo<JcrPropertyPayload> propertyInfo() throws PathNotFoundException, RepositoryException {
+ return node.nodeInfo().getProperty(name);
}
- final Name name() throws RepositoryException {
- return propertyInfo().getPropertyName();
+ final Name name() {
+ return name;
}
+ final JcrPropertyPayload payload() throws RepositoryException {
+ return propertyInfo().getPayload();
+ }
+
final org.jboss.dna.graph.property.Property property() throws RepositoryException {
return propertyInfo().getProperty();
}
JcrValue createValue( Object value ) throws RepositoryException {
- return new JcrValue(context().getValueFactories(), this.cache, propertyInfo().getPropertyType(), value);
+ return new JcrValue(context().getValueFactories(), this.cache, payload().getPropertyType(), value);
}
final JcrValue createValue( Object value,
@@ -97,7 +106,7 @@
@Override
Path path() throws RepositoryException {
- return cache.getPathFor(propertyInfo());
+ return context().getValueFactories().getPathFactory().create(node.path(), name);
}
/**
@@ -106,7 +115,7 @@
* @see javax.jcr.Property#getType()
*/
public int getType() throws RepositoryException {
- return propertyInfo().getPropertyType();
+ return payload().getPropertyType();
}
/**
@@ -115,9 +124,7 @@
* @see javax.jcr.Property#getDefinition()
*/
public final PropertyDefinition getDefinition() throws RepositoryException {
- PropertyInfo info = propertyInfo();
- PropertyDefinitionId definitionId = info.getDefinitionId();
- return cache.session().nodeTypeManager().getPropertyDefinition(definitionId);
+ return cache.session().nodeTypeManager().getPropertyDefinition(payload().getPropertyDefinitionId());
}
/**
@@ -129,8 +136,8 @@
*
* @see javax.jcr.Item#getName()
*/
- public final String getName() throws RepositoryException {
- return propertyInfo().getPropertyName().getString(namespaces());
+ public final String getName() {
+ return name.getString(namespaces());
}
/**
@@ -138,8 +145,8 @@
*
* @see javax.jcr.Item#getParent()
*/
- public final Node getParent() throws RepositoryException {
- return cache.findJcrNode(propertyId.getNodeId());
+ public final Node getParent() {
+ return node;
}
/**
@@ -148,7 +155,7 @@
* @see javax.jcr.Item#getPath()
*/
public final String getPath() throws RepositoryException {
- return cache.getPathFor(propertyInfo()).getString(namespaces());
+ return path().getString(namespaces());
}
/**
@@ -159,8 +166,7 @@
public final boolean isModified() {
try {
return propertyInfo().isModified();
- }
- catch (RepositoryException re) {
+ } catch (RepositoryException re) {
throw new IllegalStateException(re);
}
}
@@ -173,8 +179,7 @@
public final boolean isNew() {
try {
return propertyInfo().isNew();
- }
- catch (RepositoryException re) {
+ } catch (RepositoryException re) {
throw new IllegalStateException(re);
}
}
@@ -222,7 +227,7 @@
* @see javax.jcr.Item#remove()
*/
public void remove() throws VersionException, LockException, ConstraintViolationException, RepositoryException {
- editor().removeProperty(propertyId.getPropertyName());
+ editor().removeProperty(name);
}
/**
@@ -234,4 +239,18 @@
public void save() {
throw new UnsupportedOperationException();
}
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Comparable#compareTo(java.lang.Object)
+ */
+ public int compareTo( Property that ) {
+ if (that == this) return 0;
+ try {
+ return this.getName().compareTo(that.getName());
+ } catch (RepositoryException e) {
+ throw new RuntimeException(e);
+ }
+ }
}
Added: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/CorrespondenceId.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/CorrespondenceId.java (rev 0)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/CorrespondenceId.java 2009-07-09 16:26:04 UTC (rev 1082)
@@ -0,0 +1,102 @@
+/*
+ * 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.jcr;
+
+import net.jcip.annotations.Immutable;
+import org.jboss.dna.common.util.CheckArg;
+import org.jboss.dna.common.util.HashCode;
+import org.jboss.dna.graph.property.Path;
+import org.jboss.dna.graph.property.basic.BasicPath;
+
+/**
+ * A correspondence identifier is defined to be the pair of the UUID of the nearest referenceable ancestor and the relative path
+ * from that referenceable ancestor to the node of interest. If any node is a referenceable node, then the correspondence
+ * identifier is just the UUID of the node. Per Section 4.10.2 of JSR-170, version 1.0.1.
+ * <p>
+ * Note that per Section 6.2.8, two non-referenceable nodes are the same if they have the same correspondence identifier.
+ * </p>
+ */
+@Immutable
+public class CorrespondenceId {
+
+ private static final Path NO_PATH = BasicPath.SELF_PATH;
+
+ private final String referenceableId;
+ private final Path relativePath;
+ private final int hc;
+
+ public CorrespondenceId( String referenceableId ) {
+ this(referenceableId, NO_PATH);
+ }
+
+ public CorrespondenceId( String referenceableId,
+ Path relativePath ) {
+ CheckArg.isNotNull(referenceableId, "referenceableId");
+ CheckArg.isNotNull(relativePath, "relativePath");
+ assert !relativePath.isAbsolute();
+ this.referenceableId = referenceableId;
+ this.relativePath = relativePath;
+ this.hc = HashCode.compute(this.referenceableId, this.relativePath);
+ }
+
+ /**
+ * @return referenceableId
+ */
+ public String getReferenceableId() {
+ return referenceableId;
+ }
+
+ /**
+ * @return relativePath
+ */
+ public Path getRelativePath() {
+ return relativePath;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ return hc;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals( Object obj ) {
+ if (obj == this) return true;
+ if (obj instanceof CorrespondenceId) {
+ CorrespondenceId that = (CorrespondenceId)obj;
+ return this.referenceableId.equals(that.referenceableId) && this.relativePath.equals(that.relativePath);
+ }
+ return false;
+ }
+
+}
Property changes on: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/CorrespondenceId.java
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrChildNodeIterator.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrChildNodeIterator.java 2009-07-09 16:23:09 UTC (rev 1081)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrChildNodeIterator.java 2009-07-09 16:26:04 UTC (rev 1082)
@@ -24,29 +24,22 @@
package org.jboss.dna.jcr;
import java.util.Iterator;
-import javax.jcr.Node;
import javax.jcr.NodeIterator;
-import javax.jcr.RepositoryException;
import net.jcip.annotations.Immutable;
import org.jboss.dna.common.util.CheckArg;
-import org.jboss.dna.jcr.cache.ChildNode;
/**
*/
@Immutable
final class JcrChildNodeIterator implements NodeIterator {
- private final SessionCache cache;
- private final Iterator<ChildNode> iterator;
+ private final Iterator<AbstractJcrNode> iterator;
private int ndx;
private int size;
- JcrChildNodeIterator( SessionCache cache,
- Iterable<ChildNode> children,
+ JcrChildNodeIterator( Iterable<AbstractJcrNode> children,
int size ) {
- assert cache != null;
assert children != null;
- this.cache = cache;
iterator = children.iterator();
this.size = size;
}
@@ -92,14 +85,10 @@
*
* @see javax.jcr.NodeIterator#nextNode()
*/
- public Node nextNode() {
- ChildNode child = iterator.next();
+ public javax.jcr.Node nextNode() {
+ AbstractJcrNode child = iterator.next();
ndx++;
- try {
- return cache.findJcrNode(child.getUuid());
- } catch (RepositoryException error) {
- throw new RuntimeException(error);
- }
+ return child;
}
/**
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrContentHandler.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrContentHandler.java 2009-07-09 16:23:09 UTC (rev 1081)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrContentHandler.java 2009-07-09 16:26:04 UTC (rev 1082)
@@ -29,15 +29,12 @@
import java.util.List;
import java.util.Map;
import java.util.Stack;
-import java.util.UUID;
import javax.jcr.ImportUUIDBehavior;
-import javax.jcr.ItemExistsException;
import javax.jcr.PathNotFoundException;
import javax.jcr.PropertyType;
import javax.jcr.RepositoryException;
import javax.jcr.Value;
import javax.jcr.ValueFormatException;
-import javax.jcr.nodetype.ConstraintViolationException;
import net.jcip.annotations.NotThreadSafe;
import org.jboss.dna.common.text.TextDecoder;
import org.jboss.dna.common.text.XmlNameEncoder;
@@ -303,57 +300,58 @@
}
private void addNodeIfPending() throws SAXException {
- if (currentNodeName != null) {
- try {
- AbstractJcrNode parentNode = parentStack.peek();
-
- UUID uuid = null;
- List<Value> rawUuid = currentProps.get(uuidName);
-
- if (rawUuid != null) {
- assert rawUuid.size() == 1;
- uuid = UUID.fromString(rawUuid.get(0).getString());
- }
-
- String typeName = currentProps.get(primaryTypeName).get(0).getString();
- AbstractJcrNode newNode = cache().findJcrNode(parentNode.editorFor(operations()).createChild(nameFor(currentNodeName),
- uuid,
- nameFor(typeName)).getUuid());
-
- for (Map.Entry<String, List<Value>> entry : currentProps.entrySet()) {
- if (entry.getKey().equals(primaryTypeName)) {
- continue;
- }
-
- if (entry.getKey().equals(mixinTypesName)) {
- for (Value value : entry.getValue()) {
- JcrNodeType mixinType = session.workspace().nodeTypeManager().getNodeType(nameFor(value.getString()));
- newNode.editorFor(operations()).addMixin(mixinType);
- }
- continue;
- }
-
- if (entry.getKey().equals(uuidName)) {
- continue;
- }
-
- List<Value> values = entry.getValue();
-
- if (values.size() == 1) {
- newNode.editorFor(operations()).setProperty(nameFor(entry.getKey()), (JcrValue)values.get(0));
- } else {
- newNode.editorFor(operations()).setProperty(nameFor(entry.getKey()),
- values.toArray(new Value[values.size()]),
- PropertyType.UNDEFINED);
- }
- }
-
- parentStack.push(newNode);
- currentProps.clear();
- } catch (RepositoryException re) {
- throw new EnclosingSAXException(re);
- }
- }
+ // if (currentNodeName != null) {
+ // try {
+ // AbstractJcrNode parentNode = parentStack.peek();
+ //
+ // UUID uuid = null;
+ // List<Value> rawUuid = currentProps.get(uuidName);
+ //
+ // if (rawUuid != null) {
+ // assert rawUuid.size() == 1;
+ // uuid = UUID.fromString(rawUuid.get(0).getString());
+ // }
+ //
+ // String typeName = currentProps.get(primaryTypeName).get(0).getString();
+ // AbstractJcrNode newNode =
+ // cache().findJcrNode(parentNode.editorFor(operations()).createChild(nameFor(currentNodeName),
+ // uuid,
+ // nameFor(typeName)).getUuid());
+ //
+ // for (Map.Entry<String, List<Value>> entry : currentProps.entrySet()) {
+ // if (entry.getKey().equals(primaryTypeName)) {
+ // continue;
+ // }
+ //
+ // if (entry.getKey().equals(mixinTypesName)) {
+ // for (Value value : entry.getValue()) {
+ // JcrNodeType mixinType = session.workspace().nodeTypeManager().getNodeType(nameFor(value.getString()));
+ // newNode.editorFor(operations()).addMixin(mixinType);
+ // }
+ // continue;
+ // }
+ //
+ // if (entry.getKey().equals(uuidName)) {
+ // continue;
+ // }
+ //
+ // List<Value> values = entry.getValue();
+ //
+ // if (values.size() == 1) {
+ // newNode.editorFor(operations()).setProperty(nameFor(entry.getKey()), (JcrValue)values.get(0));
+ // } else {
+ // newNode.editorFor(operations()).setProperty(nameFor(entry.getKey()),
+ // values.toArray(new Value[values.size()]),
+ // PropertyType.UNDEFINED);
+ // }
+ // }
+ //
+ // parentStack.push(newNode);
+ // currentProps.clear();
+ // } catch (RepositoryException re) {
+ // throw new EnclosingSAXException(re);
+ // }
+ // }
}
@Override
@@ -371,8 +369,9 @@
ByteArrayInputStream is = new ByteArrayInputStream(Base64.decode(s, Base64.URL_SAFE));
currentProps.get(currentPropName).add(session.getValueFactory().createValue(is));
} else {
- currentProps.get(currentPropName).add(session.getValueFactory().createValue(SYSTEM_VIEW_NAME_DECODER.decode(s),
- currentPropType));
+ currentProps.get(currentPropName).add(session.getValueFactory()
+ .createValue(SYSTEM_VIEW_NAME_DECODER.decode(s),
+ currentPropType));
}
} catch (RepositoryException re) {
throw new EnclosingSAXException(re);
@@ -418,70 +417,70 @@
String localName,
String name,
Attributes atts ) throws SAXException {
- try {
- String primaryTypeName = atts.getValue(JcrContentHandler.this.primaryTypeName);
- String rawUuid = atts.getValue(uuidName);
- UUID uuid = (rawUuid != null ? UUID.fromString(rawUuid) : null);
- AbstractJcrNode parentNode = parentStack.peek();
+ // try {
+ // String primaryTypeName = atts.getValue(JcrContentHandler.this.primaryTypeName);
+ // String rawUuid = atts.getValue(uuidName);
+ // UUID uuid = (rawUuid != null ? UUID.fromString(rawUuid) : null);
+ // AbstractJcrNode parentNode = parentStack.peek();
+ //
+ // if (uuid != null) {
+ // AbstractJcrNode existingNodeWithUuid = (AbstractJcrNode)session.getNodeByUUID(rawUuid);
+ // if (existingNodeWithUuid != null) {
+ // switch (uuidBehavior) {
+ // case ImportUUIDBehavior.IMPORT_UUID_COLLISION_REPLACE_EXISTING:
+ // parentNode = existingNodeWithUuid.getParent();
+ // parentNode.editorFor(operations()).destroyChild(uuid);
+ // break;
+ // case ImportUUIDBehavior.IMPORT_UUID_CREATE_NEW:
+ // uuid = UUID.randomUUID();
+ // break;
+ // case ImportUUIDBehavior.IMPORT_UUID_COLLISION_REMOVE_EXISTING:
+ // if (existingNodeWithUuid.path().isAtOrAbove(parentStack.firstElement().path())) {
+ // throw new ConstraintViolationException();
+ // }
+ // AbstractJcrNode temp = existingNodeWithUuid.getParent();
+ // temp.editorFor(operations()).destroyChild(uuid);
+ // break;
+ // case ImportUUIDBehavior.IMPORT_UUID_COLLISION_THROW:
+ // throw new ItemExistsException();
+ // }
+ // }
+ // }
+ //
+ // name = DOCUMENT_VIEW_NAME_DECODER.decode(name);
+ // AbstractJcrNode currentNode = cache().findJcrNode(parentNode.editorFor(operations()).createChild(nameFor(name),
+ // uuid,
+ // nameFor(primaryTypeName)).getUuid());
+ //
+ // for (int i = 0; i < atts.getLength(); i++) {
+ // if (JcrContentHandler.this.primaryTypeName.equals(atts.getQName(i))) {
+ // continue;
+ // }
+ //
+ // if (mixinTypesName.equals(atts.getQName(i))) {
+ // JcrNodeType mixinType = session.workspace().nodeTypeManager().getNodeType(nameFor(atts.getValue(i)));
+ // currentNode.editorFor(operations()).addMixin(mixinType);
+ // continue;
+ // }
+ //
+ // if (uuidName.equals(atts.getQName(i))) {
+ // continue;
+ // }
+ //
+ // // We may want to use the workspace context here so that we only use the permanent namespace mappings
+ // // Name propName = session.executionContext.getValueFactories().getNameFactory().create(atts.getQName(i));
+ // // String value = DOCUMENT_VIEW_NAME_DECODER.decode(atts.getValue(i));
+ // String value = atts.getValue(i);
+ // String propertyName = DOCUMENT_VIEW_NAME_DECODER.decode(atts.getQName(i));
+ // currentNode.editorFor(operations()).setProperty(nameFor(propertyName),
+ // (JcrValue)valueFor(value, PropertyType.STRING));
+ // }
+ //
+ // parentStack.push(currentNode);
+ // } catch (RepositoryException re) {
+ // throw new EnclosingSAXException(re);
+ // }
- if (uuid != null) {
- AbstractJcrNode existingNodeWithUuid = (AbstractJcrNode)session.getNodeByUUID(rawUuid);
- if (existingNodeWithUuid != null) {
- switch (uuidBehavior) {
- case ImportUUIDBehavior.IMPORT_UUID_COLLISION_REPLACE_EXISTING:
- parentNode = existingNodeWithUuid.getParent();
- parentNode.editorFor(operations()).destroyChild(uuid);
- break;
- case ImportUUIDBehavior.IMPORT_UUID_CREATE_NEW:
- uuid = UUID.randomUUID();
- break;
- case ImportUUIDBehavior.IMPORT_UUID_COLLISION_REMOVE_EXISTING:
- if (existingNodeWithUuid.path().isAtOrAbove(parentStack.firstElement().path())) {
- throw new ConstraintViolationException();
- }
- AbstractJcrNode temp = existingNodeWithUuid.getParent();
- temp.editorFor(operations()).destroyChild(uuid);
- break;
- case ImportUUIDBehavior.IMPORT_UUID_COLLISION_THROW:
- throw new ItemExistsException();
- }
- }
- }
-
- name = DOCUMENT_VIEW_NAME_DECODER.decode(name);
- AbstractJcrNode currentNode = cache().findJcrNode(parentNode.editorFor(operations()).createChild(nameFor(name),
- uuid,
- nameFor(primaryTypeName)).getUuid());
-
- for (int i = 0; i < atts.getLength(); i++) {
- if (JcrContentHandler.this.primaryTypeName.equals(atts.getQName(i))) {
- continue;
- }
-
- if (mixinTypesName.equals(atts.getQName(i))) {
- JcrNodeType mixinType = session.workspace().nodeTypeManager().getNodeType(nameFor(atts.getValue(i)));
- currentNode.editorFor(operations()).addMixin(mixinType);
- continue;
- }
-
- if (uuidName.equals(atts.getQName(i))) {
- continue;
- }
-
- // We may want to use the workspace context here so that we only use the permanent namespace mappings
- // Name propName = session.executionContext.getValueFactories().getNameFactory().create(atts.getQName(i));
- // String value = DOCUMENT_VIEW_NAME_DECODER.decode(atts.getValue(i));
- String value = atts.getValue(i);
- String propertyName = DOCUMENT_VIEW_NAME_DECODER.decode(atts.getQName(i));
- currentNode.editorFor(operations()).setProperty(nameFor(propertyName),
- (JcrValue)valueFor(value, PropertyType.STRING));
- }
-
- parentStack.push(currentNode);
- } catch (RepositoryException re) {
- throw new EnclosingSAXException(re);
- }
-
}
@Override
@@ -500,19 +499,20 @@
public void characters( char[] ch,
int start,
int length ) throws SAXException {
- try {
- AbstractJcrNode parentNode = parentStack.peek();
- AbstractJcrNode currentNode = cache().findJcrNode(parentNode.editorFor(operations()).createChild(JcrLexicon.XMLTEXT,
- null,
- JcrNtLexicon.UNSTRUCTURED).getUuid());
-
- String s = new String(ch, start, length);
- currentNode.editorFor(operations()).setProperty(JcrLexicon.XMLCHARACTERS,
- (JcrValue)valueFor(s, PropertyType.STRING));
-
- } catch (RepositoryException re) {
- throw new EnclosingSAXException(re);
- }
+ // try {
+ // AbstractJcrNode parentNode = parentStack.peek();
+ // AbstractJcrNode currentNode =
+ // cache().findJcrNode(parentNode.editorFor(operations()).createChild(JcrLexicon.XMLTEXT,
+ // null,
+ // JcrNtLexicon.UNSTRUCTURED).getUuid());
+ //
+ // String s = new String(ch, start, length);
+ // currentNode.editorFor(operations()).setProperty(JcrLexicon.XMLCHARACTERS,
+ // (JcrValue)valueFor(s, PropertyType.STRING));
+ //
+ // } catch (RepositoryException re) {
+ // throw new EnclosingSAXException(re);
+ // }
}
}
}
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrI18n.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrI18n.java 2009-07-09 16:23:09 UTC (rev 1081)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrI18n.java 2009-07-09 16:26:04 UTC (rev 1082)
@@ -47,7 +47,7 @@
public static I18n fileDoesNotExist;
public static I18n rootNodeHasNoParent;
-
+
public static I18n noNamespaceWithPrefix;
public static I18n noNamespaceWithUri;
public static I18n unableToChangeTheDefaultNamespace;
@@ -87,7 +87,8 @@
public static I18n unableToSaveNodeThatWasCreatedSincePreviousSave;
public static I18n unableToSetMultiValuedPropertyUsingSingleValue;
public static I18n unableToSetSingleValuedPropertyUsingMultipleValues;
- public static I18n unableToRefreshBranchSinceAtLeastOneNodeMovedToParentOutsideOfBranch;
+ public static I18n unableToRefreshBranchBecauseChangesDependOnChangesToNodesOutsideOfBranch;
+ public static I18n unableToSaveBranchBecauseChangesDependOnChangesToNodesOutsideOfBranch;
public static I18n allPropertyValuesMustHaveSameType;
public static I18n cannotRemoveNodeFromClone;
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrMultiValueProperty.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrMultiValueProperty.java 2009-07-09 16:23:09 UTC (rev 1081)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrMultiValueProperty.java 2009-07-09 16:26:04 UTC (rev 1082)
@@ -37,6 +37,7 @@
import javax.jcr.nodetype.ConstraintViolationException;
import javax.jcr.version.VersionException;
import net.jcip.annotations.NotThreadSafe;
+import org.jboss.dna.graph.property.Name;
import org.jboss.dna.graph.property.Property;
/**
@@ -48,8 +49,9 @@
static final JcrValue[] EMPTY_VALUES = new JcrValue[] {};
JcrMultiValueProperty( SessionCache cache,
- PropertyId propertyId ) {
- super(cache, propertyId);
+ AbstractJcrNode node,
+ Name name ) {
+ super(cache, node, name);
}
/**
@@ -191,10 +193,10 @@
for (int i = 0; i < values.length; i++) {
// Force a conversion as per SetValueValueFormatExceptionTest in JR TCK
- if (values[i] != null) ((JcrValue) values[i]).asType(this.getType());
+ if (values[i] != null) ((JcrValue)values[i]).asType(this.getType());
}
-
- cache.getEditorFor(propertyId.getNodeId()).setProperty(propertyId.getPropertyName(), values, PropertyType.UNDEFINED);
+
+ editor().setProperty(name(), values, PropertyType.UNDEFINED);
}
/**
@@ -228,7 +230,7 @@
jcrValues = EMPTY_VALUES;
}
- cache.getEditorFor(propertyId.getNodeId()).setProperty(propertyId.getPropertyName(), jcrValues, this.getType());
+ editor().setProperty(name(), jcrValues, this.getType());
}
/**
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNode.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNode.java 2009-07-09 16:23:09 UTC (rev 1081)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNode.java 2009-07-09 16:26:04 UTC (rev 1082)
@@ -23,10 +23,11 @@
*/
package org.jboss.dna.jcr;
-import java.util.UUID;
import javax.jcr.ItemNotFoundException;
import javax.jcr.RepositoryException;
import net.jcip.annotations.NotThreadSafe;
+import org.jboss.dna.graph.Location;
+import org.jboss.dna.graph.session.GraphSession.NodeId;
/**
*
@@ -35,8 +36,9 @@
final class JcrNode extends AbstractJcrNode {
JcrNode( SessionCache cache,
- UUID nodeUuid ) {
- super(cache, nodeUuid);
+ NodeId nodeId,
+ Location location ) {
+ super(cache, nodeId, location);
}
/**
@@ -55,7 +57,7 @@
* @see javax.jcr.Node#getIndex()
*/
public int getIndex() throws RepositoryException {
- return cache.getSnsIndexOf(nodeUuid);
+ return segment().getIndex();
}
/**
@@ -64,7 +66,7 @@
* @see javax.jcr.Item#getName()
*/
public String getName() throws RepositoryException {
- return cache.getNameOf(nodeUuid).getString(namespaces());
+ return name().getString(namespaces());
}
/**
@@ -74,7 +76,7 @@
*/
@Override
public AbstractJcrNode getParent() throws ItemNotFoundException, RepositoryException {
- return cache.findJcrNode(nodeInfo().getParent());
+ return nodeInfo().getParent().getPayload().getJcrNode();
}
/**
@@ -83,7 +85,7 @@
* @see javax.jcr.Item#getPath()
*/
public String getPath() throws RepositoryException {
- return cache.getPathFor(nodeUuid).getString(namespaces());
+ return nodeInfo().getPath().getString(namespaces());
}
/**
@@ -92,6 +94,6 @@
* @see javax.jcr.Item#remove()
*/
public void remove() throws RepositoryException {
- editorForParent().destroyChild(nodeUuid);
+ editorForParent().destroyChild(nodeInfo());
}
}
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNodeType.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNodeType.java 2009-07-09 16:23:09 UTC (rev 1081)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNodeType.java 2009-07-09 16:26:04 UTC (rev 1082)
@@ -490,7 +490,22 @@
return this.thisAndAllSupertypesNames.contains(nodeTypeName);
}
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
@Override
+ public boolean equals( Object obj ) {
+ if (obj == this) return true;
+ if (obj instanceof NodeType) {
+ NodeType that = (NodeType)obj;
+ return this.getName().equals(that.getName());
+ }
+ return false;
+ }
+
+ @Override
public String toString() {
return getName();
}
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrPropertyDefinition.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrPropertyDefinition.java 2009-07-09 16:23:09 UTC (rev 1081)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrPropertyDefinition.java 2009-07-09 16:26:04 UTC (rev 1082)
@@ -32,6 +32,7 @@
import javax.jcr.nodetype.PropertyDefinition;
import net.jcip.annotations.Immutable;
import org.jboss.dna.graph.ExecutionContext;
+import org.jboss.dna.graph.Location;
import org.jboss.dna.graph.property.Binary;
import org.jboss.dna.graph.property.DateTime;
import org.jboss.dna.graph.property.Name;
@@ -310,7 +311,7 @@
throw new IllegalStateException("Invalid property type: " + type);
}
}
-
+
@Override
public int hashCode() {
return getId().toString().hashCode();
@@ -327,7 +328,6 @@
} else if (!id.equals(other.id)) return false;
return true;
}
-
/**
* Interface that encapsulates a reusable method that can test values to determine if they match a specific list of
@@ -564,7 +564,7 @@
Node node = null;
try {
UUID uuid = cache.factories().getUuidFactory().create(jcrValue.value());
- node = cache.findJcrNode(uuid);
+ node = cache.findJcrNode(Location.create(uuid));
} catch (RepositoryException re) {
return false;
}
@@ -608,7 +608,12 @@
JcrValue jcrValue = (JcrValue)value;
// Need to use the session execution context to handle the remaps
- Name name = jcrValue.sessionCache().session().getExecutionContext().getValueFactories().getNameFactory().create(jcrValue.value());
+ Name name = jcrValue.sessionCache()
+ .session()
+ .getExecutionContext()
+ .getValueFactories()
+ .getNameFactory()
+ .create(jcrValue.value());
for (int i = 0; i < constraints.length; i++) {
if (constraints[i].equals(name)) {
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrRootNode.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrRootNode.java 2009-07-09 16:23:09 UTC (rev 1081)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrRootNode.java 2009-07-09 16:26:04 UTC (rev 1082)
@@ -23,12 +23,13 @@
*/
package org.jboss.dna.jcr;
-import java.util.UUID;
import javax.jcr.Item;
import javax.jcr.ItemNotFoundException;
import javax.jcr.RepositoryException;
import javax.jcr.nodetype.ConstraintViolationException;
import net.jcip.annotations.NotThreadSafe;
+import org.jboss.dna.graph.Location;
+import org.jboss.dna.graph.session.GraphSession.NodeId;
/**
* @author jverhaeg
@@ -37,8 +38,9 @@
final class JcrRootNode extends AbstractJcrNode {
JcrRootNode( SessionCache cache,
- UUID nodeUuid ) {
- super(cache, nodeUuid);
+ NodeId nodeId,
+ Location location ) {
+ super(cache, nodeId, location);
}
/**
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrSession.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrSession.java 2009-07-09 16:23:09 UTC (rev 1081)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrSession.java 2009-07-09 16:26:04 UTC (rev 1082)
@@ -53,10 +53,10 @@
import org.jboss.dna.common.util.CheckArg;
import org.jboss.dna.graph.ExecutionContext;
import org.jboss.dna.graph.Graph;
+import org.jboss.dna.graph.Location;
import org.jboss.dna.graph.SecurityContext;
import org.jboss.dna.graph.property.Binary;
import org.jboss.dna.graph.property.DateTime;
-import org.jboss.dna.graph.property.Name;
import org.jboss.dna.graph.property.NamespaceRegistry;
import org.jboss.dna.graph.property.Path;
import org.jboss.dna.graph.property.PathFactory;
@@ -480,14 +480,11 @@
if (path.getLastSegment().hasIndex()) {
return getNode(path);
}
- // We can't tell from the name, so try a node first ...
+ // We can't tell from the name, so ask for an item ...
try {
- return getNode(path);
- } catch (PathNotFoundException e) {
- // A node was not found, so look for a node using the parent as the node's path ...
- Path parentPath = path.getParent();
- Name propertyName = path.getLastSegment().getName();
- return getNode(parentPath).getProperty(propertyName.getString(namespaces()));
+ return cache.findJcrItem(null, rootPath, path.relativeTo(rootPath));
+ } catch (ItemNotFoundException e) {
+ throw new PathNotFoundException(e.getMessage(), e);
}
}
@@ -511,7 +508,11 @@
*/
AbstractJcrNode getNode( Path path ) throws RepositoryException, PathNotFoundException {
if (path.isRoot()) return cache.findJcrRootNode();
- return cache.findJcrNode(null, path.relativeTo(rootPath));
+ try {
+ return cache.findJcrNode(null, path);
+ } catch (ItemNotFoundException e) {
+ throw new PathNotFoundException(e.getMessage());
+ }
}
/**
@@ -520,7 +521,7 @@
* @see javax.jcr.Session#getNodeByUUID(java.lang.String)
*/
public Node getNodeByUUID( String uuid ) throws ItemNotFoundException, RepositoryException {
- return cache.findJcrNode(UUID.fromString(uuid));
+ return cache.findJcrNode(Location.create(UUID.fromString(uuid)));
}
/**
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrSingleValueProperty.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrSingleValueProperty.java 2009-07-09 16:23:09 UTC (rev 1081)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrSingleValueProperty.java 2009-07-09 16:26:04 UTC (rev 1082)
@@ -34,7 +34,9 @@
import javax.jcr.lock.LockException;
import javax.jcr.nodetype.ConstraintViolationException;
import javax.jcr.version.VersionException;
+import org.jboss.dna.graph.Location;
import org.jboss.dna.graph.property.Binary;
+import org.jboss.dna.graph.property.Name;
import org.jboss.dna.graph.property.Reference;
import org.jboss.dna.graph.property.ValueFactories;
@@ -44,8 +46,9 @@
final class JcrSingleValueProperty extends AbstractJcrProperty {
JcrSingleValueProperty( SessionCache cache,
- PropertyId propertyId ) {
- super(cache, propertyId);
+ AbstractJcrNode node,
+ Name name ) {
+ super(cache, node, name);
}
/**
@@ -139,7 +142,7 @@
ValueFactories factories = context().getValueFactories();
Reference dnaReference = factories.getReferenceFactory().create(property().getFirstValue());
UUID uuid = factories.getUuidFactory().create(dnaReference);
- return cache.findJcrNode(uuid);
+ return cache.findJcrNode(Location.create(uuid));
} catch (org.jboss.dna.graph.property.ValueFormatException e) {
throw new ValueFormatException(e.getMessage(), e);
}
@@ -194,16 +197,16 @@
// Force a conversion as per SetValueValueFormatExceptionTest in JR TCK
jcrValue.asType(this.getType());
-
- cache.getEditorFor(propertyId.getNodeId()).setProperty(propertyId.getPropertyName(), jcrValue);
+
+ editor().setProperty(name(), jcrValue);
return;
}
if (value == null) {
// Then we're to delete the property ...
- cache.getEditorFor(propertyId.getNodeId()).removeProperty(propertyId.getPropertyName());
+ editor().removeProperty(name());
return;
}
-
+
// We have to convert from one Value implementation to ours ...
switch (value.getType()) {
case PropertyType.STRING:
@@ -241,7 +244,7 @@
protected void setValue( JcrValue jcrValue )
throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException {
assert jcrValue != null;
- cache.getEditorFor(propertyId.getNodeId()).setProperty(propertyId.getPropertyName(), jcrValue);
+ editor().setProperty(name(), jcrValue);
}
/**
@@ -327,11 +330,11 @@
this.remove();
return;
}
-
+
if (!value.isNodeType(JcrMixLexicon.REFERENCEABLE.getString(this.context().getNamespaceRegistry()))) {
throw new ValueFormatException(JcrI18n.nodeNotReferenceable.text());
}
-
+
String uuid = value.getUUID();
setValue(createValue(uuid, PropertyType.REFERENCE).asType(this.getType()));
}
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrWorkspace.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrWorkspace.java 2009-07-09 16:23:09 UTC (rev 1081)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrWorkspace.java 2009-07-09 16:26:04 UTC (rev 1082)
@@ -26,11 +26,8 @@
import java.io.IOException;
import java.io.InputStream;
import java.security.AccessControlException;
-import java.util.HashSet;
-import java.util.LinkedList;
import java.util.Map;
import java.util.Set;
-import java.util.UUID;
import javax.jcr.AccessDeniedException;
import javax.jcr.InvalidSerializedDataException;
import javax.jcr.ItemExistsException;
@@ -53,26 +50,24 @@
import org.jboss.dna.common.util.CheckArg;
import org.jboss.dna.graph.ExecutionContext;
import org.jboss.dna.graph.Graph;
-import org.jboss.dna.graph.Subgraph;
-import org.jboss.dna.graph.SubgraphNode;
import org.jboss.dna.graph.connector.RepositoryConnectionFactory;
import org.jboss.dna.graph.connector.RepositorySource;
import org.jboss.dna.graph.connector.RepositorySourceException;
import org.jboss.dna.graph.connector.UuidAlreadyExistsException;
import org.jboss.dna.graph.property.Name;
-import org.jboss.dna.graph.property.NameFactory;
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.PropertyFactory;
-import org.jboss.dna.graph.property.UuidFactory;
import org.jboss.dna.graph.property.ValueFormatException;
import org.jboss.dna.graph.property.basic.GraphNamespaceRegistry;
-import org.jboss.dna.graph.request.ReadBranchRequest;
+import org.jboss.dna.graph.request.InvalidWorkspaceException;
+import org.jboss.dna.graph.session.GraphSession.Node;
import org.jboss.dna.jcr.JcrContentHandler.EnclosingSAXException;
import org.jboss.dna.jcr.JcrContentHandler.SaveMode;
import org.jboss.dna.jcr.JcrRepository.Option;
-import org.jboss.dna.jcr.cache.NodeInfo;
+import org.jboss.dna.jcr.SessionCache.JcrNodePayload;
+import org.jboss.dna.jcr.SessionCache.JcrPropertyPayload;
import org.xml.sax.ContentHandler;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
@@ -312,134 +307,31 @@
}
try {
- this.session.checkPermission(destPath.getParent(), "add_node");
+ // Use the session to verify that the node location has a definition and is valid with the new cloned child.
+ // This also performs the check permission for reading the parent ...
+ Name newNodeName = destPath.getLastSegment().getName();
+ SessionCache cache = this.session.cache();
+ Node<JcrNodePayload, JcrPropertyPayload> parent = cache.findNode(null, destPath.getParent());
+ cache.findBestNodeDefinition(parent, newNodeName, parent.getPayload().getPrimaryTypeName());
+
+ // Now perform the clone, using the direct (non-session) method ...
+ cache.graphSession().immediateClone(srcPath, srcWorkspace, destPath, removeExisting);
+ } catch (ItemNotFoundException e) {
+ // The destination path was not found ...
+ throw new PathNotFoundException(e.getLocalizedMessage(), e);
+ } catch (org.jboss.dna.graph.property.PathNotFoundException e) {
+ throw new PathNotFoundException(e.getLocalizedMessage(), e);
+ } catch (UuidAlreadyExistsException e) {
+ throw new ItemExistsException(e.getLocalizedMessage(), e);
+ } catch (InvalidWorkspaceException e) {
+ throw new NoSuchWorkspaceException(e.getLocalizedMessage(), e);
+ } catch (RepositorySourceException e) {
+ throw new RepositoryException(e.getLocalizedMessage(), e);
} catch (AccessControlException ace) {
throw new AccessDeniedException(ace);
}
-
- clone(srcWorkspace, srcPath, destPath, removeExisting, false);
}
- void clone( String srcWorkspace,
- Path srcPath,
- Path destPath,
- boolean removeExisting,
- boolean destPathIncludesSegment )
- throws ConstraintViolationException, VersionException, AccessDeniedException, PathNotFoundException, ItemExistsException,
- LockException, RepositoryException {
-
- /*
- * Make sure that the node has a definition at the new location
- */
- SessionCache cache = this.session.cache();
- NodeInfo cacheParent = cache.findNodeInfo(null, destPath.getParent());
-
- // Skip the cache and load the latest parent info directly from the graph
- NodeInfo parent = cache.loadFromGraph(null, cacheParent.getUuid());
- Name newNodeName = destPath.getLastSegment().getName();
- String parentPath = destPath.getParent().getString(this.context.getNamespaceRegistry());
-
- Subgraph sourceTree = null;
- // This will check for a definition and throw a ConstraintViolationException or ItemExistsException if none is found
- graph.useWorkspace(srcWorkspace);
- Property primaryTypeProp;
- Property uuidProp;
- try {
- Map<Name, Property> props;
-
- if (removeExisting) {
- sourceTree = graph.getSubgraphOfDepth(ReadBranchRequest.NO_MAXIMUM_DEPTH).at(srcPath);
- props = sourceTree.getRoot().getPropertiesByName();
- } else {
- props = graph.getNodeAt(srcPath).getPropertiesByName();
- }
- primaryTypeProp = props.get(JcrLexicon.PRIMARY_TYPE);
- uuidProp = props.get(DnaLexicon.UUID);
- } catch (org.jboss.dna.graph.property.PathNotFoundException pnfe) {
- String srcAbsPath = srcPath.getString(this.context.getNamespaceRegistry());
- throw new PathNotFoundException(JcrI18n.itemNotFoundAtPath.text(srcAbsPath, srcWorkspace));
- } finally {
- graph.useWorkspace(this.name);
- }
-
- assert primaryTypeProp != null : "Cannot have a node in a JCR repository with no jcr:primaryType property";
- assert uuidProp != null : "Cannot have a node in a JCR repository with no UUID";
-
- NameFactory nameFactory = this.context.getValueFactories().getNameFactory();
- this.session.cache().findBestNodeDefinition(parent,
- parentPath,
- newNodeName,
- nameFactory.create(primaryTypeProp.getFirstValue()));
-
- if (removeExisting) {
- assert sourceTree != null;
-
- // Find all of the UUIDS in the source tree
- UuidFactory uuidFactory = context().getValueFactories().getUuidFactory();
- PathFactory pathFactory = context().getValueFactories().getPathFactory();
-
- Set<UUID> sourceUuids = new HashSet<UUID>();
- LinkedList<SubgraphNode> nodesToVisit = new LinkedList<SubgraphNode>();
- nodesToVisit.addFirst(sourceTree.getRoot());
-
- while (!nodesToVisit.isEmpty()) {
- SubgraphNode node = nodesToVisit.removeFirst();
-
- UUID uuid = uuidFactory.create(node.getProperty(DnaLexicon.UUID).getFirstValue().toString());
- if (uuid != null) {
- sourceUuids.add(uuid);
- }
- for (Path.Segment childSegment : node.getChildrenSegments()) {
- nodesToVisit.add(node.getNode(pathFactory.createRelativePath(childSegment)));
- }
- }
-
- // See if the nodes exist in the current workspace outside of the current tree
- for (UUID uuid : sourceUuids) {
- NodeInfo nodeInfo = null;
- try {
- nodeInfo = session.cache().findNodeInfo(uuid);
- } catch (ItemNotFoundException infe) {
- continue;
- }
- assert nodeInfo != null;
-
- NodeDefinitionId nodeDefnId = nodeInfo.getDefinitionId();
-
- JcrNodeType nodeType = nodeTypeManager.getNodeType(nodeDefnId.getNodeTypeName());
- JcrNodeDefinition nodeDefn = nodeType.childNodeDefinition(nodeDefnId);
- if (nodeDefn.isMandatory()) {
- // We can't just remove a mandatory node... unless its parent will be removed too!
- String path = session.cache().getPathFor(nodeInfo).getString(context().getNamespaceRegistry());
- throw new ConstraintViolationException(JcrI18n.cannotRemoveNodeFromClone.text(path, uuid));
-
- }
- }
-
- if (destPathIncludesSegment) {
- graph.clone(srcPath).fromWorkspace(srcWorkspace).as(destPath.getLastSegment()).into(destPath.getParent()).replacingExistingNodesWithSameUuids();
- } else {
- graph.clone(srcPath).fromWorkspace(srcWorkspace).as(newNodeName).into(destPath.getParent()).replacingExistingNodesWithSameUuids();
- }
- } else {
- try {
- if (destPathIncludesSegment) {
- graph.clone(srcPath).fromWorkspace(srcWorkspace).as(destPath.getLastSegment()).into(destPath.getParent()).replacingExistingNodesWithSameUuids();
- } else {
- graph.clone(srcPath).fromWorkspace(srcWorkspace).as(newNodeName).into(destPath.getParent()).failingIfAnyUuidsMatch();
- }
-
- } catch (UuidAlreadyExistsException uaee) {
- throw new ItemExistsException(uaee.getMessage());
- }
- }
-
- assert uuidProp.getFirstValue() instanceof UUID;
- // Load the node that we just copied
- cache.compensateForWorkspaceChildChange(cacheParent.getUuid(), null, (UUID)uuidProp.getFirstValue(), newNodeName);
-
- }
-
/**
* {@inheritDoc}
*
@@ -489,54 +381,29 @@
}
try {
- this.session.checkPermission(destPath.getParent(), "add_node");
+ // Use the session to verify that the node location has a definition and is valid with the new cloned child.
+ // This also performs the check permission for reading the parent ...
+ Name newNodeName = destPath.getLastSegment().getName();
+ SessionCache cache = this.session.cache();
+ Node<JcrNodePayload, JcrPropertyPayload> parent = cache.findNode(null, destPath.getParent());
+ cache.findBestNodeDefinition(parent, newNodeName, parent.getPayload().getPrimaryTypeName());
+
+ // Now perform the clone, using the direct (non-session) method ...
+ cache.graphSession().immediateCopy(srcPath, srcWorkspace, destPath);
+ } catch (ItemNotFoundException e) {
+ // The destination path was not found ...
+ throw new PathNotFoundException(e.getLocalizedMessage(), e);
+ } catch (org.jboss.dna.graph.property.PathNotFoundException e) {
+ throw new PathNotFoundException(e.getLocalizedMessage(), e);
+ } catch (UuidAlreadyExistsException e) {
+ throw new ItemExistsException(e.getLocalizedMessage(), e);
+ } catch (InvalidWorkspaceException e) {
+ throw new NoSuchWorkspaceException(e.getLocalizedMessage(), e);
+ } catch (RepositorySourceException e) {
+ throw new RepositoryException(e.getLocalizedMessage(), e);
} catch (AccessControlException ace) {
throw new AccessDeniedException(ace);
}
-
- /*
- * Make sure that the node has a definition at the new location
- */
- SessionCache cache = this.session.cache();
- NodeInfo cacheParent = cache.findNodeInfo(null, destPath.getParent());
-
- // Skip the cache and load the latest parent info directly from the graph
- NodeInfo parent = cache.loadFromGraph(destPath.getParent(), cacheParent.getUuid());
- Name newNodeName = destPath.getLastSegment().getName();
- String parentPath = destPath.getParent().getString(this.context.getNamespaceRegistry());
-
- // This will check for a definition and throw a ConstraintViolationException or ItemExistsException if none is found
- graph.useWorkspace(srcWorkspace);
-
- Property primaryTypeProp;
- Property uuidProp;
- try {
- Map<Name, Property> props = graph.getNodeAt(srcPath).getPropertiesByName();
- primaryTypeProp = props.get(JcrLexicon.PRIMARY_TYPE);
- uuidProp = props.get(DnaLexicon.UUID);
- } catch (org.jboss.dna.graph.property.PathNotFoundException pnfe) {
- throw new PathNotFoundException(JcrI18n.itemNotFoundAtPath.text(srcAbsPath, srcWorkspace));
- } finally {
- graph.useWorkspace(this.name);
- }
-
- assert primaryTypeProp != null : "Cannot have a node in a JCR repository with no jcr:primaryType property";
- assert uuidProp != null : "Cannot have a node in a JCR repository with no UUID";
-
- NameFactory nameFactory = this.context.getValueFactories().getNameFactory();
- this.session.cache().findBestNodeDefinition(parent,
- parentPath,
- newNodeName,
- nameFactory.create(primaryTypeProp.getFirstValue()));
-
- // Perform the copy operation, but use the "to" form (not the "into", which takes the parent) ...
- graph.copy(srcPath).fromWorkspace(srcWorkspace).to(destPath);
-
- // Load the node that we just copied
- cache.compensateForWorkspaceChildChange(cacheParent.getUuid(),
- null,
- UUID.fromString(uuidProp.getFirstValue().toString()),
- newNodeName);
}
/**
@@ -621,31 +488,38 @@
}
try {
- this.session.checkPermission(srcAbsPath.substring(0, srcAbsPath.lastIndexOf('/')), "remove");
- this.session.checkPermission(destAbsPath, "add_node");
+ // Use the session to verify that the node location has a definition and is valid with the new cloned child.
+ // This also performs the check permission for reading the parent ...
+ Name newNodeName = destPath.getLastSegment().getName();
+ SessionCache cache = this.session.cache();
+ Node<JcrNodePayload, JcrPropertyPayload> newParent = cache.findNode(null, destPath.getParent());
+ cache.findBestNodeDefinition(newParent, newNodeName, newParent.getPayload().getPrimaryTypeName());
+
+ // Now perform the clone, using the direct (non-session) method ...
+ cache.graphSession().immediateMove(srcPath, destPath);
} catch (AccessControlException ace) {
throw new AccessDeniedException(ace);
}
- /*
- * Make sure that the node has a definition at the new location
- */
- SessionCache cache = this.session.cache();
- NodeInfo nodeInfo = cache.findNodeInfo(null, srcPath);
- NodeInfo cacheParent = cache.findNodeInfo(null, destPath.getParent());
- NodeInfo oldParent = cache.findNodeInfo(null, srcPath.getParent());
-
- // Skip the cache and load the latest parent info directly from the graph
- NodeInfo parent = cache.loadFromGraph(destPath.getParent(), cacheParent.getUuid());
- Name newNodeName = destPath.getLastSegment().getName();
- String parentPath = destPath.getParent().getString(this.context.getNamespaceRegistry());
-
- // This will check for a definition and throw a ConstraintViolationException or ItemExistsException if none is found
- cache.findBestNodeDefinition(parent, parentPath, newNodeName, nodeInfo.getPrimaryTypeName());
-
- // Perform the copy operation, but use the "to" form (not the "into", which takes the parent) ...
- graph.move(srcPath).as(newNodeName).into(destPath.getParent());
- cache.compensateForWorkspaceChildChange(cacheParent.getUuid(), oldParent.getUuid(), nodeInfo.getUuid(), newNodeName);
+ // /*
+ // * Make sure that the node has a definition at the new location
+ // */
+ // SessionCache cache = this.session.cache();
+ // NodeInfo nodeInfo = cache.findNodeInfo(null, srcPath);
+ // NodeInfo cacheParent = cache.findNodeInfo(null, destPath.getParent());
+ // NodeInfo oldParent = cache.findNodeInfo(null, srcPath.getParent());
+ //
+ // // Skip the cache and load the latest parent info directly from the graph
+ // NodeInfo parent = cache.loadFromGraph(destPath.getParent(), cacheParent.getUuid());
+ // Name newNodeName = destPath.getLastSegment().getName();
+ // String parentPath = destPath.getParent().getString(this.context.getNamespaceRegistry());
+ //
+ // // This will check for a definition and throw a ConstraintViolationException or ItemExistsException if none is found
+ // cache.findBestNodeDefinition(parent, parentPath, newNodeName, nodeInfo.getPrimaryTypeName());
+ //
+ // // Perform the copy operation, but use the "to" form (not the "into", which takes the parent) ...
+ // graph.move(srcPath).as(newNodeName).into(destPath.getParent());
+ // cache.compensateForWorkspaceChildChange(cacheParent.getUuid(), oldParent.getUuid(), nodeInfo.getUuid(), newNodeName);
}
/**
Deleted: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/PropertyId.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/PropertyId.java 2009-07-09 16:23:09 UTC (rev 1081)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/PropertyId.java 2009-07-09 16:26:04 UTC (rev 1082)
@@ -1,111 +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.
- *
- * 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.jcr;
-
-import java.util.UUID;
-import net.jcip.annotations.Immutable;
-import org.jboss.dna.common.util.HashCode;
-import org.jboss.dna.graph.property.Name;
-
-/**
- * An immutable identifier for a property, often used to reference information a property held within the {@link SessionCache}.
- */
-@Immutable
-public final class PropertyId {
-
- private final UUID nodeId;
- private final Name propertyName;
- private final int hc;
-
- /**
- * Create a new property identifier.
- *
- * @param nodeId the UUID of the node that owns the property being reference; may not be null
- * @param propertyName the name of the property being referenced; may not be null
- */
- public PropertyId( UUID nodeId,
- Name propertyName ) {
- assert nodeId != null;
- assert propertyName != null;
- this.nodeId = nodeId;
- this.propertyName = propertyName;
- this.hc = HashCode.compute(this.nodeId, this.propertyName);
- }
-
- /**
- * Get the UUID of the node that owns the property.
- *
- * @return the node's UUID; never null
- */
- public UUID getNodeId() {
- return nodeId;
- }
-
- /**
- * Get the name of the property.
- *
- * @return the property name; never null
- */
- public Name getPropertyName() {
- return propertyName;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see java.lang.Object#hashCode()
- */
- @Override
- public int hashCode() {
- return hc;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see java.lang.Object#equals(java.lang.Object)
- */
- @Override
- public boolean equals( Object obj ) {
- if (obj == this) return true;
- if (obj instanceof PropertyId) {
- PropertyId that = (PropertyId)obj;
- if (this.hc != that.hc) return false;
- if (!this.nodeId.equals(that.nodeId)) return false;
- return this.propertyName.equals(that.propertyName);
- }
- return false;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see java.lang.Object#toString()
- */
- @Override
- public String toString() {
- return this.nodeId.toString() + '@' + this.propertyName.toString();
- }
-
-}
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-09 16:23:09 UTC (rev 1081)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/SessionCache.java 2009-07-09 16:26:04 UTC (rev 1082)
@@ -23,19 +23,17 @@
*/
package org.jboss.dna.jcr;
+import java.lang.ref.SoftReference;
import java.security.AccessControlException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
-import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
-import java.util.Queue;
import java.util.Set;
-import java.util.Stack;
import java.util.UUID;
import javax.jcr.AccessDeniedException;
import javax.jcr.InvalidItemStateException;
@@ -43,7 +41,6 @@
import javax.jcr.ItemExistsException;
import javax.jcr.ItemNotFoundException;
import javax.jcr.NoSuchWorkspaceException;
-import javax.jcr.Node;
import javax.jcr.PathNotFoundException;
import javax.jcr.PropertyType;
import javax.jcr.RepositoryException;
@@ -51,16 +48,15 @@
import javax.jcr.Value;
import javax.jcr.nodetype.ConstraintViolationException;
import javax.jcr.nodetype.NoSuchNodeTypeException;
-import javax.jcr.nodetype.NodeDefinition;
import javax.jcr.nodetype.NodeType;
import javax.jcr.nodetype.PropertyDefinition;
+import net.jcip.annotations.Immutable;
import net.jcip.annotations.ThreadSafe;
import org.jboss.dna.common.i18n.I18n;
import org.jboss.dna.common.util.Logger;
import org.jboss.dna.graph.ExecutionContext;
import org.jboss.dna.graph.Graph;
import org.jboss.dna.graph.Location;
-import org.jboss.dna.graph.Results;
import org.jboss.dna.graph.connector.RepositorySourceException;
import org.jboss.dna.graph.property.Name;
import org.jboss.dna.graph.property.NameFactory;
@@ -72,22 +68,14 @@
import org.jboss.dna.graph.property.ValueFactories;
import org.jboss.dna.graph.property.ValueFactory;
import org.jboss.dna.graph.property.ValueFormatException;
-import org.jboss.dna.graph.request.BatchRequestBuilder;
-import org.jboss.dna.graph.request.ChangeRequest;
-import org.jboss.dna.graph.request.CreateNodeRequest;
import org.jboss.dna.graph.request.InvalidWorkspaceException;
-import org.jboss.dna.graph.request.Request;
-import org.jboss.dna.jcr.cache.ChangedNodeInfo;
-import org.jboss.dna.jcr.cache.ChildNode;
-import org.jboss.dna.jcr.cache.Children;
-import org.jboss.dna.jcr.cache.EmptyChildren;
-import org.jboss.dna.jcr.cache.ImmutableChildren;
-import org.jboss.dna.jcr.cache.ImmutableNodeInfo;
-import org.jboss.dna.jcr.cache.NewNodeInfo;
-import org.jboss.dna.jcr.cache.NodeInfo;
-import org.jboss.dna.jcr.cache.PropertyInfo;
-import com.google.common.base.ReferenceType;
-import com.google.common.collect.ReferenceMap;
+import org.jboss.dna.graph.session.GraphSession;
+import org.jboss.dna.graph.session.InvalidStateException;
+import org.jboss.dna.graph.session.ValidationException;
+import org.jboss.dna.graph.session.GraphSession.Node;
+import org.jboss.dna.graph.session.GraphSession.NodeId;
+import org.jboss.dna.graph.session.GraphSession.PropertyInfo;
+import org.jboss.dna.graph.session.GraphSession.Status;
/**
* The class that manages the session's information that has been locally-cached after reading from the underlying {@link Graph
@@ -132,9 +120,9 @@
* Hidden flag that controls whether properties that appear on DNA nodes but not allowed by the node type or mixins should be
* included anyway. This is currently {@value} .
*/
- private static final boolean INCLUDE_PROPERTIES_NOT_ALLOWED_BY_NODE_TYPE_OR_MIXINS = true;
+ protected static final boolean INCLUDE_PROPERTIES_NOT_ALLOWED_BY_NODE_TYPE_OR_MIXINS = true;
- private static final Set<Name> EMPTY_NAMES = Collections.emptySet();
+ protected static final Set<Name> EMPTY_NAMES = Collections.emptySet();
private final JcrSession session;
private final String workspaceName;
@@ -146,24 +134,13 @@
protected final NamespaceRegistry namespaces;
protected final PropertyFactory propertyFactory;
private final Graph store;
- private final Name defaultPrimaryTypeName;
- private final Property defaultPrimaryTypeProperty;
+ protected final Name defaultPrimaryTypeName;
+ protected final Property defaultPrimaryTypeProperty;
protected final Path rootPath;
protected final Name residualName;
- private UUID root;
- private final ReferenceMap<UUID, AbstractJcrNode> jcrNodes;
- private final ReferenceMap<PropertyId, AbstractJcrProperty> jcrProperties;
+ private GraphSession<JcrNodePayload, JcrPropertyPayload> graphSession;
- protected final HashMap<UUID, ImmutableNodeInfo> cachedNodes;
- protected final HashMap<UUID, ChangedNodeInfo> changedNodes;
- protected final HashMap<UUID, NodeInfo> deletedNodes;
- protected final Map<UUID, Path> pathCache;
-
- private LinkedList<Request> requests;
- private BatchRequestBuilder requestBuilder;
- protected Graph.Batch operations;
-
public SessionCache( JcrSession session,
String workspaceName,
ExecutionContext context,
@@ -188,18 +165,13 @@
this.rootPath = pathFactory.createRootPath();
this.residualName = nameFactory.create(JcrNodeType.RESIDUAL_ITEM_NAME);
- this.jcrNodes = new ReferenceMap<UUID, AbstractJcrNode>(ReferenceType.STRONG, ReferenceType.SOFT);
- this.jcrProperties = new ReferenceMap<PropertyId, AbstractJcrProperty>(ReferenceType.STRONG, ReferenceType.SOFT);
+ // Create the graph session, customized for JCR ...
+ this.graphSession = new GraphSession<JcrNodePayload, JcrPropertyPayload>(this.store, this.workspaceName,
+ new JcrNodeOperations(), new JcrAuthorizer());
+ }
- this.cachedNodes = new HashMap<UUID, ImmutableNodeInfo>();
- this.changedNodes = new HashMap<UUID, ChangedNodeInfo>();
- this.deletedNodes = new HashMap<UUID, NodeInfo>();
- this.pathCache = new HashMap<UUID, Path>();
-
- // Create the batch operations ...
- this.requests = new LinkedList<Request>();
- this.requestBuilder = new BatchRequestBuilder(this.requests);
- this.operations = this.store.batch(this.requestBuilder);
+ final GraphSession<JcrNodePayload, JcrPropertyPayload> graphSession() {
+ return graphSession;
}
JcrSession session() {
@@ -211,7 +183,7 @@
}
String sourceName() {
- return session.sourceName();
+ return store.getSourceName();
}
ExecutionContext context() {
@@ -234,21 +206,36 @@
return session.nodeTypeManager();
}
- /**
- * Checks whether the current session has the appropriate permissions to perform the given action.
- *
- * @param node the node on which the action will be performed
- * @param action the name of the action to perform, should be "add_node", "remove", or "set_property"
- * @throws AccessDeniedException if the current session does not have the requisite privileges to perform this task
- * @throws RepositoryException if any other error occurs
- */
- protected void checkPermission( NodeInfo node,
- String action ) throws AccessDeniedException, RepositoryException {
- try {
- this.session.checkPermission(SessionCache.this.getPathFor(node), action);
- } catch (AccessControlException ace) {
- throw new AccessDeniedException(ace);
+ final String readable( Name name ) {
+ return name.getString(namespaces);
+ }
+
+ final String readable( Path.Segment segment ) {
+ return segment.getString(namespaces);
+ }
+
+ final String readable( Path path ) {
+ return path.getString(namespaces);
+ }
+
+ final String readable( Location location ) {
+ return location.getString(namespaces);
+ }
+
+ final String readable( Iterable<Name> names ) {
+ StringBuilder sb = new StringBuilder();
+ sb.append('[');
+ boolean first = true;
+ for (Name name : names) {
+ if (first) {
+ first = false;
+ } else {
+ sb.append(", ");
+ }
+ sb.append(name.getString(namespaces));
}
+ sb.append(']');
+ return sb.toString();
}
/**
@@ -257,7 +244,7 @@
* @return true if there are pending changes, or false if there is currently no changes
*/
boolean hasPendingChanges() {
- return operations.isExecuteRequired();
+ return graphSession.hasPendingChanges();
}
/**
@@ -269,24 +256,7 @@
* @param keepChanges indicates whether changed nodes should be kept or refreshed from the repository.
*/
public void refresh( boolean keepChanges ) {
- if (keepChanges) {
- // Keep the pending operations
- Set<UUID> retainedSet = new HashSet<UUID>(this.changedNodes.size() + this.deletedNodes.size());
- retainedSet.addAll(this.changedNodes.keySet());
- retainedSet.addAll(this.deletedNodes.keySet());
-
- // Removed any cached nodes not already in the changed or deleted set
- this.cachedNodes.keySet().retainAll(retainedSet);
- this.jcrNodes.keySet().retainAll(retainedSet);
- } else {
- // Throw out the old pending operations
- this.requests.clear();
- this.changedNodes.clear();
- this.cachedNodes.clear();
- this.deletedNodes.clear();
- this.jcrNodes.clear();
- }
-
+ graphSession.refresh(keepChanges);
}
/**
@@ -295,238 +265,28 @@
* If {@code keepChanges == true}, modified nodes will not have their state refreshed.
* </p>
*
- * @param nodeUuid the UUID of the node that is to be saved; may not be null
+ * @param nodeId the identifier of the node that is to be saved; may not be null
* @param keepChanges indicates whether changed nodes should be kept or refreshed from the repository.
+ * @throws InvalidItemStateException if the node being refreshed no longer exists
* @throws RepositoryException if any error resulting while saving the changes to the repository
*/
- public void refresh( UUID nodeUuid,
- boolean keepChanges ) throws RepositoryException {
- assert nodeUuid != null;
- // If the node being refreshed is the root node, then it's more efficient to refresh the whole workspace ...
- if (this.root.equals(nodeUuid)) {
- refresh(keepChanges);
- return;
+ public void refresh( NodeId nodeId,
+ boolean keepChanges ) throws InvalidItemStateException, RepositoryException {
+ assert nodeId != null;
+ try {
+ Node<JcrNodePayload, JcrPropertyPayload> node = graphSession.findNodeWith(nodeId);
+ graphSession.refresh(node, keepChanges);
+ } catch (InvalidStateException e) {
+ throw new InvalidItemStateException(e.getLocalizedMessage());
+ } catch (RepositorySourceException e) {
+ throw new RepositoryException(e.getLocalizedMessage());
}
-
- // Build the set of affected node UUIDs
- Set<UUID> nodesUnderBranch = new HashSet<UUID>();
- Stack<UUID> nodesToVisit = new Stack<UUID>();
- Set<UUID> nodesRemovedFromBranch = new HashSet<UUID>();
-
- nodesToVisit.add(nodeUuid);
- while (!nodesToVisit.isEmpty()) {
- UUID uuid = nodesToVisit.pop();
- nodesUnderBranch.add(uuid);
-
- NodeInfo nodeInfo = null;
- ChangedNodeInfo changedInfo = this.changedNodes.get(uuid);
- if (changedInfo != null) {
- Collection<UUID> removedNodes = changedInfo.getUuidsForRemovedChildren();
- nodesToVisit.addAll(removedNodes);
- nodesRemovedFromBranch.addAll(removedNodes);
- nodeInfo = changedInfo;
- } else {
- nodeInfo = this.cachedNodes.get(uuid);
- }
- if (nodeInfo != null) {
- for (ChildNode childNode : nodeInfo.getChildren()) {
- nodesToVisit.add(childNode.getUuid());
- }
- }
- }
-
- if (!nodesRemovedFromBranch.isEmpty()) {
- // Skip any nodes that were moved from one parent to another within this branch ...
- nodesRemovedFromBranch.removeAll(nodesUnderBranch);
- // Skip any nodes that were actually deleted (not moved)...
- nodesRemovedFromBranch.removeAll(this.deletedNodes.keySet());
- if (!nodesRemovedFromBranch.isEmpty()) {
- // There was at least one node that was moved from this branch to another parent outside this branch
- Path path = getPathFor(nodeUuid);
- String msg = JcrI18n.unableToRefreshBranchSinceAtLeastOneNodeMovedToParentOutsideOfBranch.text(path,
- workspaceName());
- throw new RepositoryException(msg);
- }
- }
-
- // Find the path of the given node ...
- Path path = getPathFor(nodeUuid);
-
- if (keepChanges) {
- // Keep the pending operations
- for (UUID uuid : nodesUnderBranch) {
- // getPathFor can (and will) add entries to cachedNodes - hence the existence of nodesToCheck
- if (getPathFor(uuid).isDecendantOf(path)) {
- if (!this.changedNodes.containsKey(uuid) && !this.deletedNodes.containsKey(uuid)) {
- this.cachedNodes.remove(uuid);
- }
- }
- }
- } else {
- this.cachedNodes.keySet().removeAll(nodesUnderBranch);
- this.changedNodes.keySet().removeAll(nodesUnderBranch);
- this.deletedNodes.keySet().removeAll(nodesUnderBranch);
- this.jcrNodes.keySet().removeAll(nodesUnderBranch);
-
- // Throw out the old pending operations
- if (operations.isExecuteRequired()) {
-
- // Make sure the builder has finished all the requests ...
- this.requestBuilder.finishPendingRequest();
-
- // Remove all of the enqueued requests for this branch ...
- for (Iterator<Request> iter = this.requests.iterator(); iter.hasNext();) {
- Request request = iter.next();
- assert request instanceof ChangeRequest;
- ChangeRequest change = (ChangeRequest)request;
- if (change.changes(workspaceName, path)) {
- iter.remove();
- }
- }
- }
- }
-
}
/**
- * Checks that the child items of the node are consistent with the definitions required by the node's primary type and mixin
- * types (if any).
- * <p>
- * This method first checks that all of the child nodes and properties for the node have definitions based on the current
- * primary and mixin node types for the node as held in the node type registry. The method then checks that all mandatory (and
- * non-protected) items are populated.
- * </p>
- *
- * @param nodeUuid the UUID of the node to check
- * @param checkSns if true indicates that this method should distinguish between child nodes that have no matching definition
- * and child nodes that would have a definition that would match if it allowed same-name siblings. This flag determines
- * which exception type should be thrown in that case.
- * @throws ItemExistsException if checkSns is true and there is no definition that allows same-name siblings for one of the
- * node's child nodes and the node already has a child node with the given name
- * @throws ConstraintViolationException if one of the node's properties or child nodes does not have a matching definition for
- * the name and type among the node's primary and mixin types; this should only occur if type definitions have been
- * modified since the node was loaded or modified.
- * @throws RepositoryException if any other error occurs
- */
- private void checkAgainstTypeDefinitions( UUID nodeUuid,
- boolean checkSns )
- throws ConstraintViolationException, ItemExistsException, RepositoryException {
-
- assert nodeUuid != null;
-
- if (this.deletedNodes.containsKey(nodeUuid)) {
- nodeUuid = this.deletedNodes.get(nodeUuid).getParent();
- }
-
- NodeInfo nodeInfo = findNodeInfo(nodeUuid);
- AbstractJcrNode node = findJcrNode(nodeUuid);
-
- Name primaryTypeName = node.getPrimaryTypeName();
- List<Name> mixinTypeNames = node.getMixinTypeNames();
- Set<JcrNodeDefinition> satisfiedChildNodes = new HashSet<JcrNodeDefinition>();
- Set<JcrPropertyDefinition> satisfiedProperties = new HashSet<JcrPropertyDefinition>();
-
- for (AbstractJcrProperty property : findJcrPropertiesFor(nodeUuid)) {
- JcrPropertyDefinition definition = findBestPropertyDefintion(primaryTypeName,
- mixinTypeNames,
- property.property(),
- property.getType(),
- property.property().isSingle(),
- false);
- if (definition == null) {
- throw new ConstraintViolationException(JcrI18n.noDefinition.text("property",
- property.getName(),
- node.getPath(),
- primaryTypeName,
- mixinTypeNames));
- }
-
- satisfiedProperties.add(definition);
- }
-
- Children children = nodeInfo.getChildren();
- for (ChildNode child : children) {
- int snsCount = children.getCountOfSameNameSiblingsWithName(child.getName());
- NodeInfo childInfo = findNodeInfo(child.getUuid());
- JcrNodeDefinition definition = nodeTypes().findChildNodeDefinition(primaryTypeName,
- mixinTypeNames,
- child.getName(),
- childInfo.getPrimaryTypeName(),
- snsCount,
- false);
- if (definition == null) {
- if (checkSns && snsCount > 1) {
- definition = nodeTypes().findChildNodeDefinition(primaryTypeName,
- mixinTypeNames,
- child.getName(),
- childInfo.getPrimaryTypeName(),
- 1,
- false);
-
- if (definition != null) {
- throw new ItemExistsException(JcrI18n.noSnsDefinition.text(child.getName(),
- node.getPath(),
- primaryTypeName,
- mixinTypeNames));
- }
- }
- throw new ConstraintViolationException(JcrI18n.noDefinition.text("child node",
- child.getName(),
- node.getPath(),
- primaryTypeName,
- mixinTypeNames));
- }
- satisfiedChildNodes.add(definition);
- }
-
- JcrNodeType primaryType = nodeTypes().getNodeType(primaryTypeName);
- for (JcrPropertyDefinition definition : primaryType.getPropertyDefinitions()) {
- if (definition.isMandatory() && !definition.isProtected() && !satisfiedProperties.contains(definition)) {
- throw new ConstraintViolationException(JcrI18n.noDefinition.text("property",
- definition.getName(),
- node.getPath(),
- primaryTypeName,
- mixinTypeNames));
- }
- }
- for (JcrNodeDefinition definition : primaryType.getChildNodeDefinitions()) {
- if (definition.isMandatory() && !definition.isProtected() && !satisfiedChildNodes.contains(definition)) {
- throw new ConstraintViolationException(JcrI18n.noDefinition.text("child node",
- definition.getName(),
- node.getPath(),
- primaryTypeName,
- mixinTypeNames));
- }
- }
-
- for (Name mixinTypeName : mixinTypeNames) {
- JcrNodeType mixinType = nodeTypes().getNodeType(mixinTypeName);
- for (JcrPropertyDefinition definition : mixinType.getPropertyDefinitions()) {
- if (definition.isMandatory() && !definition.isProtected() && !satisfiedProperties.contains(definition)) {
- throw new ConstraintViolationException(JcrI18n.noDefinition.text("child node",
- definition.getName(),
- node.getPath(),
- primaryTypeName,
- mixinTypeNames));
- }
- }
- for (JcrNodeDefinition definition : mixinType.getChildNodeDefinitions()) {
- if (definition.isMandatory() && !definition.isProtected() && !satisfiedChildNodes.contains(definition)) {
- throw new ConstraintViolationException(JcrI18n.noDefinition.text("child node",
- definition.getName(),
- node.getPath(),
- primaryTypeName,
- mixinTypeNames));
- }
- }
-
- }
- }
-
- /**
* Find the best definition for the child node with the given name on the node with the given UUID.
*
- * @param nodeUuid the parent node; may not be null
+ * @param parent the parent node; may not be null
* @param newNodeName the name of the potential new child node; may not be null
* @param newNodePrimaryTypeName the primary type of the potential new child node; may not be null
* @return the definition that best fits the new node name and type
@@ -536,48 +296,18 @@
* mixin types
* @throws RepositoryException if any other error occurs
*/
- protected JcrNodeDefinition findBestNodeDefinition( UUID nodeUuid,
+ protected JcrNodeDefinition findBestNodeDefinition( Node<JcrNodePayload, JcrPropertyPayload> parent,
Name newNodeName,
Name newNodePrimaryTypeName )
throws ItemExistsException, ConstraintViolationException, RepositoryException {
- assert (nodeUuid != null);
- assert (newNodeName != null);
+ assert parent != null;
+ assert newNodeName != null;
- NodeInfo nodeInfo = findNodeInfo(nodeUuid);
- AbstractJcrNode node = findJcrNode(nodeUuid);
+ Name primaryTypeName = parent.getPayload().getPrimaryTypeName();
+ List<Name> mixinTypeNames = parent.getPayload().getMixinTypeNames();
- return findBestNodeDefinition(nodeInfo, node.getPath(), newNodeName, newNodePrimaryTypeName);
- }
-
- /**
- * Find the best definition for the child node with the given name on the node with the given UUID.
- *
- * @param parentInfo the parent node's info; may not be null
- * @param parentPath the path to the parent node; may not be null
- * @param newNodeName the name of the potential new child node; may not be null
- * @param newNodePrimaryTypeName the primary type of the potential new child node; may not be null
- * @return the definition that best fits the new node name and type
- * @throws ItemExistsException if there is no definition that allows same-name siblings for the name and type and the parent
- * node already has a child node with the given name
- * @throws ConstraintViolationException if there is no definition for the name and type among the parent node's primary and
- * mixin types
- * @throws RepositoryException if any other error occurs
- */
- protected JcrNodeDefinition findBestNodeDefinition( NodeInfo parentInfo,
- String parentPath,
- Name newNodeName,
- Name newNodePrimaryTypeName )
- throws ItemExistsException, ConstraintViolationException, RepositoryException {
- assert (parentInfo != null);
- assert (parentPath != null);
- assert (newNodeName != null);
-
- Name primaryTypeName = parentInfo.getPrimaryTypeName();
- List<Name> mixinTypeNames = parentInfo.getMixinTypeNames();
-
- Children children = parentInfo.getChildren();
// Need to add one to speculate that this node will be added
- int snsCount = children.getCountOfSameNameSiblingsWithName(newNodeName) + 1;
+ int snsCount = parent.getChildrenCount(newNodeName) + 1;
JcrNodeDefinition definition = nodeTypes().findChildNodeDefinition(primaryTypeName,
mixinTypeNames,
newNodeName,
@@ -594,302 +324,271 @@
true);
if (definition != null) {
- throw new ItemExistsException(JcrI18n.noSnsDefinition.text(newNodeName,
- parentPath,
- primaryTypeName,
- mixinTypeNames));
+ throw new ItemExistsException(JcrI18n.noSnsDefinition.text(readable(newNodeName),
+ readable(parent.getPath()),
+ readable(primaryTypeName),
+ readable(mixinTypeNames)));
}
}
throw new ConstraintViolationException(JcrI18n.noDefinition.text("child node",
- newNodeName,
- parentPath,
- primaryTypeName,
- mixinTypeNames));
+ readable(newNodeName),
+ readable(parent.getPath()),
+ readable(primaryTypeName),
+ readable(mixinTypeNames)));
}
return definition;
}
/**
- * The JCR specification assumes that reading a node into the session does not imply reading the relationship between the node
- * and its children into the session. As a performance optimization, DNA eagerly loads the list of child names and UUIDs (but
- * not the child nodes themselves). This creates an issue when direct writes are performed through the workspace. The act of
- * modifying a node is assumed to imply loading its children, but we must load the node in order to modify it.
- * <p>
- * This method provides a way to signal that a child should be added to one parent and, optionally, removed from another. The
- * cache of loaded nodes and the cache of changed nodes are modified accordingly, but no additional graph requests are
- * batched.
- * </p>
+ * Save any changes that have been accumulated by this session.
*
- * @param newParentUuid the UUID of the node to which the child is to be moved; may not be null
- * @param oldParentUuid the UUID of the parent node from which the child was moved; may not be null
- * @param child the UUID of the child node that was moved or copied; may not be null
- * @param childName the new name of the child node; may not be null
- * @throws RepositoryException if an error occurs
+ * @throws IllegalArgumentException if the identifier and path are both node
+ * @throws ItemNotFoundException if a node with the supplied identifier and path could not be found
+ * @throws AccessDeniedException if the caller does not have privilege to perform the operation
+ * @throws ConstraintViolationException if there was a constraint violation
+ * @throws RepositoryException if any error resulting while saving the changes to the repository
*/
- public void compensateForWorkspaceChildChange( UUID newParentUuid,
- UUID oldParentUuid,
- UUID child,
- Name childName ) throws RepositoryException {
- assert newParentUuid != null;
- assert child != null;
- assert childName != null;
-
- ChangedNodeInfo changedNode = this.changedNodes.get(newParentUuid);
- if (changedNode != null) {
- // This adds the child to the changed node, but doesn't generate a corresponding pending request
- // avoiding a challenge later.
- changedNode.addChild(childName, child, this.pathFactory);
-
- } else {
- this.cachedNodes.remove(newParentUuid);
+ public void save() throws ItemNotFoundException, AccessDeniedException, ConstraintViolationException, RepositoryException {
+ try {
+ graphSession.save();
+ } catch (ValidationException e) {
+ throw new ConstraintViolationException(e.getLocalizedMessage(), e.getCause());
+ } catch (InvalidStateException e) {
+ throw new InvalidItemStateException(e.getLocalizedMessage(), e.getCause());
+ } catch (RepositorySourceException e) {
+ throw new RepositoryException(e.getLocalizedMessage(), e.getCause());
+ } catch (AccessControlException e) {
+ throw new AccessDeniedException(e.getMessage(), e.getCause());
}
-
- if (oldParentUuid != null) {
- changedNode = this.changedNodes.get(oldParentUuid);
- if (changedNode != null) {
- changedNode.removeChild(child, this.pathFactory);
- } else {
- this.cachedNodes.remove(newParentUuid);
- }
- }
}
/**
- * Save any changes that have been accumulated by this session.
+ * Save any changes to the identified node or its descendants. The supplied node may not have been deleted or created in this
+ * session since the last save operation.
*
+ * @param nodeId the identifier of the node that is to be saved; may not be null
+ * @param absolutePath the absolute path to the node; may not be null
+ * @throws IllegalArgumentException if the identifier and path are both node
+ * @throws ItemNotFoundException if a node with the supplied identifier and path could not be found
+ * @throws AccessDeniedException if the caller does not have privilege to perform the operation
+ * @throws ConstraintViolationException if there was a constraint violation
* @throws RepositoryException if any error resulting while saving the changes to the repository
*/
- public void save() throws RepositoryException {
- if (operations.isExecuteRequired()) {
- for (UUID changedUuid : this.changedNodes.keySet()) {
- checkAgainstTypeDefinitions(changedUuid, false);
- }
-
- // Execute the batched operations ...
- try {
- operations.execute();
- } catch (org.jboss.dna.graph.property.PathNotFoundException e) {
- throw new InvalidItemStateException(e.getLocalizedMessage(), e);
- } catch (RuntimeException e) {
- throw new RepositoryException(e.getLocalizedMessage(), e);
- }
-
- // Create a new batch for future operations ...
- // LinkedList<Request> oldRequests = this.requests;
- this.requests = new LinkedList<Request>();
- this.requestBuilder = new BatchRequestBuilder(this.requests);
- operations = store.batch(this.requestBuilder);
-
- // Remove all the cached items that have been changed or deleted ...
- for (UUID changedUuid : changedNodes.keySet()) {
- cachedNodes.remove(changedUuid);
- }
- for (UUID changedUuid : deletedNodes.keySet()) {
- cachedNodes.remove(changedUuid);
- }
- // Remove all the changed and deleted infos ...
- changedNodes.clear();
- deletedNodes.clear();
+ public void save( NodeId nodeId,
+ Path absolutePath )
+ throws ItemNotFoundException, AccessDeniedException, ConstraintViolationException, RepositoryException {
+ assert nodeId != null;
+ try {
+ Node<JcrNodePayload, JcrPropertyPayload> node = graphSession.findNodeWith(nodeId, absolutePath);
+ assert node != null;
+ graphSession.save(node);
+ } catch (ValidationException e) {
+ throw new ConstraintViolationException(e.getLocalizedMessage(), e.getCause());
+ } catch (InvalidStateException e) {
+ throw new InvalidItemStateException(e.getLocalizedMessage(), e.getCause());
+ } catch (RepositorySourceException e) {
+ throw new RepositoryException(e.getLocalizedMessage(), e.getCause());
+ } catch (AccessControlException e) {
+ throw new AccessDeniedException(e.getMessage(), e.getCause());
}
}
/**
- * Save any changes to the identified node or its descendants. The supplied node may not have been deleted or created in this
- * session since the last save operation.
+ * Find the session's node for the given identifier and path.
*
- * @param nodeUuid the UUID of the node that is to be saved; may not be null
- * @throws RepositoryException if any error resulting while saving the changes to the repository
+ * @param id the identifier for the node
+ * @param absolutePath the absolute path to the node; may not be null
+ * @return the existing node implementation
+ * @throws IllegalArgumentException if the identifier and path are both node
+ * @throws ItemNotFoundException if a node with the supplied identifier and path could not be found
+ * @throws AccessDeniedException if the caller does not have privilege to read the node
+ * @throws RepositoryException if an error resulting in finding this node in the repository
*/
- public void save( UUID nodeUuid ) throws RepositoryException {
- assert nodeUuid != null;
- if (deletedNodes.containsKey(nodeUuid)) {
- // This node was deleted in this session ...
- throw new InvalidItemStateException(JcrI18n.nodeHasAlreadyBeenRemovedFromThisSession.text(nodeUuid, workspaceName()));
+ public Node<JcrNodePayload, JcrPropertyPayload> findNode( NodeId id,
+ Path absolutePath )
+ throws ItemNotFoundException, AccessDeniedException, RepositoryException {
+ try {
+ return graphSession.findNodeWith(id, absolutePath);
+ } catch (org.jboss.dna.graph.property.PathNotFoundException e) {
+ throw new ItemNotFoundException(e.getMessage(), e.getCause());
+ } catch (RepositorySourceException e) {
+ throw new RepositoryException(e.getMessage(), e.getCause());
+ } catch (AccessControlException e) {
+ throw new AccessDeniedException(e.getMessage(), e.getCause());
}
+ }
- // The node must not have been created since the last save ...
- if (!cachedNodes.containsKey(nodeUuid)) {
- // It is not cached, which means it WAS created ...
- Path path = getPathFor(nodeUuid);
- throw new RepositoryException(JcrI18n.unableToSaveNodeThatWasCreatedSincePreviousSave.text(path, workspaceName()));
+ /**
+ * Find the session's node for the given identifier and path.
+ *
+ * @param from the identifier of the reference node; may be null if the root node is to be used as the reference
+ * @param fromAbsolutePath the absolute path of the reference node; may not be null
+ * @param relativePath the relative (but normalized) path from the reference node, but which may be an absolute (and
+ * normalized) path only when the reference node is the root node; may not be null
+ * @return the existing node implementation
+ * @throws IllegalArgumentException if the identifier and path are both node
+ * @throws ItemNotFoundException if a node with the supplied identifier and path could not be found
+ * @throws PathNotFoundException if the node given by the relative path does not exist
+ * @throws AccessDeniedException if the caller does not have privilege to read the node
+ * @throws RepositoryException if an error resulting in finding this node in the repository
+ */
+ public Node<JcrNodePayload, JcrPropertyPayload> findNode( NodeId from,
+ Path fromAbsolutePath,
+ Path relativePath )
+ throws PathNotFoundException, ItemNotFoundException, AccessDeniedException, RepositoryException {
+ // Find the reference node ...
+ Node<JcrNodePayload, JcrPropertyPayload> referenceNode = findNode(from, fromAbsolutePath);
+ try {
+ return graphSession.findNodeRelativeTo(referenceNode, relativePath);
+ } catch (org.jboss.dna.graph.property.PathNotFoundException e) {
+ throw new PathNotFoundException(e.getMessage(), e.getCause());
+ } catch (RepositorySourceException e) {
+ throw new RepositoryException(e.getMessage(), e.getCause());
+ } catch (AccessControlException e) {
+ throw new AccessDeniedException(e.getMessage(), e.getCause());
}
-
- if (operations.isExecuteRequired()) {
- // Find the path of the given node ...
- Path path = getPathFor(nodeUuid);
-
- // Make sure the builder has finished all the requests ...
- this.requestBuilder.finishPendingRequest();
-
- // Remove all of the enqueued requests for this branch ...
- LinkedList<Request> branchRequests = new LinkedList<Request>();
- LinkedList<Request> nonBranchRequests = new LinkedList<Request>();
- Set<UUID> branchUuids = new HashSet<UUID>();
- for (Request request : this.requests) {
- assert request instanceof ChangeRequest;
- ChangeRequest change = (ChangeRequest)request;
- if (change.changes(workspaceName, path)) {
- branchRequests.add(request);
- // Record the UUID of the node being saved now ...
- UUID changedUuid = null;
- if (change instanceof CreateNodeRequest) {
- // We want the parent UUID ...
- changedUuid = ((CreateNodeRequest)change).under().getUuid();
- } else {
- changedUuid = change.changedLocation().getUuid();
- }
- assert changedUuid != null;
- branchUuids.add(changedUuid);
- } else {
- nonBranchRequests.add(request);
- }
- }
-
- if (branchRequests.isEmpty()) {
- // None of the changes affected the branch given by the node ...
- return;
- }
-
- /*
- * branchUuids contains all the roots of the changes, but there may be further changes under the roots (e.g., a
- * newly created node will have it's parent's UUID in branchUuids, but not the new node's uuid.
- */
- Set<UUID> uuidsUnderBranch = new HashSet<UUID>();
- LinkedList<UUID> peersToCheck = new LinkedList<UUID>();
-
- for (UUID changedUuid : branchUuids) {
- checkAgainstTypeDefinitions(changedUuid, false);
- }
-
- for (UUID branchUuid : branchUuids) {
- uuidsUnderBranch.add(branchUuid);
- ChangedNodeInfo changedNode = changedNodes.get(branchUuid);
- if (changedNode != null) {
- for (ChildNode childNode : changedNode.getChildren()) {
- uuidsUnderBranch.add(childNode.getUuid());
- }
-
- Collection<UUID> peers = changedNode.getPeers();
- if (peers != null) peersToCheck.addAll(peers);
- }
-
- }
-
- /*
- * Need to check that any peers in a Session.move operation are both in the save
- */
- for (UUID peerUuid : peersToCheck) {
- if (!uuidsUnderBranch.contains(peerUuid)) {
- throw new ConstraintViolationException();
- }
- }
-
- // Now execute the branch ...
- Graph.Batch branchBatch = store.batch(new BatchRequestBuilder(branchRequests));
- try {
- branchBatch.execute();
-
- // Still have non-branch related requests that we haven't executed ...
- this.requests = nonBranchRequests;
- this.requestBuilder = new BatchRequestBuilder(this.requests);
- this.operations = store.batch(this.requestBuilder);
-
- // Remove all the cached, changed or deleted items that were just saved ...
- cachedNodes.keySet().removeAll(uuidsUnderBranch);
- changedNodes.keySet().removeAll(uuidsUnderBranch);
- deletedNodes.keySet().removeAll(uuidsUnderBranch);
- } catch (org.jboss.dna.graph.property.PathNotFoundException e) {
- throw new InvalidItemStateException(e.getLocalizedMessage(), e);
- } catch (RuntimeException e) {
- throw new RepositoryException(e.getLocalizedMessage(), e);
- }
- }
}
+ /**
+ * Find the root node associated with this workspace.
+ *
+ * @return the root node; never null
+ * @throws RepositoryException if an error resulting in finding this node in the repository
+ */
public JcrRootNode findJcrRootNode() throws RepositoryException {
- return (JcrRootNode)findJcrNode(findNodeInfoForRoot().getUuid());
+ return (JcrRootNode)graphSession.getRoot().getPayload().getJcrNode();
}
/**
- * Find the JCR {@link JcrNode Node implementation} for the given UUID.
+ * Find the JCR {@link JcrNode Node implementation} for the given identifier and path.
*
- * @param uuid the node's UUID
+ * @param location the location of the node
* @return the existing node implementation
- * @throws ItemNotFoundException if a node with the supplied UUID could not be found
+ * @throws IllegalArgumentException if the identifier and path are both node
+ * @throws ItemNotFoundException if a node with the supplied identifier and path could not be found
+ * @throws AccessDeniedException if the caller does not have privilege to read the node
* @throws RepositoryException if an error resulting in finding this node in the repository
*/
- public AbstractJcrNode findJcrNode( UUID uuid ) throws ItemNotFoundException, RepositoryException {
- AbstractJcrNode node = jcrNodes.get(uuid);
- if (node != null) return node;
+ public AbstractJcrNode findJcrNode( Location location )
+ throws ItemNotFoundException, AccessDeniedException, RepositoryException {
+ try {
+ return graphSession.findNodeWith(location).getPayload().getJcrNode();
+ } catch (org.jboss.dna.graph.property.PathNotFoundException e) {
+ throw new ItemNotFoundException(e.getMessage(), e.getCause());
+ } catch (RepositorySourceException e) {
+ throw new RepositoryException(e.getMessage(), e.getCause());
+ } catch (AccessControlException e) {
+ throw new AccessDeniedException(e.getMessage(), e.getCause());
+ }
+ }
- // An existing JCR Node object was not found, so we'll have to create it by finding the underlying
- // NodeInfo for the node (from the changed state or the cache) ...
- NodeInfo info = findNodeInfo(uuid);
- assert info != null;
-
- // Create the appropriate JCR Node object ...
- return createAndCacheJcrNodeFor(info);
+ /**
+ * Find the JCR {@link JcrNode Node implementation} for the given identifier and path.
+ *
+ * @param id the identifier for the node
+ * @param absolutePath the absolute path to the node; may not be null
+ * @return the existing node implementation
+ * @throws IllegalArgumentException if the identifier and path are both node
+ * @throws ItemNotFoundException if a node with the supplied identifier and path could not be found
+ * @throws AccessDeniedException if the caller does not have privilege to read the node
+ * @throws RepositoryException if an error resulting in finding this node in the repository
+ */
+ public AbstractJcrNode findJcrNode( NodeId id,
+ Path absolutePath )
+ throws ItemNotFoundException, AccessDeniedException, RepositoryException {
+ return findNode(id, absolutePath).getPayload().getJcrNode();
}
/**
* Find the JCR {@link AbstractJcrNode Node implementation} for the node given by the UUID of a reference node and a relative
* path from the reference node. The relative path should already have been {@link Path#getNormalizedPath() normalized}.
*
- * @param uuidOfReferenceNode the UUID of the reference node; may be null if the root node is to be used as the reference
+ * @param from the identifier of the reference node; may be null if the root node is to be used as the reference
+ * @param fromAbsolutePath the absolute path of the reference node; may not be null
* @param relativePath the relative (but normalized) path from the reference node, but which may be an absolute (and
* normalized) path only when the reference node is the root node; may not be null
* @return the information for the referenced node; never null
- * @throws ItemNotFoundException if the reference node with the supplied UUID does not exist
+ * @throws ItemNotFoundException if the reference node with the supplied identifier and path does not exist
* @throws PathNotFoundException if the node given by the relative path does not exist
- * @throws InvalidItemStateException if the node with the UUID has been deleted in this session
+ * @throws InvalidItemStateException if the reference node has been deleted in this session
+ * @throws AccessDeniedException if the caller does not have privilege to read the reference or result node
* @throws RepositoryException if any other error occurs while reading information from the repository
- * @see #findNodeInfoForRoot()
*/
- public AbstractJcrNode findJcrNode( UUID uuidOfReferenceNode,
+ public AbstractJcrNode findJcrNode( NodeId from,
+ Path fromAbsolutePath,
Path relativePath )
- throws PathNotFoundException, InvalidItemStateException, RepositoryException {
- // An existing JCR Node object was not found, so we'll have to create it by finding the underlying
- // NodeInfo for the node (from the changed state or the cache) ...
- NodeInfo info = findNodeInfo(uuidOfReferenceNode, relativePath);
- assert info != null;
-
- // Look for an existing node ...
- AbstractJcrNode node = jcrNodes.get(info.getUuid());
- if (node != null) return node;
-
- // Create the appropriate JCR Node object ...
- return createAndCacheJcrNodeFor(info);
+ throws ItemNotFoundException, PathNotFoundException, InvalidItemStateException, AccessDeniedException,
+ RepositoryException {
+ // Find the reference node ...
+ Node<JcrNodePayload, JcrPropertyPayload> referenceNode = findNode(from, fromAbsolutePath);
+ try {
+ // Find the reference node ...
+ return graphSession.findNodeRelativeTo(referenceNode, relativePath).getPayload().getJcrNode();
+ } catch (org.jboss.dna.graph.property.PathNotFoundException e) {
+ throw new PathNotFoundException(e.getMessage(), e.getCause());
+ } catch (RepositorySourceException e) {
+ throw new RepositoryException(e.getMessage(), e.getCause());
+ } catch (AccessControlException e) {
+ throw new AccessDeniedException(e.getMessage(), e.getCause());
+ }
}
- public AbstractJcrProperty findJcrProperty( PropertyId propertyId ) throws PathNotFoundException, RepositoryException {
- AbstractJcrProperty property = jcrProperties.get(propertyId);
- if (property != null) return property;
-
- // An existing JCR Property object was not found, so we'll have to create it by finding the underlying
- // NodeInfo for the property's parent (from the changed state or the cache) ...
- PropertyInfo info = findPropertyInfo(propertyId); // throws PathNotFoundException if node not there
- if (info == null) return null; // no such property on this node
-
- // Skip all internal properties ...
- if (info.getPropertyName().getNamespaceUri().equals(DnaIntLexicon.Namespace.URI)) return null;
-
- // Now create the appropriate JCR Property object ...
- return createAndCacheJcrPropertyFor(info);
+ /**
+ * Find the JCR {@link javax.jcr.Property} with the givenname on the node with the supplied ID and/or at the absolute path.
+ *
+ * @param id the identifier of the node, or null if the path should be used
+ * @param absolutePath the absolute path to the node; should not be null
+ * @param propertyName the property name; may not be null
+ * @return the property, or null if there is no such property
+ * @throws PathNotFoundException if the node does not exist
+ * @throws AccessDeniedException if the caller cannot read the property
+ * @throws RepositoryException if there is a problem reading the node and/or property
+ */
+ public AbstractJcrProperty findJcrProperty( NodeId id,
+ Path absolutePath,
+ Name propertyName )
+ throws PathNotFoundException, AccessDeniedException, RepositoryException {
+ // Find the node that owns the property ...
+ Node<JcrNodePayload, JcrPropertyPayload> node = findNode(id, absolutePath);
+ PropertyInfo<JcrPropertyPayload> propertyInfo = node.getProperty(propertyName);
+ if (propertyInfo != null) {
+ return propertyInfo.getPayload().getJcrProperty();
+ }
+ return null;
}
- public Collection<AbstractJcrProperty> findJcrPropertiesFor( UUID nodeUuid )
- throws ItemNotFoundException, RepositoryException {
- NodeInfo info = findNodeInfo(nodeUuid);
- Set<Name> propertyNames = info.getPropertyNames();
- Collection<AbstractJcrProperty> result = new ArrayList<AbstractJcrProperty>(propertyNames.size());
- for (Name propertyName : propertyNames) {
- if (!propertyName.getNamespaceUri().equals(DnaIntLexicon.Namespace.URI)) {
- result.add(findJcrProperty(new PropertyId(nodeUuid, propertyName)));
+ /**
+ * Find the properties for the node given by the supplied identifier and/or path.
+ *
+ * @param id the identifier of the node, or null if the path should be used
+ * @param absolutePath the absolute path to the node; should not be null
+ * @return an immutable snapshot of the properties in the node
+ * @throws PathNotFoundException if the node does not exist
+ * @throws AccessDeniedException if the caller cannot read the property
+ * @throws RepositoryException if there is a problem reading the node and/or property
+ */
+ public Collection<AbstractJcrProperty> findJcrPropertiesFor( NodeId id,
+ Path absolutePath )
+ throws PathNotFoundException, AccessDeniedException, RepositoryException {
+ try {
+ Node<JcrNodePayload, JcrPropertyPayload> node = graphSession.findNodeWith(id, absolutePath);
+ Collection<AbstractJcrProperty> result = new ArrayList<AbstractJcrProperty>(node.getPropertyCount());
+ for (org.jboss.dna.graph.session.GraphSession.PropertyInfo<JcrPropertyPayload> property : node.getProperties()) {
+ Name propertyName = property.getName();
+ if (!propertyName.getNamespaceUri().equals(DnaIntLexicon.Namespace.URI)) {
+ result.add(property.getPayload().getJcrProperty());
+ }
}
+ return result;
+ } catch (org.jboss.dna.graph.property.PathNotFoundException e) {
+ throw new PathNotFoundException(e.getMessage(), e.getCause());
+ } catch (RepositorySourceException e) {
+ throw new RepositoryException(e.getMessage(), e.getCause());
+ } catch (AccessControlException e) {
+ throw new AccessDeniedException(e.getMessage(), e.getCause());
}
- return result;
}
/**
@@ -897,7 +596,9 @@
* a relative path from the reference node to the desired item. The relative path should already have been
* {@link Path#getNormalizedPath() normalized}.
*
- * @param uuidOfReferenceNode the UUID of the reference node; may be null if the root node is to be used as the reference
+ * @param from the identifier of the reference node; may be null if the root node is to be used as the reference
+ * @param fromAbsolutePath the absolute path of the reference node; may be null if the root node is to be used as the
+ * reference
* @param relativePath the relative (but normalized) path from the reference node to the desired item, but which may be an
* absolute (and normalized) path only when the reference node is the root node; may not be null
* @return the information for the referenced item; never null
@@ -905,21 +606,23 @@
* supplied relative path does not exist
* @throws InvalidItemStateException if the node with the UUID has been deleted in this session
* @throws RepositoryException if any other error occurs while reading information from the repository
- * @see #findNodeInfoForRoot()
*/
- public AbstractJcrItem findJcrItem( UUID uuidOfReferenceNode,
+ public AbstractJcrItem findJcrItem( NodeId from,
+ Path fromAbsolutePath,
Path relativePath )
throws ItemNotFoundException, InvalidItemStateException, RepositoryException {
+ if (from == null && fromAbsolutePath == null) {
+ from = graphSession.getRoot().getNodeId();
+ }
// A pathological case is an empty relative path ...
if (relativePath.size() == 0) {
- return findJcrNode(uuidOfReferenceNode);
+ return findJcrNode(from, fromAbsolutePath);
}
if (relativePath.size() == 1) {
Path.Segment segment = relativePath.getLastSegment();
- if (segment.isSelfReference()) return findJcrNode(uuidOfReferenceNode);
+ if (segment.isSelfReference()) return findJcrNode(from, fromAbsolutePath);
if (segment.isParentReference()) {
- NodeInfo referencedNode = findNodeInfo(uuidOfReferenceNode);
- return findJcrNode(referencedNode.getParent());
+ return findJcrNode(from, fromAbsolutePath, relativePath);
}
}
@@ -927,115 +630,168 @@
Path.Segment lastSegment = relativePath.getLastSegment();
if (lastSegment.getIndex() > 1) {
// Only nodes can have SNS index (but an index of 1 is the default)...
- return findJcrNode(uuidOfReferenceNode);
+ return findJcrNode(from, fromAbsolutePath);
}
- NodeInfo parent = null;
- if (relativePath.size() == 1) {
- // The referenced node must be the parent ...
- parent = findNodeInfo(uuidOfReferenceNode);
- } else {
- // We know that the parent of the referenced item should be a node (if the path is right) ...
- parent = findNodeInfo(uuidOfReferenceNode, relativePath.getParent());
+ Node<JcrNodePayload, JcrPropertyPayload> fromNode = null;
+ Node<JcrNodePayload, JcrPropertyPayload> parent = null;
+ try {
+ fromNode = graphSession.findNodeWith(from, fromAbsolutePath);
+ if (from == null) from = fromNode.getNodeId();
+ assert from != null;
+ if (relativePath.size() == 1) {
+ // The referenced node must be the parent ...
+ parent = fromNode;
+ } else {
+ // We know that the parent of the referenced item should be a node (if the path is right) ...
+ parent = graphSession.findNodeRelativeTo(fromNode, relativePath.getParent());
+ }
+ } catch (org.jboss.dna.graph.property.PathNotFoundException e) {
+ throw new ItemNotFoundException(e.getMessage(), e.getCause());
+ } catch (RepositorySourceException e) {
+ throw new RepositoryException(e.getMessage(), e.getCause());
+ } catch (AccessControlException e) {
+ throw new AccessDeniedException(e.getMessage(), e.getCause());
}
// JSR-170 doesn't allow children and proeprties to have the same name, but this is relaxed in JSR-283.
// But JSR-283 Section 3.3.4 states "The method Session.getItem will return the item at the specified path
// if there is only one such item, if there is both a node and a property at the specified path, getItem
// will return the node." Therefore, look for a child first ...
- ChildNode child = parent.getChildren().getChild(lastSegment);
- if (child != null) {
- return findJcrNode(child.getUuid());
+ if (parent.hasChild(lastSegment)) {
+ // There is a child!
+ Node<JcrNodePayload, JcrPropertyPayload> child = parent.getChild(lastSegment);
+ return child.getPayload().getJcrNode();
}
// Otherwise it should be a property ...
- PropertyInfo propertyInfo = parent.getProperty(lastSegment.getName());
+ org.jboss.dna.graph.session.GraphSession.PropertyInfo<JcrPropertyPayload> propertyInfo = parent.getProperty(lastSegment.getName());
if (propertyInfo != null) {
- return findJcrProperty(propertyInfo.getPropertyId());
+ return propertyInfo.getPayload().getJcrProperty();
}
// It was not found, so prepare a good exception message ...
String msg = null;
- if (findNodeInfoForRoot().getUuid().equals(uuidOfReferenceNode)) {
+ if (from.equals(graphSession.getRoot().getNodeId())) {
// The reference node was the root, so use this fact to convert the path to an absolute path in the message
Path absolutePath = rootPath.resolve(relativePath);
- msg = JcrI18n.itemNotFoundAtPath.text(absolutePath, workspaceName);
+ msg = JcrI18n.itemNotFoundAtPath.text(readable(absolutePath), workspaceName);
} else {
// Find the path of the reference node ...
- Path referenceNodePath = getPathFor(uuidOfReferenceNode);
- msg = JcrI18n.itemNotFoundAtPathRelativeToReferenceNode.text(relativePath, referenceNodePath, workspaceName);
+ Path referenceNodePath = fromNode.getPath();
+ msg = JcrI18n.itemNotFoundAtPathRelativeToReferenceNode.text(readable(relativePath),
+ readable(referenceNodePath),
+ workspaceName);
}
throw new ItemNotFoundException(msg);
}
/**
* Obtain an {@link NodeEditor editor} that can be used to manipulate the properties or children on the node identified by the
- * supplied UUID. The node must exist prior to this call, either as a node that exists in the workspace or as a node that was
- * created within this session but not yet persisted to the workspace. This method returns an editor that batches all changes
- * in transient storage from where they can be persisted to the repository by {@link javax.jcr.Session#save() saving the
- * session} or by {@link javax.jcr.Item#save() saving an ancestor}.
+ * supplied identifier and path. The node must exist prior to this call, either as a node that exists in the workspace or as a
+ * node that was created within this session but not yet persisted to the workspace. This method returns an editor that
+ * batches all changes in transient storage from where they can be persisted to the repository by
+ * {@link javax.jcr.Session#save() saving the session} or by {@link javax.jcr.Item#save() saving an ancestor}.
*
- * @param uuid the UUID of the node that is to be changed; may not be null and must represent an <i>existing</i> node
+ * @param node the node
* @return the editor; never null
- * @throws ItemNotFoundException if no such node could be found in the session or workspace
- * @throws InvalidItemStateException if the item has been marked for deletion within this session
- * @throws RepositoryException if any other error occurs while reading information from the repository
*/
- public NodeEditor getEditorFor( UUID uuid ) throws ItemNotFoundException, InvalidItemStateException, RepositoryException {
- return getEditorFor(uuid, this.operations);
+ public NodeEditor getEditorFor( Node<JcrNodePayload, JcrPropertyPayload> node ) {
+ return new NodeEditor(node);
}
/**
* Obtain an {@link NodeEditor editor} that can be used to manipulate the properties or children on the node identified by the
- * supplied UUID. The node must exist prior to this call, either as a node that exists in the workspace or as a node that was
- * created within this session but not yet persisted to the workspace.
+ * supplied identifier and path. The node must exist prior to this call, either as a node that exists in the workspace or as a
+ * node that was created within this session but not yet persisted to the workspace. This method returns an editor that
+ * batches all changes in transient storage from where they can be persisted to the repository by
+ * {@link javax.jcr.Session#save() saving the session} or by {@link javax.jcr.Item#save() saving an ancestor}.
*
- * @param uuid the UUID of the node that is to be changed; may not be null and must represent an <i>existing</i> node
- * @param operationsBatch the {@link Graph.Batch} to use for batching operations. This should be populated for direct
- * persistence (q.v. section 7.1.3.7 of the JCR 1.0.1 specification) and should be null to use session-based
- * persistence.
+ * @param id the identifier for the node
+ * @param absolutePath the absolute path to the node; may not be null
* @return the editor; never null
* @throws ItemNotFoundException if no such node could be found in the session or workspace
+ * @throws AccessDeniedException if the caller does not have privilege to read the reference or result node
* @throws InvalidItemStateException if the item has been marked for deletion within this session
* @throws RepositoryException if any other error occurs while reading information from the repository
*/
- public NodeEditor getEditorFor( UUID uuid,
- Graph.Batch operationsBatch )
- throws ItemNotFoundException, InvalidItemStateException, RepositoryException {
- // See if we already have something in the changed nodes ...
- ChangedNodeInfo info = changedNodes.get(uuid);
- Location currentLocation = null;
- if (info == null) {
- // Or in the cache ...
- NodeInfo cached = cachedNodes.get(uuid);
- if (cached == null) {
- cached = loadFromGraph(null, uuid);
+ public NodeEditor getEditorFor( NodeId id,
+ Path absolutePath )
+ throws ItemNotFoundException, AccessDeniedException, InvalidItemStateException, RepositoryException {
+ Node<JcrNodePayload, JcrPropertyPayload> node = this.graphSession.findNodeWith(id, absolutePath);
+ return new NodeEditor(node);
+ }
+
+ /**
+ * Returns the absolute path of the node in the specified workspace that corresponds to this node.
+ * <p>
+ * The corresponding node is defined as the node in srcWorkspace with the same UUID as this node or, if this node has no UUID,
+ * the same path relative to the nearest ancestor that does have a UUID, or the root node, whichever comes first. This is
+ * qualified by the requirement that referencable nodes only correspond with other referencables and non-referenceables with
+ * other non-referenceables.
+ * </p>
+ *
+ * @param workspaceName the name of the workspace
+ * @param uuid the UUID of the corresponding node, or the UUID of the closest ancestor that is referenceable
+ * @param relativePath the relative path from the referenceable node, or null if the supplied UUID identifies the
+ * corresponding node
+ * @return the absolute path to the corresponding node in the workspace; never null
+ * @throws NoSuchWorkspaceException if the specified workspace does not exist
+ * @throws ItemNotFoundException if no corresponding node exists
+ * @throws AccessDeniedException if the current session does not have sufficient rights to perform this operation
+ * @throws RepositoryException if another exception occurs
+ */
+ Path getPathForCorrespondingNode( String workspaceName,
+ UUID uuid,
+ Path relativePath )
+ throws NoSuchWorkspaceException, AccessDeniedException, ItemNotFoundException, RepositoryException {
+ assert workspaceName != null;
+ assert uuid != null || relativePath != null;
+
+ try {
+ try {
+ store.useWorkspace(workspaceName);
+ } catch (InvalidWorkspaceException iwe) {
+ throw new NoSuchWorkspaceException(JcrI18n.workspaceNameIsInvalid.text(store.getSourceName(), workspaceName));
}
- // Now put into the changed nodes ...
- info = new ChangedNodeInfo(cached);
- changedNodes.put(uuid, info);
- currentLocation = info.getOriginalLocation();
- } else {
- // compute the current location ...
- currentLocation = Location.create(getPathFor(info), uuid);
+ org.jboss.dna.graph.Node node;
+ if (uuid != null) {
+ node = store.getNodeAt(uuid);
+
+ if (relativePath != null) {
+ Path nodePath = node.getLocation().getPath();
+ Path absolutePath = relativePath.resolveAgainst(nodePath);
+ node = store.getNodeAt(absolutePath);
+ }
+
+ } else {
+ Path absolutePath = pathFactory.createAbsolutePath(relativePath.getSegmentsList());
+ node = store.getNodeAt(absolutePath);
+ }
+ assert node != null;
+
+ Path path = node.getLocation().getPath();
+ try {
+ this.session().checkPermission(workspaceName, path, "read");
+ } catch (AccessControlException ace) {
+ throw new AccessDeniedException(ace);
+ }
+ return path;
+ } catch (org.jboss.dna.graph.property.PathNotFoundException pnfe) {
+ throw new ItemNotFoundException(pnfe);
+ } finally {
+ store.useWorkspace(this.workspaceName);
}
- return new NodeEditor(info, currentLocation, operationsBatch == null ? this.operations : operationsBatch);
}
/**
* An interface used to manipulate a node's properties and children.
*/
public final class NodeEditor {
- private final ChangedNodeInfo node;
- private final Location currentLocation;
- private final Graph.Batch operations;
+ private final Node<JcrNodePayload, JcrPropertyPayload> node;
- protected NodeEditor( ChangedNodeInfo node,
- Location currentLocation,
- Graph.Batch operations ) {
+ protected NodeEditor( Node<JcrNodePayload, JcrPropertyPayload> node ) {
this.node = node;
- this.currentLocation = currentLocation;
- this.operations = operations;
}
/**
@@ -1052,20 +808,17 @@
boolean isMultiple )
throws javax.jcr.ValueFormatException, RepositoryException {
// Check for existing single-valued property - can't set multiple values on single-valued property
- PropertyInfo propInfo = this.node.getProperty(propertyName);
+ PropertyInfo<JcrPropertyPayload> propInfo = this.node.getProperty(propertyName);
if (propInfo != null && propInfo.isMultiValued() != isMultiple) {
- NamespaceRegistry namespaces = SessionCache.this.namespaces;
String workspaceName = SessionCache.this.workspaceName();
+ String propName = readable(propertyName);
+ String path = readable(node.getPath());
if (isMultiple) {
I18n msg = JcrI18n.unableToSetSingleValuedPropertyUsingMultipleValues;
- throw new javax.jcr.ValueFormatException(msg.text(propertyName.getString(namespaces),
- getPathFor(this.node).getString(namespaces),
- workspaceName));
+ throw new javax.jcr.ValueFormatException(msg.text(propName, path, workspaceName));
}
I18n msg = JcrI18n.unableToSetMultiValuedPropertyUsingSingleValue;
- throw new javax.jcr.ValueFormatException(msg.text(propertyName.getString(namespaces),
- getPathFor(this.node).getString(namespaces),
- workspaceName));
+ throw new javax.jcr.ValueFormatException(msg.text(propName, path, workspaceName));
}
}
@@ -1076,14 +829,14 @@
*
* @param name the property name; may not be null
* @param value the new property values; may not be null
- * @return the identifier for the property; never null
+ * @return the JCR property object for the property; never null
* @throws ConstraintViolationException if the property could not be set because of a node type constraint or property
* definition constraint
* @throws AccessDeniedException if the current session does not have the requisite privileges to perform this task
* @throws RepositoryException if any other error occurs
*/
- public PropertyId setProperty( Name name,
- JcrValue value )
+ public AbstractJcrProperty setProperty( Name name,
+ JcrValue value )
throws AccessDeniedException, ConstraintViolationException, RepositoryException {
return setProperty(name, value, true);
}
@@ -1096,35 +849,30 @@
* @param name the property name; may not be null
* @param value the new property values; may not be null
* @param skipProtected indicates whether protected property definitions should be ignored
- * @return the identifier for the property; never null
+ * @return the JCR property object for the property; never null
* @throws ConstraintViolationException if the property could not be set because of a node type constraint or property
* definition constraint
* @throws AccessDeniedException if the current session does not have the requisite privileges to perform this task
* @throws RepositoryException if any other error occurs
*/
- public PropertyId setProperty( Name name,
- JcrValue value,
- boolean skipProtected )
+ public AbstractJcrProperty setProperty( Name name,
+ JcrValue value,
+ boolean skipProtected )
throws AccessDeniedException, ConstraintViolationException, RepositoryException {
assert name != null;
assert value != null;
- SessionCache.this.checkPermission(node, JcrSession.JCR_SET_PROPERTY_PERMISSION);
+ checkCardinalityOfExistingProperty(name, false);
JcrPropertyDefinition definition = null;
- PropertyId id = null;
- checkCardinalityOfExistingProperty(name, false);
-
// Look for an existing property ...
- PropertyInfo existing = node.getProperty(name);
+ PropertyInfo<JcrPropertyPayload> existing = node.getProperty(name);
if (existing != null) {
- // Reuse the existing ID ...
- id = existing.getPropertyId();
// We're replacing an existing property, but we still need to check that the property definition
// (still) defines a type. So, find the property definition for the existing property ...
- definition = nodeTypes().getPropertyDefinition(existing.getDefinitionId());
+ definition = nodeTypes().getPropertyDefinition(existing.getPayload().getPropertyDefinitionId());
if (definition != null) {
// The definition's require type must match the value's ...
@@ -1137,14 +885,12 @@
if (!definition.satisfiesConstraints(value)) definition = null;
}
}
- } else {
- // This is a new property, so create a new ID ...
- id = new PropertyId(node.getUuid(), name);
}
+ JcrNodePayload payload = node.getPayload();
if (definition == null) {
// Look for a definition ...
- definition = nodeTypes().findPropertyDefinition(node.getPrimaryTypeName(),
- node.getMixinTypeNames(),
+ definition = nodeTypes().findPropertyDefinition(payload.getPrimaryTypeName(),
+ payload.getMixinTypeNames(),
name,
value,
true,
@@ -1167,14 +913,30 @@
}
Property dnaProp = propertyFactory.create(name, objValue);
- // Create the property info ...
- PropertyInfo newProperty = new PropertyInfo(id, definition.getId(), propertyType, dnaProp, definition.isMultiple(),
- existing == null, existing != null);
-
- // Finally update the cached information and record the change ...
- node.setProperty(newProperty, factories());
- operations.set(dnaProp).on(currentLocation);
- return newProperty.getPropertyId();
+ try {
+ // Create (or reuse) the JCR Property object ...
+ AbstractJcrProperty jcrProp = null;
+ if (existing != null) {
+ jcrProp = existing.getPayload().getJcrProperty();
+ } else {
+ AbstractJcrNode jcrNode = payload.getJcrNode();
+ if (definition.isMultiple()) {
+ jcrProp = new JcrMultiValueProperty(SessionCache.this, jcrNode, dnaProp.getName());
+ } else {
+ jcrProp = new JcrSingleValueProperty(SessionCache.this, jcrNode, dnaProp.getName());
+ }
+ }
+ assert jcrProp != null;
+ JcrPropertyPayload propPayload = new JcrPropertyPayload(definition.getId(), propertyType, jcrProp);
+ node.setProperty(dnaProp, definition.isMultiple(), propPayload);
+ return jcrProp;
+ } catch (ValidationException e) {
+ throw new ConstraintViolationException(e.getMessage(), e.getCause());
+ } catch (RepositorySourceException e) {
+ throw new RepositoryException(e.getMessage(), e.getCause());
+ } catch (AccessControlException e) {
+ throw new AccessDeniedException(e.getMessage(), e.getCause());
+ }
}
/**
@@ -1188,16 +950,16 @@
* @param values new property values, all of which must have the same {@link Value#getType() property type}; may not be
* null but may be empty
* @param valueType
- * @return the identifier for the property; never null
+ * @return the JCR property object for the property; never null
* @throws ConstraintViolationException if the property could not be set because of a node type constraint or property
* definition constraint
* @throws javax.jcr.ValueFormatException
* @throws AccessDeniedException if the current session does not have the requisite privileges to perform this task
* @throws RepositoryException if any other error occurs
*/
- public PropertyId setProperty( Name name,
- Value[] values,
- int valueType )
+ public AbstractJcrProperty setProperty( Name name,
+ Value[] values,
+ int valueType )
throws AccessDeniedException, ConstraintViolationException, RepositoryException, javax.jcr.ValueFormatException {
return setProperty(name, values, valueType, true);
}
@@ -1212,22 +974,21 @@
* @param skipProtected if true, attempts to set protected properties will fail. If false, attempts to set protected
* properties will be allowed.
* @param valueType
- * @return the identifier for the property; never null
+ * @return the JCR property object for the property; never null
* @throws ConstraintViolationException if the property could not be set because of a node type constraint or property
* definition constraint
* @throws javax.jcr.ValueFormatException
* @throws AccessDeniedException if the current session does not have the requisite privileges to perform this task
* @throws RepositoryException if any other error occurs
*/
- public PropertyId setProperty( Name name,
- Value[] values,
- int valueType,
- boolean skipProtected )
+ public AbstractJcrProperty setProperty( Name name,
+ Value[] values,
+ int valueType,
+ boolean skipProtected )
throws AccessDeniedException, ConstraintViolationException, RepositoryException, javax.jcr.ValueFormatException {
assert name != null;
assert values != null;
- SessionCache.this.checkPermission(node, JcrSession.JCR_SET_PROPERTY_PERMISSION);
checkCardinalityOfExistingProperty(name, true);
int len = values.length;
@@ -1254,10 +1015,9 @@
sb.append(']');
String propType = PropertyType.nameFromValue(expectedType);
I18n msg = JcrI18n.allPropertyValuesMustHaveSameType;
- NamespaceRegistry namespaces = SessionCache.this.namespaces;
- String path = getPathFor(node.getUuid()).getString(namespaces);
+ String path = readable(node.getPath());
String workspaceName = SessionCache.this.workspaceName();
- throw new javax.jcr.ValueFormatException(msg.text(name, values, propType, path, workspaceName));
+ throw new javax.jcr.ValueFormatException(msg.text(readable(name), values, propType, path, workspaceName));
}
if (value.getType() != valueType && valueType != PropertyType.UNDEFINED) {
value = ((JcrValue)value).asType(valueType);
@@ -1273,17 +1033,13 @@
int numValues = newValues.length;
JcrPropertyDefinition definition = null;
- PropertyId id = null;
// Look for an existing property ...
- PropertyInfo existing = node.getProperty(name);
+ PropertyInfo<JcrPropertyPayload> existing = node.getProperty(name);
if (existing != null) {
- // Reuse the existing ID ...
- id = existing.getPropertyId();
-
// We're replacing an existing property, but we still need to check that the property definition
// (still) defines a type. So, find the property definition for the existing property ...
- definition = nodeTypes().getPropertyDefinition(existing.getDefinitionId());
+ definition = nodeTypes().getPropertyDefinition(existing.getPayload().getPropertyDefinitionId());
if (definition != null) {
// The definition's require type must match the value's ...
@@ -1302,14 +1058,12 @@
}
}
}
- } else {
- // This is a new property, so create a new ID ...
- id = new PropertyId(node.getUuid(), name);
}
+ JcrNodePayload payload = node.getPayload();
if (definition == null) {
// Look for a definition ...
- definition = nodeTypes().findPropertyDefinition(node.getPrimaryTypeName(),
- node.getMixinTypeNames(),
+ definition = nodeTypes().findPropertyDefinition(payload.getPrimaryTypeName(),
+ payload.getMixinTypeNames(),
name,
newValues,
skipProtected);
@@ -1338,31 +1092,30 @@
}
Property dnaProp = propertyFactory.create(name, objValues);
- // Create the property info ...
- PropertyInfo newProperty = new PropertyInfo(id, definition.getId(), propertyType, dnaProp, definition.isMultiple(),
- existing == null, existing != null);
-
- // Finally update the cached information and record the change ...
- node.setProperty(newProperty, factories());
- operations.set(dnaProp).on(currentLocation);
-
- // If there is a single value, we need to record that this property is actually a multi-valued property definition ...
- if (numValues == 1) {
- if (node.setSingleMultiProperty(name)) {
- Set<Name> names = node.getSingleMultiPropertyNames();
- // Added this property name to the set, so record the change ...
- PropertyInfo singleMulti = createSingleMultiplePropertyInfo(node.getUuid(),
- node.getPrimaryTypeName(),
- node.getMixinTypeNames(),
- names);
- node.setProperty(singleMulti, factories());
- operations.set(singleMulti.getProperty()).on(currentLocation);
+ try {
+ // Create (or reuse) the JCR Property object ...
+ AbstractJcrProperty jcrProp = null;
+ if (existing != null) {
+ jcrProp = existing.getPayload().getJcrProperty();
+ } else {
+ AbstractJcrNode jcrNode = payload.getJcrNode();
+ if (definition.isMultiple()) {
+ jcrProp = new JcrMultiValueProperty(SessionCache.this, jcrNode, dnaProp.getName());
+ } else {
+ jcrProp = new JcrSingleValueProperty(SessionCache.this, jcrNode, dnaProp.getName());
+ }
}
- } else {
- removeSingleMultiProperty(node, name);
+ assert jcrProp != null;
+ JcrPropertyPayload propPayload = new JcrPropertyPayload(definition.getId(), propertyType, jcrProp);
+ node.setProperty(dnaProp, definition.isMultiple(), propPayload);
+ return jcrProp;
+ } catch (ValidationException e) {
+ throw new ConstraintViolationException(e.getMessage(), e.getCause());
+ } catch (RepositorySourceException e) {
+ throw new RepositoryException(e.getMessage(), e.getCause());
+ } catch (AccessControlException e) {
+ throw new AccessDeniedException(e.getMessage(), e.getCause());
}
-
- return newProperty.getPropertyId();
}
/**
@@ -1374,63 +1127,37 @@
* @throws RepositoryException if any other error occurs
*/
public boolean removeProperty( Name name ) throws AccessDeniedException, RepositoryException {
- SessionCache.this.checkPermission(node, JcrSession.JCR_REMOVE_PERMISSION);
-
- PropertyInfo info = node.removeProperty(name);
- if (info != null) {
- operations.remove(name).on(currentLocation);
- // Is this named in the single-multi property names? ...
- removeSingleMultiProperty(node, name);
- return true;
+ try {
+ return node.removeProperty(name) != null;
+ } catch (ValidationException e) {
+ throw new ConstraintViolationException(e.getMessage(), e.getCause());
+ } catch (RepositorySourceException e) {
+ throw new RepositoryException(e.getMessage(), e.getCause());
+ } catch (AccessControlException e) {
+ throw new AccessDeniedException(e.getMessage(), e.getCause());
}
- return false;
}
- private void removeSingleMultiProperty( ChangedNodeInfo node,
- Name propertyName ) {
- if (node.removeSingleMultiProperty(propertyName)) {
- Set<Name> names = node.getSingleMultiPropertyNames();
- if (names == null || names.isEmpty()) {
- node.removeProperty(DnaIntLexicon.MULTI_VALUED_PROPERTIES);
- operations.remove(DnaIntLexicon.MULTI_VALUED_PROPERTIES).on(currentLocation);
- } else {
- // Added this property name to the set, so record the change ...
- PropertyInfo singleMulti = createSingleMultiplePropertyInfo(node.getUuid(),
- node.getPrimaryTypeName(),
- node.getMixinTypeNames(),
- names);
- node.setProperty(singleMulti, factories());
- operations.set(singleMulti.getProperty()).on(currentLocation);
- }
- }
- }
-
+ /**
+ * Move the specified child to be located immediately before the other supplied node.
+ *
+ * @param childToBeMoved the path segment specifying the child that is to be moved
+ * @param before the path segment of the node before which the {@code childToBeMoved} should be placed, or null if the
+ * node should be moved to the end
+ * @throws IllegalArgumentException if either segment is null or does not specify an existing node
+ * @throws AccessDeniedException if the current session does not have the requisite permissions to remove this property
+ * @throws RepositoryException if any other error occurs
+ */
public void orderChildBefore( Path.Segment childToBeMoved,
- Path.Segment before ) {
- // Clear the path cache ...
- SessionCache.this.pathCache.clear();
-
- PathFactory pathFactory = SessionCache.this.pathFactory;
- Path thisPath = this.currentLocation.getPath();
- UUID fromUuid = this.node.getChildren().getChild(childToBeMoved).getUuid();
- Location fromLocation = Location.create(pathFactory.create(thisPath, childToBeMoved), fromUuid);
-
- Children children = this.node.getChildren();
- ChildNode nodeToBeMoved = children.getChild(childToBeMoved);
- this.node.removeChild(nodeToBeMoved.getUuid(), pathFactory);
-
- if (before == null) {
- this.node.addChild(nodeToBeMoved.getName(), nodeToBeMoved.getUuid(), pathFactory);
- // Moving the node into its parent will remove it from its current spot in the child list and re-add it to the end
- operations.move(fromLocation).into(this.currentLocation);
-
- } else {
- Path beforePath = pathFactory.create(thisPath, before);
- UUID beforeUuid = this.node.getChildren().getChild(before).getUuid();
- Location beforeLocation = Location.create(beforePath, beforeUuid);
-
- this.node.addChild(nodeToBeMoved.getName(), before, nodeToBeMoved.getUuid(), pathFactory);
- operations.move(fromLocation).before(beforeLocation);
+ Path.Segment before ) throws AccessDeniedException, RepositoryException {
+ try {
+ node.orderChildBefore(childToBeMoved, before);
+ } catch (ValidationException e) {
+ throw new ConstraintViolationException(e.getMessage(), e.getCause());
+ } catch (RepositorySourceException e) {
+ throw new RepositoryException(e.getMessage(), e.getCause());
+ } catch (AccessControlException e) {
+ throw new AccessDeniedException(e.getMessage(), e.getCause());
}
}
@@ -1440,133 +1167,127 @@
*
* @param child the UUID of the existing node; may not be null
* @param newNodeName
- * @return the representation of the newly-added child, which includes the {@link ChildNode#getSnsIndex()
- * same-name-sibling index}
+ * @return the newly-added child in its location under the new parent; never null
* @throws ItemNotFoundException if the specified child node could be found in the session or workspace
* @throws InvalidItemStateException if the specified child has been marked for deletion within this session
* @throws ConstraintViolationException if moving the node into this node violates this node's definition
* @throws RepositoryException if any other error occurs while reading information from the repository
*/
- public ChildNode moveToBeChild( AbstractJcrNode child,
- Name newNodeName )
+ public Node<JcrNodePayload, JcrPropertyPayload> moveToBeChild( AbstractJcrNode child,
+ Name newNodeName )
throws ItemNotFoundException, InvalidItemStateException, ConstraintViolationException, RepositoryException {
- UUID nodeUuid = child.nodeUuid;
- if (nodeUuid.equals(node.getUuid()) || isAncestor(nodeUuid)) {
- Path pathOfNode = getPathFor(nodeUuid);
- Path thisPath = currentLocation.getPath();
- String msg = JcrI18n.unableToMoveNodeToBeChildOfDecendent.text(pathOfNode, thisPath, workspaceName());
+ // Look up the child and verify that the child can move into this node ...
+ Node<JcrNodePayload, JcrPropertyPayload> existingChild = findNode(child.nodeId, child.location.getPath());
+ if (existingChild.equals(node) || node.isAtOrBelow(existingChild)) {
+ String pathOfChild = readable(existingChild.getPath());
+ String thisPath = readable(node.getPath());
+ String msg = JcrI18n.unableToMoveNodeToBeChildOfDecendent.text(pathOfChild, thisPath, workspaceName());
throw new RepositoryException(msg);
}
- // Is the node already a child?
- boolean nameDoesNotChange = newNodeName == null || newNodeName.equals(child.path().getLastSegment());
- ChildNode existingChild = node.getChildren().getChild(nodeUuid);
- if (existingChild != null && nameDoesNotChange) return existingChild;
+ // Find the best node definition for the child in the new parent, or throw an exception if there is none ...
+ JcrNodeDefinition defn = findBestNodeDefinition(node, newNodeName, child.getPrimaryTypeName());
- JcrNodeDefinition definition = findBestNodeDefinition(node.getUuid(), newNodeName, child.getPrimaryTypeName());
+ try {
+ // Perform the move ...
+ existingChild.moveTo(node, newNodeName);
- // Get an editor for the child (in its current location) and one for its parent ...
- NodeEditor newChildEditor = getEditorFor(nodeUuid);
+ NodeDefinitionId existingChildDefinitionId = existingChild.getPayload().getDefinitionId();
+ if (defn.getId().equals(existingChildDefinitionId)) {
+ // The node definition changed, so try to set the property ...
+ NodeEditor newChildEditor = getEditorFor(existingChild);
+ try {
+ JcrValue value = new JcrValue(factories(), SessionCache.this, PropertyType.STRING, defn.getId()
+ .getString());
+ newChildEditor.setProperty(DnaIntLexicon.NODE_DEFINITON, value);
+ } catch (ConstraintViolationException e) {
+ // We can't set this property on the node (according to the node definition).
+ // But we still want the node info to have the correct node definition.
+ // When it is reloaded into a cache (after being persisted), the correct node definition
+ // will be computed again ...
+ existingChild.setPayload(existingChild.getPayload().with(defn.getId()));
- if (!definition.getId().equals(node.getDefinitionId())) {
- // The node definition changed, so try to set the property ...
- try {
- JcrValue value = new JcrValue(factories(), SessionCache.this, PropertyType.STRING,
- definition.getId().getString());
- newChildEditor.setProperty(DnaIntLexicon.NODE_DEFINITON, value);
- } catch (ConstraintViolationException e) {
- // We can't set this property on the node (according to the node definition).
- // But we still want the node info to have the correct node definition.
- // When it is reloaded into a cache (after being persisted), the correct node definition
- // will be computed again ...
- node.setDefinitionId(definition.getId());
-
- // And remove the property from the info ...
- newChildEditor.removeProperty(DnaIntLexicon.NODE_DEFINITON);
+ // And remove the property from the info ...
+ newChildEditor.removeProperty(DnaIntLexicon.NODE_DEFINITON);
+ }
}
+ return existingChild;
+ } catch (ValidationException e) {
+ throw new ConstraintViolationException(e.getMessage(), e.getCause());
+ } catch (RepositorySourceException e) {
+ throw new RepositoryException(e.getMessage(), e.getCause());
+ } catch (AccessControlException e) {
+ throw new AccessDeniedException(e.getMessage(), e.getCause());
}
-
- // Clear the path cache ...
- SessionCache.this.pathCache.clear();
-
- // Remove the node from the current parent and add it to this ...
- ChangedNodeInfo newChildInfo = newChildEditor.node;
- UUID existingParent = newChildInfo.getParent();
-
- ChangedNodeInfo existingParentInfo = getEditorFor(existingParent).node;
- existingChild = existingParentInfo.removeChild(nodeUuid, pathFactory);
- ChildNode newChild = node.addChild(newNodeName, existingChild.getUuid(), pathFactory);
-
- // Set the child's changed representation to point to this node as its parent ...
- newChildInfo.setParent(node.getUuid());
-
- // Set up the peer relationship between the two nodes that must be saved together
- node.addPeer(existingParent);
- existingParentInfo.addPeer(node.getUuid());
-
- // Set up the peer relationship between the two nodes that must be saved together
- node.addPeer(existingParent);
- existingParentInfo.addPeer(node.getUuid());
-
- // Now, record the operation to do this ...
- if (nameDoesNotChange) {
- operations.move(newChildEditor.currentLocation).into(currentLocation);
- } else {
- operations.move(newChildEditor.currentLocation).as(newNodeName).into(currentLocation);
- }
-
- return newChild;
}
public void addMixin( JcrNodeType mixinCandidateType ) throws javax.jcr.ValueFormatException, RepositoryException {
- PropertyInfo existingMixinProperty = node.getProperty(JcrLexicon.MIXIN_TYPES);
+ try {
+ PropertyInfo<JcrPropertyPayload> existingMixinProperty = node.getProperty(JcrLexicon.MIXIN_TYPES);
- // getProperty(JcrLexicon.MIXIN_TYPES);
- Value[] existingMixinValues;
- if (existingMixinProperty != null) {
- existingMixinValues = findJcrProperty(existingMixinProperty.getPropertyId()).getValues();
- } else {
- existingMixinValues = new Value[0];
- }
+ // getProperty(JcrLexicon.MIXIN_TYPES);
+ Value[] existingMixinValues;
+ if (existingMixinProperty != null) {
+ existingMixinValues = existingMixinProperty.getPayload().getJcrProperty().getValues();
+ } else {
+ existingMixinValues = new Value[0];
+ }
- Value[] newMixinValues = new Value[existingMixinValues.length + 1];
- System.arraycopy(existingMixinValues, 0, newMixinValues, 0, existingMixinValues.length);
- newMixinValues[newMixinValues.length - 1] = new JcrValue(factories(), SessionCache.this, PropertyType.NAME,
- mixinCandidateType.getInternalName());
+ Value[] newMixinValues = new Value[existingMixinValues.length + 1];
+ System.arraycopy(existingMixinValues, 0, newMixinValues, 0, existingMixinValues.length);
+ newMixinValues[newMixinValues.length - 1] = new JcrValue(factories(), SessionCache.this, PropertyType.NAME,
+ mixinCandidateType.getInternalName());
- findJcrProperty(setProperty(JcrLexicon.MIXIN_TYPES, newMixinValues, PropertyType.NAME, false));
+ setProperty(JcrLexicon.MIXIN_TYPES, newMixinValues, PropertyType.NAME, false);
- // ------------------------------------------------------------------------------
- // Create any auto-created properties/nodes from new type
- // ------------------------------------------------------------------------------
+ // ------------------------------------------------------------------------------
+ // Create any auto-created properties/nodes from new type
+ // ------------------------------------------------------------------------------
- for (JcrPropertyDefinition propertyDefinition : mixinCandidateType.propertyDefinitions()) {
- if (propertyDefinition.isAutoCreated() && !propertyDefinition.isProtected()) {
- if (null == findJcrProperty(new PropertyId(node.getUuid(), propertyDefinition.getInternalName()))) {
- assert propertyDefinition.getDefaultValues() != null;
- if (propertyDefinition.isMultiple()) {
- setProperty(propertyDefinition.getInternalName(),
- propertyDefinition.getDefaultValues(),
- propertyDefinition.getRequiredType());
- } else {
- assert propertyDefinition.getDefaultValues().length == 1;
- setProperty(propertyDefinition.getInternalName(), (JcrValue)propertyDefinition.getDefaultValues()[0]);
+ for (JcrPropertyDefinition propertyDefinition : mixinCandidateType.propertyDefinitions()) {
+ if (propertyDefinition.isAutoCreated() && !propertyDefinition.isProtected()) {
+ PropertyInfo<JcrPropertyPayload> autoCreatedProp = node.getProperty(propertyDefinition.getInternalName());
+ if (autoCreatedProp == null) {
+ // We have to 'auto-create' the property ...
+ assert propertyDefinition.getDefaultValues() != null;
+ if (propertyDefinition.isMultiple()) {
+ setProperty(propertyDefinition.getInternalName(),
+ propertyDefinition.getDefaultValues(),
+ propertyDefinition.getRequiredType());
+ } else {
+ assert propertyDefinition.getDefaultValues().length == 1;
+ setProperty(propertyDefinition.getInternalName(),
+ (JcrValue)propertyDefinition.getDefaultValues()[0]);
+ }
}
}
}
- }
- for (JcrNodeDefinition nodeDefinition : mixinCandidateType.childNodeDefinitions()) {
- if (nodeDefinition.isAutoCreated() && !nodeDefinition.isProtected()) {
- Name nodeName = nodeDefinition.getInternalName();
- if (!node.getChildren().getChildren(nodeName).hasNext()) {
- assert nodeDefinition.getDefaultPrimaryType() != null;
- createChild(nodeName, (UUID)null, ((JcrNodeType)nodeDefinition.getDefaultPrimaryType()).getInternalName());
+ for (JcrNodeDefinition nodeDefinition : mixinCandidateType.childNodeDefinitions()) {
+ if (nodeDefinition.isAutoCreated() && !nodeDefinition.isProtected()) {
+ Name nodeName = nodeDefinition.getInternalName();
+ if (node.getChildrenCount(nodeName) == 0) {
+ assert nodeDefinition.getDefaultPrimaryType() != null;
+ createChild(nodeName,
+ (UUID)null,
+ ((JcrNodeType)nodeDefinition.getDefaultPrimaryType()).getInternalName());
+ }
}
}
- }
+ if (JcrMixLexicon.REFERENCEABLE.equals(mixinCandidateType.getInternalName())) {
+ // This node is now referenceable, so make sure there is a UUID property ...
+ UUID uuid = node.getLocation().getUuid();
+ if (uuid == null) uuid = UUID.randomUUID();
+ JcrValue value = new JcrValue(factories(), SessionCache.this, PropertyType.STRING, uuid);
+ setProperty(JcrLexicon.UUID, value, false);
+ }
+ } catch (RepositorySourceException e) {
+ throw new RepositoryException(e.getMessage(), e.getCause());
+ } catch (AccessControlException e) {
+ throw new AccessDeniedException(e.getMessage(), e.getCause());
+ }
}
/**
@@ -1575,190 +1296,133 @@
* @param name the name for the new child; may not be null
* @param desiredUuid the desired UUID, or null if the UUID for the child should be generated automatically
* @param primaryTypeName the name of the primary type for the new node
- * @return the representation of the newly-created child, which includes the {@link ChildNode#getSnsIndex()
- * same-name-sibling index}
+ * @return the representation of the newly-created child
* @throws InvalidItemStateException if the specified child has been marked for deletion within this session
* @throws ConstraintViolationException if moving the node into this node violates this node's definition
* @throws NoSuchNodeTypeException if the node type for the primary type could not be found
* @throws AccessDeniedException if the current session does not have the requisite privileges to perform this task
* @throws RepositoryException if any other error occurs while reading information from the repository
*/
- public ChildNode createChild( Name name,
- UUID desiredUuid,
- Name primaryTypeName )
+ public JcrNode createChild( Name name,
+ UUID desiredUuid,
+ Name primaryTypeName )
throws InvalidItemStateException, ConstraintViolationException, AccessDeniedException, RepositoryException {
- SessionCache.this.checkPermission(node, JcrSession.JCR_ADD_NODE_PERMISSION);
-
if (desiredUuid == null) desiredUuid = UUID.randomUUID();
+ try {
- // Verify that this node accepts a child of the supplied name (given any existing SNS nodes) ...
- int numSns = node.getChildren().getCountOfSameNameSiblingsWithName(name) + 1;
- JcrNodeDefinition definition = nodeTypes().findChildNodeDefinition(node.getPrimaryTypeName(),
- node.getMixinTypeNames(),
- name,
- primaryTypeName,
- numSns,
- true);
- // Make sure there was a valid child node definition ...
- if (definition == null) {
+ // Verify that this node accepts a child of the supplied name (given any existing SNS nodes) ...
+ int numSns = node.getChildrenCount(name) + 1;
+ JcrNodePayload payload = node.getPayload();
+ JcrNodeDefinition definition = nodeTypes().findChildNodeDefinition(payload.getPrimaryTypeName(),
+ payload.getMixinTypeNames(),
+ name,
+ primaryTypeName,
+ numSns,
+ true);
+ // Make sure there was a valid child node definition ...
+ if (definition == null) {
- // Check if the definition would have worked with less SNS
- definition = nodeTypes().findChildNodeDefinition(node.getPrimaryTypeName(),
- node.getMixinTypeNames(),
- name,
- primaryTypeName,
- numSns - 1,
- true);
- if (definition != null) {
- // Only failed because there was no SNS definition - throw ItemExistsException per 7.1.4 of 1.0.1 spec
- Path pathForChild = pathFactory.create(getPathFor(node), name, numSns + 1);
- String msg = JcrI18n.noSnsDefinitionForNode.text(pathForChild, workspaceName());
- throw new ItemExistsException(msg);
+ // Check if the definition would have worked with less SNS
+ definition = nodeTypes().findChildNodeDefinition(payload.getPrimaryTypeName(),
+ payload.getMixinTypeNames(),
+ name,
+ primaryTypeName,
+ numSns - 1,
+ true);
+ if (definition != null) {
+ // Only failed because there was no SNS definition - throw ItemExistsException per 7.1.4 of 1.0.1 spec
+ Path pathForChild = pathFactory.create(node.getPath(), name, numSns + 1);
+ String msg = JcrI18n.noSnsDefinitionForNode.text(pathForChild, workspaceName());
+ throw new ItemExistsException(msg);
+ }
+ // Didn't work for other reasons - throw ConstraintViolationException
+ Path pathForChild = pathFactory.create(node.getPath(), name, numSns + 1);
+ String msg = JcrI18n.nodeDefinitionCouldNotBeDeterminedForNode.text(pathForChild,
+ workspaceName(),
+ sourceName());
+ throw new ConstraintViolationException(msg);
}
- // Didn't work for other reasons - throw ConstraintViolationException
- Path pathForChild = pathFactory.create(getPathFor(node), name, numSns + 1);
- String msg = JcrI18n.nodeDefinitionCouldNotBeDeterminedForNode.text(pathForChild, workspaceName());
- throw new ConstraintViolationException(msg);
- }
- // Find the primary type ...
- JcrNodeType primaryType = null;
- if (primaryTypeName != null) {
- primaryType = nodeTypes().getNodeType(primaryTypeName);
- if (primaryType == null) {
- Path pathForChild = pathFactory.create(getPathFor(node), name, numSns + 1);
- I18n msg = JcrI18n.unableToCreateNodeWithPrimaryTypeThatDoesNotExist;
- throw new NoSuchNodeTypeException(msg.text(primaryTypeName, pathForChild, workspaceName()));
+ // Find the primary type ...
+ JcrNodeType primaryType = null;
+ if (primaryTypeName != null) {
+ primaryType = nodeTypes().getNodeType(primaryTypeName);
+ if (primaryType == null) {
+ Path pathForChild = pathFactory.create(node.getPath(), name, numSns + 1);
+ I18n msg = JcrI18n.unableToCreateNodeWithPrimaryTypeThatDoesNotExist;
+ throw new NoSuchNodeTypeException(msg.text(primaryTypeName, pathForChild, workspaceName()));
+ }
+ } else {
+ primaryType = (JcrNodeType)definition.getDefaultPrimaryType();
+ if (primaryType == null) {
+ // There is no default primary type ...
+ Path pathForChild = pathFactory.create(node.getPath(), name, numSns + 1);
+ I18n msg = JcrI18n.unableToCreateNodeWithNoDefaultPrimaryTypeOnChildNodeDefinition;
+ String nodeTypeName = definition.getDeclaringNodeType().getName();
+ throw new NoSuchNodeTypeException(msg.text(definition.getName(),
+ nodeTypeName,
+ pathForChild,
+ workspaceName()));
+ }
}
- } else {
- primaryType = (JcrNodeType)definition.getDefaultPrimaryType();
- if (primaryType == null) {
- // There is no default primary type ...
- Path pathForChild = pathFactory.create(getPathFor(node), name, numSns + 1);
- I18n msg = JcrI18n.unableToCreateNodeWithNoDefaultPrimaryTypeOnChildNodeDefinition;
- String nodeTypeName = definition.getDeclaringNodeType().getName();
- throw new NoSuchNodeTypeException(msg.text(definition.getName(), nodeTypeName, pathForChild, workspaceName()));
- }
- }
- primaryTypeName = primaryType.getInternalName();
+ primaryTypeName = primaryType.getInternalName();
- ChildNode result = node.addChild(name, desiredUuid, pathFactory);
+ // ---------------------------------------------------------
+ // Now create the child node representation in the cache ...
+ // ---------------------------------------------------------
- // ---------------------------------------------------------
- // Now create the child node representation in the cache ...
- // ---------------------------------------------------------
- Path newPath = pathFactory.create(currentLocation.getPath(), result.getSegment());
- Location location = Location.create(newPath, desiredUuid);
+ // Create the initial properties ...
+ Property primaryTypeProp = propertyFactory.create(JcrLexicon.PRIMARY_TYPE, primaryTypeName);
+ Property nodeDefinitionProp = propertyFactory.create(DnaIntLexicon.NODE_DEFINITON, definition.getId().getString());
+ List<Name> mixinTypeNames = null;
- // Create the properties ...
- Map<Name, PropertyInfo> properties = new HashMap<Name, PropertyInfo>();
- Property primaryTypeProp = propertyFactory.create(JcrLexicon.PRIMARY_TYPE, primaryTypeName);
- Property nodeDefinitionProp = propertyFactory.create(DnaIntLexicon.NODE_DEFINITON, definition.getId().getString());
-
- // Now add the "jcr:uuid" property if and only if referenceable ...
- if (primaryType.isNodeType(JcrMixLexicon.REFERENCEABLE)) {
- if (desiredUuid == null) {
- desiredUuid = UUID.randomUUID();
+ // Now add the "jcr:uuid" property if and only if referenceable ...
+ Node<JcrNodePayload, JcrPropertyPayload> result = null;
+ if (primaryType.isNodeType(JcrMixLexicon.REFERENCEABLE)) {
+ if (desiredUuid == null) {
+ desiredUuid = UUID.randomUUID();
+ }
+ Property uuidProperty = propertyFactory.create(JcrLexicon.UUID, desiredUuid);
+ result = node.createChild(name, uuidProperty, primaryTypeProp, nodeDefinitionProp);
+ } else {
+ result = node.createChild(name, primaryTypeProp, nodeDefinitionProp);
}
-
- // We know that this property is single-valued
- JcrValue value = new JcrValue(factories(), SessionCache.this, PropertyType.STRING, desiredUuid.toString());
- PropertyDefinition propertyDefinition = nodeTypes().findPropertyDefinition(primaryTypeName,
- Collections.<Name>emptyList(),
- JcrLexicon.UUID,
- value,
- false,
- false);
- PropertyId propId = new PropertyId(desiredUuid, JcrLexicon.UUID);
- JcrPropertyDefinition defn = (JcrPropertyDefinition)propertyDefinition;
- org.jboss.dna.graph.property.Property uuidProperty = propertyFactory.create(JcrLexicon.UUID, desiredUuid);
- PropertyInfo propInfo = new PropertyInfo(propId, defn.getId(), PropertyType.STRING, uuidProperty,
- defn.isMultiple(), true, false);
- properties.put(JcrLexicon.UUID, propInfo);
+ // Now create the payload ...
+ JcrNodePayload newPayload = new JcrNodePayload(SessionCache.this, result, primaryTypeName, mixinTypeNames,
+ definition.getId());
+ result.setPayload(newPayload);
+ // Finally, return the jcr node ...
+ assert result.getPayload() == newPayload;
+ return (JcrNode)newPayload.getJcrNode();
+ } catch (ValidationException e) {
+ throw new ConstraintViolationException(e.getMessage(), e.getCause());
+ } catch (RepositorySourceException e) {
+ throw new RepositoryException(e.getMessage(), e.getCause());
+ } catch (AccessControlException e) {
+ throw new AccessDeniedException(e.getMessage(), e.getCause());
}
-
- // Create the property info for the "jcr:primaryType" child property ...
- JcrPropertyDefinition primaryTypeDefn = findBestPropertyDefintion(node.getPrimaryTypeName(),
- node.getMixinTypeNames(),
- primaryTypeProp,
- PropertyType.NAME,
- true,
- false);
- PropertyDefinitionId primaryTypeDefinitionId = primaryTypeDefn.getId();
- PropertyInfo primaryTypeInfo = new PropertyInfo(new PropertyId(desiredUuid, primaryTypeProp.getName()),
- primaryTypeDefinitionId, PropertyType.NAME, primaryTypeProp, false,
- true, false);
- properties.put(primaryTypeProp.getName(), primaryTypeInfo);
-
- // Create the property info for the "dna:nodeDefinition" child property ...
- JcrPropertyDefinition nodeDefnDefn = findBestPropertyDefintion(node.getPrimaryTypeName(),
- node.getMixinTypeNames(),
- nodeDefinitionProp,
- PropertyType.STRING,
- true,
- false);
-
- if (nodeDefnDefn != null) {
- PropertyDefinitionId nodeDefnDefinitionId = nodeDefnDefn.getId();
- PropertyInfo nodeDefinitionInfo = new PropertyInfo(new PropertyId(desiredUuid, nodeDefinitionProp.getName()),
- nodeDefnDefinitionId, PropertyType.STRING, nodeDefinitionProp,
- false, true, false);
- properties.put(nodeDefinitionProp.getName(), nodeDefinitionInfo);
- }
- assert nodeDefnDefn != null && nodeDefnDefn.getInternalName().equals(DnaIntLexicon.NODE_DEFINITON);
-
- // Now create the child node info, putting it in the changed map (and not the cache map!) ...
- NewNodeInfo newInfo = new NewNodeInfo(location, primaryTypeName, definition.getId(), node.getUuid(), properties);
- changedNodes.put(desiredUuid, newInfo);
-
- // ---------------------------------------
- // Now record the changes to the store ...
- // ---------------------------------------
- Graph.Create<Graph.Batch> create = operations.createUnder(currentLocation).nodeNamed(name).with(desiredUuid).with(primaryTypeProp);
- // if (nodeDefnDefn != null) {
- create = create.with(nodeDefinitionProp);
- // }
- create.and();
- return result;
}
/**
* Destroy the child node with the supplied UUID and all nodes that exist below it, including any nodes that were created
* and haven't been persisted.
*
- * @param nodeUuid the UUID of the child node; may not be null
+ * @param child the child node; may not be null
* @throws AccessDeniedException if the current session does not have the requisite privileges to perform this task
* @throws RepositoryException if any other error occurs
* @return true if the child was successfully removed, or false if the node did not exist as a child
*/
- public boolean destroyChild( UUID nodeUuid ) throws AccessDeniedException, RepositoryException {
- SessionCache.this.checkPermission(node, JcrSession.JCR_REMOVE_PERMISSION);
-
- ChildNode deleted = node.removeChild(nodeUuid, pathFactory);
-
- if (deleted != null) {
- // Recursively mark the cached/changed information as deleted ...
- deleteNodeInfos(nodeUuid);
-
- // Now make the request to the source ...
- Path childPath = pathFactory.create(currentLocation.getPath(), deleted.getSegment());
- Location locationOfChild = Location.create(childPath, nodeUuid);
- operations.delete(locationOfChild);
- return true;
+ public boolean destroyChild( Node<JcrNodePayload, JcrPropertyPayload> child )
+ throws AccessDeniedException, RepositoryException {
+ if (!child.getParent().equals(node)) return false;
+ try {
+ child.destroy();
+ } catch (AccessControlException e) {
+ throw new AccessDeniedException(e.getMessage(), e.getCause());
}
- return false;
+ return true;
}
-
- protected boolean isAncestor( UUID uuid ) throws ItemNotFoundException, InvalidItemStateException, RepositoryException {
- UUID ancestor = node.getParent();
- while (ancestor != null) {
- if (ancestor.equals(uuid)) return true;
- NodeInfo info = findNodeInfo(ancestor);
- ancestor = info.getParent();
- }
- return false;
- }
}
/**
@@ -1817,806 +1481,1130 @@
return null;
}
- /**
- * Utility method that creates and caches the appropriate kind of AbstractJcrNode implementation for node given by the
- * supplied information.
- *
- * @param info the information for the node; may not be null
- * @return the <i>new</i> instance of the {@link Node}; never null
- */
- private AbstractJcrNode createAndCacheJcrNodeFor( NodeInfo info ) {
- UUID uuid = info.getUuid();
- Location location = info.getOriginalLocation();
- NodeDefinitionId nodeDefinitionId = info.getDefinitionId();
- JcrNodeDefinition definition = nodeTypes().getNodeDefinition(nodeDefinitionId);
- assert definition != null;
+ // Path getPathFor( String workspaceName,
+ // UUID uuid,
+ // Path relativePath ) throws NoSuchWorkspaceException, ItemNotFoundException, RepositoryException {
+ // assert workspaceName != null;
+ // assert uuid != null || relativePath != null;
+ //
+ // Graph graph = operations.getGraph();
+ // try {
+ // graph.useWorkspace(workspaceName);
+ // } catch (InvalidWorkspaceException iwe) {
+ // throw new NoSuchWorkspaceException(JcrI18n.workspaceNameIsInvalid.text(graph.getSourceName(), workspaceName));
+ // }
+ //
+ // try {
+ // org.jboss.dna.graph.Node node;
+ // if (uuid != null) {
+ // node = graph.getNodeAt(uuid);
+ //
+ // if (relativePath != null) {
+ // Path nodePath = node.getLocation().getPath();
+ // Path absolutePath = relativePath.resolveAgainst(nodePath);
+ // node = graph.getNodeAt(absolutePath);
+ // }
+ //
+ // } else {
+ // Path absolutePath = pathFactory.createAbsolutePath(relativePath.getSegmentsList());
+ // node = graph.getNodeAt(absolutePath);
+ // }
+ // assert node != null;
+ //
+ // return node.getLocation().getPath();
+ // } catch (org.jboss.dna.graph.property.PathNotFoundException pnfe) {
+ // throw new ItemNotFoundException(pnfe);
+ // } finally {
+ // graph.useWorkspace(this.workspaceName);
+ // }
+ //
+ // }
+ //
+ // Path getPathFor( UUID uuid ) throws ItemNotFoundException, InvalidItemStateException, RepositoryException {
+ // if (uuid.equals(root)) return rootPath;
+ // return getPathFor(findNodeInfo(uuid));
+ // }
+ //
+ // Path getPathFor( NodeInfo info ) throws ItemNotFoundException, InvalidItemStateException, RepositoryException {
+ // if (info == null) {
+ // return pathFactory.createRootPath();
+ // }
+ // UUID uuid = info.getUuid();
+ // if (uuid.equals(root)) return rootPath;
+ //
+ // // This isn't the root node ...
+ // Path result = pathCache.get(uuid);
+ // if (result == null) {
+ // // We need to build a path using the parent path ...
+ // UUID parent = info.getParent();
+ // if (parent == null) {
+ // // Then this node is the root ...
+ // root = info.getUuid();
+ // result = rootPath;
+ // } else {
+ // NodeInfo parentInfo = findNodeInfo(parent);
+ // Path parentPath = getPathFor(parentInfo);
+ // ChildNode child = parentInfo.getChildren().getChild(info.getUuid());
+ // result = pathFactory.create(parentPath, child.getSegment());
+ // }
+ // pathCache.put(uuid, result);
+ // }
+ // assert result != null;
+ // return result;
+ // }
+ //
+ // Path getPathFor( PropertyInfo propertyInfo ) throws ItemNotFoundException, RepositoryException {
+ // Path nodePath = getPathFor(propertyInfo.getNodeUuid());
+ // return pathFactory.create(nodePath, propertyInfo.getPropertyName());
+ // }
+ //
+ // Path getPathFor( PropertyId propertyId ) throws ItemNotFoundException, RepositoryException {
+ // return getPathFor(findPropertyInfo(propertyId));
+ // }
+ //
+ // protected Name getNameOf( UUID nodeUuid ) throws ItemNotFoundException, InvalidItemStateException, RepositoryException {
+ // findNodeInfoForRoot();
+ // if (nodeUuid == root) return nameFactory.create("");
+ // // Get the parent ...
+ // NodeInfo info = findNodeInfo(nodeUuid);
+ // NodeInfo parent = findNodeInfo(info.getParent());
+ // ChildNode child = parent.getChildren().getChild(info.getUuid());
+ // return child.getName();
+ // }
+ //
+ // protected int getSnsIndexOf( UUID nodeUuid ) throws ItemNotFoundException, InvalidItemStateException, RepositoryException {
+ // findNodeInfoForRoot();
+ // if (nodeUuid == root) return 1;
+ // // Get the parent ...
+ // NodeInfo info = findNodeInfo(nodeUuid);
+ // NodeInfo parent = findNodeInfo(info.getParent());
+ // ChildNode child = parent.getChildren().getChild(info.getUuid());
+ // return child.getSnsIndex();
+ // }
+ //
+ // /**
+ // * Load from the underlying repository graph the information for the node with the supplied UUID. This method returns the
+ // * information for the requested node (after placing it in the cache), but this method may (at its discretion) also load and
+ // * cache information for other nodes.
+ // * <p>
+ // * Note that this method does not check the cache before loading from the repository graph.
+ // * </p>
+ // *
+ // * @param path the path of the node, if known; may be null only if the UUID is supplied
+ // * @param uuid the UUID of the node, if known; may be null only if the path is supplied
+ // * @return the information for the node
+ // * @throws ItemNotFoundException if the node does not exist in the repository
+ // * @throws RepositoryException if there was an error obtaining this information from the repository
+ // */
+ // protected ImmutableNodeInfo loadFromGraph( Path path,
+ // UUID uuid ) throws ItemNotFoundException, RepositoryException {
+ // // Load the node information from the store ...
+ // try {
+ // // See if there is a path for this uuid ...
+ // Location location = Location.create(path, uuid);
+ // org.jboss.dna.graph.Node node = store.getNodeAt(location);
+ // ImmutableNodeInfo info = createNodeInfoFrom(node, null);
+ // this.cachedNodes.put(info.getUuid(), info);
+ // return info;
+ // } catch (org.jboss.dna.graph.property.PathNotFoundException e) {
+ // throw new ItemNotFoundException(JcrI18n.itemNotFoundWithUuid.text(uuid, workspaceName, e.getLocalizedMessage()));
+ // } catch (RepositorySourceException e) {
+ // throw new RepositoryException(
+ // JcrI18n.errorWhileFindingNodeWithUuid.text(uuid, workspaceName, e.getLocalizedMessage()),
+ // e);
+ // }
+ // }
+ //
+ // /**
+ // * Load from the underlying repository graph the information for the node with the supplied UUID. This method returns the
+ // * information for the requested node (after placing it in the cache), but this method may (at its discretion) also load and
+ // * cache information for other nodes.
+ // * <p>
+ // * Note that this method does not check the cache before loading from the repository graph.
+ // * </p>
+ // *
+ // * @param path the path to the node; may not be null
+ // * @param parentInfo the parent information; may be null if not known
+ // * @return the information for the node
+ // * @throws PathNotFoundException if the node does not exist in the repository
+ // * @throws RepositoryException if there was an error obtaining this information from the repository
+ // */
+ // protected ImmutableNodeInfo loadFromGraph( Path path,
+ // NodeInfo parentInfo ) throws PathNotFoundException, RepositoryException {
+ // // Load the node information from the store ...
+ // try {
+ // org.jboss.dna.graph.Node node = store.getNodeAt(path);
+ // ImmutableNodeInfo info = createNodeInfoFrom(node, parentInfo);
+ // this.cachedNodes.put(info.getUuid(), info);
+ // return info;
+ // } catch (org.jboss.dna.graph.property.PathNotFoundException e) {
+ // throw new PathNotFoundException(JcrI18n.pathNotFound.text(path, workspaceName));
+ // } catch (RepositorySourceException e) {
+ // throw new RepositoryException(JcrI18n.errorWhileFindingNodeWithPath.text(path, workspaceName));
+ // }
+ // }
- // Need to determine if this is the root node ...
- if (location.getPath().isRoot()) {
- // It is a root node ...
- JcrRootNode node = new JcrRootNode(this, uuid);
- jcrNodes.put(uuid, node);
- root = uuid;
- return node;
+ // /**
+ // * Create the {@link NodeInfo} object given the DNA graph node and the parent node information (if it is available).
+ // *
+ // * @param graphNode the DNA graph node; may not be null
+ // * @param parentInfo the information for the parent node, or null if the supplied graph node represents the root node, or if
+ // * the parent information is not known
+ // * @return the node information; never null
+ // * @throws RepositoryException if there is an error determining the child {@link NodeDefinition} for the supplied node,
+ // * preventing the node information from being constructed
+ // */
+ // private ImmutableNodeInfo createNodeInfoFrom( org.jboss.dna.graph.Node graphNode,
+ // NodeInfo parentInfo ) throws RepositoryException {
+ // // Now get the DNA node's UUID and find the DNA property containing the UUID ...
+ // Location location = graphNode.getLocation();
+ // UUID uuid = location.getUuid();
+ // org.jboss.dna.graph.property.Property uuidProperty = null;
+ // if (uuid != null) {
+ // // Check for an identification property ...
+ // uuidProperty = location.getIdProperty(JcrLexicon.UUID);
+ // if (uuidProperty == null) {
+ // uuidProperty = propertyFactory.create(JcrLexicon.UUID, uuid);
+ // }
+ // }
+ // if (uuidProperty == null) {
+ // uuidProperty = graphNode.getProperty(JcrLexicon.UUID);
+ // 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 ...
+ // org.jboss.dna.graph.property.Property dnaUuidProperty = graphNode.getProperty(DnaLexicon.UUID);
+ // if (dnaUuidProperty != null) {
+ // // Grab the first 'good' UUID value ...
+ // for (Object uuidValue : dnaUuidProperty) {
+ // 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);
+ //
+ // // Either the UUID is not known, or there was no node. Either way, we have to create the node ...
+ // if (uuid == null) uuid = UUID.randomUUID();
+ //
+ // // Look for the primary type of the node ...
+ // Map<Name, Property> graphProperties = graphNode.getPropertiesByName();
+ // final boolean isRoot = location.getPath().isRoot();
+ // Name primaryTypeName = null;
+ // org.jboss.dna.graph.property.Property primaryTypeProperty = graphNode.getProperty(JcrLexicon.PRIMARY_TYPE);
+ // if (primaryTypeProperty != null && !primaryTypeProperty.isEmpty()) {
+ // try {
+ // primaryTypeName = factories.getNameFactory().create(primaryTypeProperty.getFirstValue());
+ // } catch (ValueFormatException e) {
+ // // use the default ...
+ // }
+ // }
+ // if (primaryTypeName == null) {
+ // // We have to have a primary type, so use the default ...
+ // if (isRoot) {
+ // primaryTypeName = DnaLexicon.ROOT;
+ // primaryTypeProperty = propertyFactory.create(JcrLexicon.PRIMARY_TYPE, primaryTypeName);
+ // } else {
+ // primaryTypeName = defaultPrimaryTypeName;
+ // primaryTypeProperty = defaultPrimaryTypeProperty;
+ // }
+ // // We have to add this property to the graph node...
+ // graphProperties = new HashMap<Name, Property>(graphProperties);
+ // graphProperties.put(primaryTypeProperty.getName(), primaryTypeProperty);
+ // }
+ // assert primaryTypeProperty != null;
+ // assert primaryTypeProperty.isEmpty() == false;
+ //
+ // // Look for a node definition stored on the node ...
+ // JcrNodeDefinition definition = null;
+ // org.jboss.dna.graph.property.Property nodeDefnProperty = graphProperties.get(DnaIntLexicon.NODE_DEFINITON);
+ // if (nodeDefnProperty != null && !nodeDefnProperty.isEmpty()) {
+ // String nodeDefinitionString = stringFactory.create(nodeDefnProperty.getFirstValue());
+ // NodeDefinitionId id = NodeDefinitionId.fromString(nodeDefinitionString, nameFactory);
+ // definition = nodeTypes().getNodeDefinition(id);
+ // }
+ // // Figure out the node definition for this node ...
+ // if (isRoot) {
+ // if (definition == null) definition = nodeTypes().getRootNodeDefinition();
+ // } else {
+ // // We need the parent ...
+ // Path path = location.getPath();
+ // if (parentInfo == null) {
+ // Path parentPath = path.getParent();
+ // parentInfo = findNodeInfo(null, parentPath.getNormalizedPath());
+ // }
+ // if (definition == null) {
+ // Name childName = path.getLastSegment().getName();
+ // int numExistingChildrenWithSameName = parentInfo.getChildren().getCountOfSameNameSiblingsWithName(childName);
+ // definition = nodeTypes().findChildNodeDefinition(parentInfo.getPrimaryTypeName(),
+ // parentInfo.getMixinTypeNames(),
+ // childName,
+ // primaryTypeName,
+ // numExistingChildrenWithSameName,
+ // false);
+ // }
+ // if (definition == null) {
+ // String msg = JcrI18n.nodeDefinitionCouldNotBeDeterminedForNode.text(path, workspaceName);
+ // throw new RepositorySourceException(sourceName(), msg);
+ // }
+ // }
+ //
+ // // ------------------------------------------------------
+ // // Set the node's properties ...
+ // // ------------------------------------------------------
+ // boolean referenceable = false;
+ //
+ // // Start with the primary type ...
+ // JcrNodeType primaryType = nodeTypes().getNodeType(primaryTypeName);
+ // if (primaryType == null) {
+ // Path path = location.getPath();
+ // String msg = JcrI18n.missingNodeTypeForExistingNode.text(primaryTypeName.getString(namespaces), path, workspaceName);
+ // throw new RepositorySourceException(sourceName(), msg);
+ // }
+ // if (primaryType.isNodeType(JcrMixLexicon.REFERENCEABLE)) referenceable = true;
+ //
+ // // The process the mixin types ...
+ // Property mixinTypesProperty = graphProperties.get(JcrLexicon.MIXIN_TYPES);
+ // List<Name> mixinTypeNames = null;
+ // if (mixinTypesProperty != null && !mixinTypesProperty.isEmpty()) {
+ // for (Object mixinTypeValue : mixinTypesProperty) {
+ // Name mixinTypeName = nameFactory.create(mixinTypeValue);
+ // if (mixinTypeNames == null) mixinTypeNames = new LinkedList<Name>();
+ // mixinTypeNames.add(mixinTypeName);
+ // JcrNodeType mixinType = nodeTypes().getNodeType(mixinTypeName);
+ // if (mixinType == null) continue;
+ // if (!referenceable && mixinType.isNodeType(JcrMixLexicon.REFERENCEABLE)) referenceable = true;
+ // }
+ // }
+ //
+ // // Create the set of multi-valued property names ...
+ // Set<Name> multiValuedPropertyNames = EMPTY_NAMES;
+ // Set<Name> newSingleMultiPropertyNames = null;
+ // Property multiValuedPropNamesProp = graphProperties.get(DnaIntLexicon.MULTI_VALUED_PROPERTIES);
+ // if (multiValuedPropNamesProp != null && !multiValuedPropNamesProp.isEmpty()) {
+ // multiValuedPropertyNames = getSingleMultiPropertyNames(multiValuedPropNamesProp, location.getPath(), uuid);
+ // }
+ //
+ // // Now create the JCR property object wrappers around the other properties ...
+ // Map<Name, PropertyInfo> props = new HashMap<Name, PropertyInfo>();
+ // for (Property dnaProp : graphProperties.values()) {
+ // Name name = dnaProp.getName();
+ //
+ // // Is this is single-valued property?
+ // boolean isSingle = dnaProp.isSingle();
+ // // Make sure that this isn't a multi-valued property with one value ...
+ // if (isSingle && multiValuedPropertyNames.contains(name)) isSingle = false;
+ //
+ // // Figure out the JCR property type for this property ...
+ // int propertyType = PropertyTypeUtil.jcrPropertyTypeFor(dnaProp);
+ // PropertyDefinition propertyDefinition = findBestPropertyDefintion(primaryTypeName,
+ // mixinTypeNames,
+ // dnaProp,
+ // propertyType,
+ // isSingle,
+ // false);
+ //
+ // // If there still is no property type defined ...
+ // if (propertyDefinition == null && INCLUDE_PROPERTIES_NOT_ALLOWED_BY_NODE_TYPE_OR_MIXINS) {
+ // // We can use the "nt:unstructured" property definitions for any property ...
+ // NodeType unstructured = nodeTypes().getNodeType(JcrNtLexicon.UNSTRUCTURED);
+ // for (PropertyDefinition anyDefinition : unstructured.getDeclaredPropertyDefinitions()) {
+ // if (anyDefinition.isMultiple()) {
+ // propertyDefinition = anyDefinition;
+ // break;
+ // }
+ // }
+ // }
+ // if (propertyDefinition == null) {
+ // // We're supposed to skip this property (since we don't have a definition for it) ...
+ // continue;
+ // }
+ //
+ // // Figure out if this is a multi-valued property ...
+ // boolean isMultiple = propertyDefinition.isMultiple();
+ // if (!isMultiple && dnaProp.isEmpty()) {
+ // // Only multi-valued properties can have no values; so if not multi-valued, then skip ...
+ // continue;
+ // }
+ //
+ // // Update the list of single-valued multi-property names ...
+ // if (isMultiple && isSingle) {
+ // if (newSingleMultiPropertyNames == null) newSingleMultiPropertyNames = new HashSet<Name>();
+ // newSingleMultiPropertyNames.add(name);
+ // }
+ //
+ // // Figure out the property type ...
+ // int definitionType = propertyDefinition.getRequiredType();
+ // if (definitionType != PropertyType.UNDEFINED) {
+ // propertyType = definitionType;
+ // }
+ //
+ // // Record the property in the node information ...
+ // PropertyId propId = new PropertyId(uuid, name);
+ // JcrPropertyDefinition defn = (JcrPropertyDefinition)propertyDefinition;
+ // PropertyInfo propInfo = new PropertyInfo(propId, defn.getId(), propertyType, dnaProp, defn.isMultiple(), false, false);
+ // props.put(name, propInfo);
+ // }
+ //
+ // // Now add the "jcr:uuid" property if and only if referenceable ...
+ // if (referenceable) {
+ // // We know that this property is single-valued
+ // JcrValue value = new JcrValue(factories(), this, PropertyType.STRING, uuid);
+ // PropertyDefinition propertyDefinition = nodeTypes().findPropertyDefinition(primaryTypeName,
+ // mixinTypeNames,
+ // JcrLexicon.UUID,
+ // value,
+ // false,
+ // false);
+ // PropertyId propId = new PropertyId(uuid, JcrLexicon.UUID);
+ // JcrPropertyDefinition defn = (JcrPropertyDefinition)propertyDefinition;
+ // PropertyInfo propInfo = new PropertyInfo(propId, defn.getId(), PropertyType.STRING, uuidProperty, defn.isMultiple(),
+ // false, false);
+ // props.put(JcrLexicon.UUID, propInfo);
+ // } else {
+ // // Make sure there is NOT a "jcr:uuid" property ...
+ // props.remove(JcrLexicon.UUID);
+ // }
+ // // Make sure the "dna:uuid" property did not get in there ...
+ // props.remove(DnaLexicon.UUID);
+ //
+ // // Make sure the single-valued multi-property names are stored as a property ...
+ // if (newSingleMultiPropertyNames != null) {
+ // PropertyInfo info = createSingleMultiplePropertyInfo(uuid,
+ // primaryTypeName,
+ // mixinTypeNames,
+ // newSingleMultiPropertyNames);
+ // props.put(info.getPropertyName(), info);
+ // }
+ //
+ // // Create the node information ...
+ // UUID parentUuid = parentInfo != null ? parentInfo.getUuid() : null;
+ // List<Location> locations = graphNode.getChildren();
+ // Children children = locations.isEmpty() ? new EmptyChildren(parentUuid) : new ImmutableChildren(parentUuid, locations);
+ // props = Collections.unmodifiableMap(props);
+ // return new ImmutableNodeInfo(location, primaryTypeName, mixinTypeNames, definition.getId(), parentUuid, children, props);
+ // }
+ //
+ protected final void updateSingleMultipleProperty( Node<JcrNodePayload, JcrPropertyPayload> node,
+ Name singleMultiPropertyName,
+ boolean add ) {
+ PropertyInfo<JcrPropertyPayload> existing = node.getProperty(DnaIntLexicon.MULTI_VALUED_PROPERTIES);
+ Set<Name> singleMultiPropertyNames = null;
+ if (existing != null) {
+ singleMultiPropertyNames = new HashSet<Name>();
+ // Grab the existing values ...
+ for (Object value : existing.getProperty()) {
+ singleMultiPropertyNames.add(nameFactory().create(value));
+ }
+ if (add) singleMultiPropertyNames.add(singleMultiPropertyName);
+ else singleMultiPropertyNames.remove(singleMultiPropertyName);
+ } else {
+ if (add) {
+ singleMultiPropertyNames = Collections.singleton(singleMultiPropertyName);
+ } else {
+ // supposed to remove the property name, but there isn't a property, so just return
+ return;
+ }
}
- // It is not a root node ...
- JcrNode node = new JcrNode(this, uuid);
- assert !uuid.equals(root);
- jcrNodes.put(uuid, node);
- return node;
- }
-
- /**
- * Utility method that creates and caches the appropriate kind of AbstractJcrProperty implementation for property given by the
- * supplied information.
- *
- * @param info the information for the property; may not be null
- * @return the <i>new</i> instance of the {@link Property}; never null
- */
- private AbstractJcrProperty createAndCacheJcrPropertyFor( PropertyInfo info ) {
- boolean multiValued = info.isMultiValued();
- JcrPropertyDefinition definition = nodeTypes().getPropertyDefinition(info.getDefinitionId());
- assert definition != null;
- if (multiValued) {
- return new JcrMultiValueProperty(this, info.getPropertyId());
+ if (singleMultiPropertyNames.isEmpty()) {
+ // Remove the property ...
+ assert existing != null;
+ node.removeProperty(existing.getName());
+ return;
}
- return new JcrSingleValueProperty(this, info.getPropertyId());
+ PropertyInfo<JcrPropertyPayload> property = createSingleMultipleProperty(node.getPayload(),
+ existing,
+ singleMultiPropertyNames);
+ node.setProperty(property.getProperty(), property.isMultiValued(), property.getPayload());
}
- /**
- * Find the information for the node given by the UUID of the node. This is often the fastest way to find information,
- * especially after the information has been cached. Note, however, that this method first checks the cache, and if the
- * information is not in the cache, the information is read from the repository.
- *
- * @param uuid the UUID for the node; may not be null
- * @return the information for the node with the supplied UUID, or null if the information is not in the cache
- * @throws AccessDeniedException if the node cannot be accessed
- * @throws ItemNotFoundException if there is no node with the supplied UUID
- * @throws InvalidItemStateException if the node with the UUID has been deleted in this session
- * @throws RepositoryException if any other error occurs while reading information from the repository
- * @see #findNodeInfoInCache(UUID)
- * @see #findNodeInfo(UUID, Path)
- * @see #findNodeInfoForRoot()
- */
- NodeInfo findNodeInfo( UUID uuid )
- throws AccessDeniedException, ItemNotFoundException, InvalidItemStateException, RepositoryException {
- assert uuid != null;
- // See if we already have something in the cache ...
- NodeInfo info = findNodeInfoInCache(uuid);
- if (info == null) {
- // Nope, so go ahead and load it ...
- info = loadFromGraph(null, uuid);
+ protected PropertyInfo<JcrPropertyPayload> createSingleMultipleProperty( JcrNodePayload nodePayload,
+ PropertyInfo<JcrPropertyPayload> existing,
+ Set<Name> singleMultiPropertyNames ) {
+ int number = singleMultiPropertyNames.size();
+ // Otherwise, we have to set/update the property ...
+ String[] names = new String[number];
+ JcrValue[] values = new JcrValue[number];
+ if (number == 1) {
+ String str = singleMultiPropertyNames.iterator().next().getString(namespaces);
+ names[0] = str;
+ values[0] = new JcrValue(factories(), this, PropertyType.STRING, str);
+ } else {
+ int index = 0;
+ for (Name name : singleMultiPropertyNames) {
+ String str = name.getString(namespaces);
+ names[index] = str;
+ values[index] = new JcrValue(factories(), this, PropertyType.STRING, str);
+ ++index;
+ }
}
- SessionCache.this.checkPermission(info, JcrSession.JCR_READ_PERMISSION);
-
- return info;
+ JcrPropertyDefinition definition = nodeTypes().findPropertyDefinition(nodePayload.getPrimaryTypeName(),
+ nodePayload.getMixinTypeNames(),
+ DnaIntLexicon.MULTI_VALUED_PROPERTIES,
+ values,
+ false);
+ Property dnaProp = propertyFactory.create(DnaIntLexicon.MULTI_VALUED_PROPERTIES, singleMultiPropertyNames.iterator());
+ return createPropertyInfo(nodePayload, dnaProp, definition, PropertyType.STRING, existing);
}
- /**
- * Find the information for the node given by the UUID of the node. This is often the fastest way to find information,
- * especially after the information has been cached. Note, however, that this method only checks the cache.
- *
- * @param uuid the UUID for the node; may not be null
- * @return the information for the node with the supplied UUID, or null if the information is not in the cache
- * @see #findNodeInfo(UUID)
- * @see #findNodeInfo(UUID, Path)
- * @see #findNodeInfoForRoot()
- * @throws InvalidItemStateException if the node with the UUID has been deleted in this session
- */
- NodeInfo findNodeInfoInCache( UUID uuid ) throws InvalidItemStateException {
- // See if we already have something in the changed nodes ...
- NodeInfo info = changedNodes.get(uuid);
- if (info == null) {
- // Or in the cache ...
- info = cachedNodes.get(uuid);
- if (info == null) {
- // Finally check if the node was deleted ...
- if (deletedNodes.containsKey(uuid)) {
- throw new InvalidItemStateException();
- }
+ protected final PropertyInfo<JcrPropertyPayload> createPropertyInfo( JcrNodePayload nodePayload,
+ Property dnaProp,
+ JcrPropertyDefinition definition,
+ int propertyType,
+ PropertyInfo<JcrPropertyPayload> existing ) {
+ // Create (or reuse) the JCR Property object ...
+ AbstractJcrProperty jcrProp = null;
+ if (existing != null) {
+ jcrProp = existing.getPayload().getJcrProperty();
+ } else {
+ AbstractJcrNode jcrNode = nodePayload.getJcrNode();
+ if (definition.isMultiple()) {
+ jcrProp = new JcrMultiValueProperty(SessionCache.this, jcrNode, dnaProp.getName());
+ } else {
+ jcrProp = new JcrSingleValueProperty(SessionCache.this, jcrNode, dnaProp.getName());
}
}
- return info;
- }
+ assert jcrProp != null;
+ JcrPropertyPayload propPayload = new JcrPropertyPayload(definition.getId(), propertyType, jcrProp);
+ Status status = existing != null ? Status.CHANGED : Status.NEW;
+ return new GraphSession.PropertyInfo<JcrPropertyPayload>(dnaProp, definition.isMultiple(), status, propPayload);
- /**
- * Find the information for the root node. Generally, this returns information that's in the cache, except for the first time
- * the root node is needed.
- *
- * @return the node information
- * @throws RepositoryException if there is an error while obtaining the information from the repository
- */
- NodeInfo findNodeInfoForRoot() throws RepositoryException {
- if (root == null) {
- // We haven't found the root yet ...
- NodeInfo info = loadFromGraph(this.rootPath, (NodeInfo)null);
- root = info.getUuid();
- this.jcrNodes.put(root, new JcrRootNode(this, root));
- return info;
- }
- return findNodeInfo(root);
}
- /**
- * Find the information for the node given by the UUID of a reference node and a relative path from the reference node.
- *
- * @param node the reference node; may be null if the root node is to be used as the reference
- * @param relativePath the relative path from the reference node, but which may be an absolute path only when the reference
- * node is the root node; may not be null
- * @return the information for the referenced node; never null
- * @throws ItemNotFoundException if the reference node with the supplied UUID does not exist
- * @throws PathNotFoundException if the node given by the relative path does not exist
- * @throws InvalidItemStateException if the node with the UUID has been deleted in this session
- * @throws RepositoryException if any other error occurs while reading information from the repository
- * @see #findNodeInfoForRoot()
- */
- NodeInfo findNodeInfo( UUID node,
- Path relativePath )
- throws ItemNotFoundException, InvalidItemStateException, PathNotFoundException, RepositoryException {
- // The relative path must be normalized ...
- assert relativePath.isNormalized();
-
- // Find the node from which we're starting ...
- NodeInfo fromInfo = null;
- if (node == null) {
- // This is only valid when the path is relative to the root (or it's an absolute path)
- fromInfo = findNodeInfoForRoot();
- node = fromInfo.getUuid();
- } else {
- fromInfo = findNodeInfo(node);
- assert relativePath.isAbsolute() ? node == root : true;
- }
- if (relativePath.isAbsolute()) {
- relativePath = relativePath.relativeTo(this.rootPath);
- }
-
- // If the relative path is of zero-length ...
- if (relativePath.size() == 0) {
- SessionCache.this.checkPermission(fromInfo, JcrSession.JCR_READ_PERMISSION);
- return fromInfo;
- }
- // Or it is of length 1 but it is a self reference ...
- if (relativePath.size() == 1 && relativePath.getLastSegment().isSelfReference()) {
- SessionCache.this.checkPermission(fromInfo, JcrSession.JCR_READ_PERMISSION);
- return fromInfo;
- }
-
- // TODO: This could be more efficient than always walking the path. For example, we could
- // maintain a cache of paths. Right now, we are walking as much of the path as we can,
- // but as soon as we reach the bottom-most cached/changed node, we need to read the rest
- // from the graph. We are figuring out all of the remaining nodes and read them from
- // the graph in one batch operation, so that part is pretty good.
-
- // Now, walk the path to find the nodes, being sure to look for changed information ...
- NodeInfo info = fromInfo;
- Iterator<Path.Segment> pathsIter = relativePath.iterator();
- while (pathsIter.hasNext()) {
- Path.Segment child = pathsIter.next();
- if (child.isParentReference()) {
- // Walk up ...
- UUID parentUuid = info.getParent();
- if (parentUuid == null) {
- assert info.getUuid() == findNodeInfoForRoot().getUuid();
- String msg = JcrI18n.errorWhileFindingNodeWithPath.text(relativePath, workspaceName);
- throw new PathNotFoundException(msg);
+ @Immutable
+ final class JcrNodeOperations extends GraphSession.NodeOperations<JcrNodePayload, JcrPropertyPayload> {
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.graph.session.GraphSession.Operations#materialize(org.jboss.dna.graph.Node,
+ * org.jboss.dna.graph.session.GraphSession.Node)
+ */
+ @Override
+ public void materialize( org.jboss.dna.graph.Node persistentNode,
+ Node<JcrNodePayload, JcrPropertyPayload> node ) {
+ // Now get the DNA node's UUID and find the DNA property containing the UUID ...
+ Location location = node.getLocation();
+ UUID uuid = location.getUuid();
+ org.jboss.dna.graph.property.Property uuidProperty = null;
+ if (uuid != null) {
+ // Check for an identification property ...
+ uuidProperty = location.getIdProperty(JcrLexicon.UUID);
+ if (uuidProperty == null) {
+ uuidProperty = propertyFactory.create(JcrLexicon.UUID, uuid);
}
- info = findNodeInfo(parentUuid);
- } else {
- // Walk down ...
- // Note that once we start walking down, a normalized path should never have any more parent
- // or self references
- ChildNode childNodeInfo = info.getChildren().getChild(child);
- if (childNodeInfo == null) {
- // The node (no longer?) exists, so compute the
- Path fromPath = getPathFor(fromInfo);
- String msg = JcrI18n.pathNotFoundRelativeTo.text(relativePath, fromPath, workspaceName);
- throw new PathNotFoundException(msg);
+ }
+ if (uuidProperty == null) {
+ org.jboss.dna.graph.session.GraphSession.PropertyInfo<JcrPropertyPayload> uuidInfo = node.getProperty(JcrLexicon.UUID);
+ if (uuidInfo != null) {
+ uuidProperty = uuidInfo.getProperty();
}
- // See if we already have something in the changed nodes ...
- UUID uuid = childNodeInfo.getUuid();
- NodeInfo childInfo = changedNodes.get(uuid);
- if (childInfo == null) {
- // Or in the cache ...
- childInfo = cachedNodes.get(uuid);
- if (childInfo == null) {
- // At this point, we've reached the bottom of the nodes that we have locally.
- // Get the actual location of the last 'info', since all paths will be relative to it...
- Location actualLocation = info.getOriginalLocation();
- Path actualPath = actualLocation.getPath();
- Path nextPath = pathFactory.create(actualPath, child);
- if (pathsIter.hasNext()) {
- // There are multiple remaining paths, so load them all in one batch operation,
- // starting at the top-most path (the one we're currently at)...
- List<Path> pathsInBatch = new LinkedList<Path>();
- Results batchResults = null;
+ 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 {
- Graph.Batch batch = store.batch();
- batch.read(nextPath);
- pathsInBatch.add(nextPath);
- while (pathsIter.hasNext()) {
- child = pathsIter.next();
- nextPath = pathFactory.create(nextPath, child);
- batch.read(nextPath);
- pathsInBatch.add(nextPath);
- }
- batchResults = batch.execute();
- } catch (org.jboss.dna.graph.property.PathNotFoundException e) {
- Path fromPath = getPathFor(fromInfo);
- throw new PathNotFoundException(JcrI18n.pathNotFoundRelativeTo.text(relativePath,
- fromPath,
- workspaceName));
- } catch (RepositorySourceException e) {
- throw new RepositoryException(JcrI18n.errorWhileFindingNodeWithUuid.text(uuid,
- workspaceName,
- e.getLocalizedMessage()));
+ uuid = factories.getUuidFactory().create(uuidValue);
+ break;
+ } catch (ValueFormatException e) {
+ // Ignore; just continue with the next property value
}
- // Now process all of the nodes that we loaded, again starting at the top and going down ...
- for (Path batchPath : pathsInBatch) {
- org.jboss.dna.graph.Node dnaNode = batchResults.getNode(batchPath);
- ImmutableNodeInfo originalChildInfo = createNodeInfoFrom(dnaNode, info);
- this.cachedNodes.put(originalChildInfo.getUuid(), originalChildInfo);
- childInfo = originalChildInfo;
- info = originalChildInfo;
- }
- } else {
- // This is the last path, so do it a little more efficiently than above ...
- childInfo = loadFromGraph(nextPath, info);
- info = childInfo;
}
- } else {
- info = childInfo;
}
+ }
+ }
+ if (uuid == null) uuid = UUID.randomUUID();
+ if (uuidProperty == null) uuidProperty = propertyFactory.create(JcrLexicon.UUID, uuid);
+
+ // Look for the primary type of the node ...
+ Map<Name, Property> graphProperties = persistentNode.getPropertiesByName();
+ final boolean isRoot = location.getPath().isRoot();
+ Name primaryTypeName = null;
+ org.jboss.dna.graph.property.Property primaryTypeProperty = graphProperties.get(JcrLexicon.PRIMARY_TYPE);
+ if (primaryTypeProperty != null && !primaryTypeProperty.isEmpty()) {
+ try {
+ primaryTypeName = factories.getNameFactory().create(primaryTypeProperty.getFirstValue());
+ } catch (ValueFormatException e) {
+ // use the default ...
+ }
+ }
+ if (primaryTypeName == null) {
+ // We have to have a primary type, so use the default ...
+ if (isRoot) {
+ primaryTypeName = DnaLexicon.ROOT;
+ primaryTypeProperty = propertyFactory.create(JcrLexicon.PRIMARY_TYPE, primaryTypeName);
} else {
- info = childInfo;
+ primaryTypeName = defaultPrimaryTypeName;
+ primaryTypeProperty = defaultPrimaryTypeProperty;
}
+ // We have to add this property to the graph node...
+ graphProperties = new HashMap<Name, Property>(graphProperties);
+ graphProperties.put(primaryTypeProperty.getName(), primaryTypeProperty);
}
- }
- SessionCache.this.checkPermission(info, JcrSession.JCR_READ_PERMISSION);
- return info;
- }
+ assert primaryTypeProperty != null;
+ assert primaryTypeProperty.isEmpty() == false;
- /**
- * Find the property information with the given identifier. If the property is not yet loaded into the cache, the node (and
- * its properties) will be read from the repository.
- *
- * @param propertyId the identifier for the property; may not be null
- * @return the property information, or null if the node does not contain the specified property
- * @throws PathNotFoundException if the node containing this property does not exist
- * @throws InvalidItemStateException if the node with the UUID has been deleted in this session
- * @throws RepositoryException if there is an error while obtaining the information
- */
- PropertyInfo findPropertyInfo( PropertyId propertyId )
- throws PathNotFoundException, InvalidItemStateException, RepositoryException {
- NodeInfo info = findNodeInfo(propertyId.getNodeId());
- return info.getProperty(propertyId.getPropertyName());
- }
+ // Look for a node definition stored on the node ...
+ JcrNodeDefinition definition = null;
+ org.jboss.dna.graph.property.Property nodeDefnProperty = graphProperties.get(DnaIntLexicon.NODE_DEFINITON);
+ if (nodeDefnProperty != null && !nodeDefnProperty.isEmpty()) {
+ String nodeDefinitionString = stringFactory.create(nodeDefnProperty.getFirstValue());
+ NodeDefinitionId id = NodeDefinitionId.fromString(nodeDefinitionString, nameFactory);
+ definition = nodeTypes().getNodeDefinition(id);
+ }
+ // Figure out the node definition for this node ...
+ if (definition == null) {
+ if (isRoot) {
+ try {
+ definition = nodeTypes().getRootNodeDefinition();
+ } catch (RepositoryException e) {
+ // Shouldn't really happen ...
+ throw new ValidationException(e.getMessage(), e);
+ }
+ } else {
+ Name childName = node.getName();
+ Node<JcrNodePayload, JcrPropertyPayload> parent = node.getParent();
+ JcrNodePayload parentInfo = parent.getPayload();
+ int numExistingChildrenWithSameName = parent.getChildrenCount(childName);
+ // The children include this node, so we need to subtract one from the count so that the
+ // number of existing children is either 0 (if there are no other SNS nodes) or 1+
+ // (if there are at least 2 SNS nodes)
+ --numExistingChildrenWithSameName;
+ definition = nodeTypes().findChildNodeDefinition(parentInfo.getPrimaryTypeName(),
+ parentInfo.getMixinTypeNames(),
+ childName,
+ primaryTypeName,
+ numExistingChildrenWithSameName,
+ false);
+ }
+ }
+ if (definition == null) {
+ String msg = JcrI18n.nodeDefinitionCouldNotBeDeterminedForNode.text(readable(node.getPath()),
+ workspaceName(),
+ sourceName());
+ throw new ValidationException(msg);
+ }
- Path getPathFor( String workspaceName,
- UUID uuid,
- Path relativePath ) throws NoSuchWorkspaceException, ItemNotFoundException, RepositoryException {
- assert workspaceName != null;
- assert uuid != null || relativePath != null;
+ // ------------------------------------------------------
+ // Set the node's properties ...
+ // ------------------------------------------------------
+ boolean referenceable = false;
- Graph graph = operations.getGraph();
- try {
- graph.useWorkspace(workspaceName);
- } catch (InvalidWorkspaceException iwe) {
- throw new NoSuchWorkspaceException(JcrI18n.workspaceNameIsInvalid.text(graph.getSourceName(), workspaceName));
- }
+ // Start with the primary type ...
+ JcrNodeType primaryType = nodeTypes().getNodeType(primaryTypeName);
+ if (primaryType == null) {
+ Path path = location.getPath();
+ String msg = JcrI18n.missingNodeTypeForExistingNode.text(readable(primaryTypeName),
+ readable(path),
+ workspaceName(),
+ sourceName());
+ throw new ValidationException(msg);
+ }
+ if (primaryType.isNodeType(JcrMixLexicon.REFERENCEABLE)) referenceable = true;
- try {
- org.jboss.dna.graph.Node node;
- if (uuid != null) {
- node = graph.getNodeAt(uuid);
-
- if (relativePath != null) {
- Path nodePath = node.getLocation().getPath();
- Path absolutePath = relativePath.resolveAgainst(nodePath);
- node = graph.getNodeAt(absolutePath);
+ // The process the mixin types ...
+ Property mixinTypesProperty = graphProperties.get(JcrLexicon.MIXIN_TYPES);
+ List<Name> mixinTypeNames = null;
+ if (mixinTypesProperty != null && !mixinTypesProperty.isEmpty()) {
+ for (Object mixinTypeValue : mixinTypesProperty) {
+ Name mixinTypeName = nameFactory.create(mixinTypeValue);
+ if (mixinTypeNames == null) mixinTypeNames = new LinkedList<Name>();
+ mixinTypeNames.add(mixinTypeName);
+ JcrNodeType mixinType = nodeTypes().getNodeType(mixinTypeName);
+ if (mixinType == null) continue;
+ if (!referenceable && mixinType.isNodeType(JcrMixLexicon.REFERENCEABLE)) referenceable = true;
}
+ }
- } else {
- Path absolutePath = pathFactory.createAbsolutePath(relativePath.getSegmentsList());
- node = graph.getNodeAt(absolutePath);
+ // Create the set of multi-valued property names ...
+ Set<Name> multiValuedPropertyNames = EMPTY_NAMES;
+ Set<Name> newSingleMultiPropertyNames = null;
+ Property multiValuedPropNamesProp = graphProperties.get(DnaIntLexicon.MULTI_VALUED_PROPERTIES);
+ if (multiValuedPropNamesProp != null && !multiValuedPropNamesProp.isEmpty()) {
+ multiValuedPropertyNames = getSingleMultiPropertyNames(multiValuedPropNamesProp, location);
}
- assert node != null;
- return node.getLocation().getPath();
- } catch (org.jboss.dna.graph.property.PathNotFoundException pnfe) {
- throw new ItemNotFoundException(pnfe);
- } finally {
- graph.useWorkspace(this.workspaceName);
- }
+ // Create the JCR Node payload object ...
+ JcrNodePayload nodePayload = new JcrNodePayload(SessionCache.this, node, primaryTypeName, mixinTypeNames,
+ definition.getId());
+ AbstractJcrNode jcrNode = nodePayload.getJcrNode();
- }
+ // Now create the JCR property object wrappers around the other properties ...
+ Map<Name, GraphSession.PropertyInfo<JcrPropertyPayload>> props = new HashMap<Name, GraphSession.PropertyInfo<JcrPropertyPayload>>();
+ for (Property dnaProp : graphProperties.values()) {
+ Name name = dnaProp.getName();
- Path getPathFor( UUID uuid ) throws ItemNotFoundException, InvalidItemStateException, RepositoryException {
- if (uuid.equals(root)) return rootPath;
- return getPathFor(findNodeInfo(uuid));
- }
+ // Is this is single-valued property?
+ boolean isSingle = dnaProp.isSingle();
+ // Make sure that this isn't a multi-valued property with one value ...
+ if (isSingle && multiValuedPropertyNames.contains(name)) isSingle = false;
- Path getPathFor( NodeInfo info ) throws ItemNotFoundException, InvalidItemStateException, RepositoryException {
- if (info == null) {
- return pathFactory.createRootPath();
- }
- UUID uuid = info.getUuid();
- if (uuid.equals(root)) return rootPath;
+ // Figure out the JCR property type for this property ...
+ int propertyType = PropertyTypeUtil.jcrPropertyTypeFor(dnaProp);
+ PropertyDefinition propertyDefinition = findBestPropertyDefintion(primaryTypeName,
+ mixinTypeNames,
+ dnaProp,
+ propertyType,
+ isSingle,
+ false);
- // This isn't the root node ...
- Path result = pathCache.get(uuid);
- if (result == null) {
- // We need to build a path using the parent path ...
- UUID parent = info.getParent();
- if (parent == null) {
- // Then this node is the root ...
- root = info.getUuid();
- result = rootPath;
+ // If there still is no property type defined ...
+ if (propertyDefinition == null && INCLUDE_PROPERTIES_NOT_ALLOWED_BY_NODE_TYPE_OR_MIXINS) {
+ // We can use the "nt:unstructured" property definitions for any property ...
+ NodeType unstructured = nodeTypes().getNodeType(JcrNtLexicon.UNSTRUCTURED);
+ for (PropertyDefinition anyDefinition : unstructured.getDeclaredPropertyDefinitions()) {
+ if (anyDefinition.isMultiple()) {
+ propertyDefinition = anyDefinition;
+ break;
+ }
+ }
+ }
+ if (propertyDefinition == null) {
+ // We're supposed to skip this property (since we don't have a definition for it) ...
+ continue;
+ }
+
+ // Figure out if this is a multi-valued property ...
+ boolean isMultiple = propertyDefinition.isMultiple();
+ if (!isMultiple && dnaProp.isEmpty()) {
+ // Only multi-valued properties can have no values; so if not multi-valued, then skip ...
+ continue;
+ }
+
+ // Update the list of single-valued multi-property names ...
+ if (isMultiple && isSingle) {
+ if (newSingleMultiPropertyNames == null) newSingleMultiPropertyNames = new HashSet<Name>();
+ newSingleMultiPropertyNames.add(name);
+ }
+
+ // Figure out the property type ...
+ int definitionType = propertyDefinition.getRequiredType();
+ if (definitionType != PropertyType.UNDEFINED) {
+ propertyType = definitionType;
+ }
+
+ // Record the property in the node information ...
+ JcrPropertyDefinition defn = (JcrPropertyDefinition)propertyDefinition;
+ AbstractJcrProperty jcrProp = null;
+ if (isMultiple) {
+ jcrProp = new JcrMultiValueProperty(SessionCache.this, jcrNode, dnaProp.getName());
+ } else {
+ jcrProp = new JcrSingleValueProperty(SessionCache.this, jcrNode, dnaProp.getName());
+ }
+ JcrPropertyPayload payload = new JcrPropertyPayload(defn.getId(), propertyType, jcrProp);
+ PropertyInfo<JcrPropertyPayload> propInfo = new PropertyInfo<JcrPropertyPayload>(dnaProp, defn.isMultiple(),
+ Status.UNCHANGED, payload);
+ props.put(name, propInfo);
+ }
+
+ // Now add the "jcr:uuid" property if and only if referenceable ...
+ if (referenceable) {
+ // We know that this property is single-valued
+ JcrValue value = new JcrValue(factories(), SessionCache.this, PropertyType.STRING, uuid);
+ JcrPropertyDefinition propDefn = nodeTypes().findPropertyDefinition(primaryTypeName,
+ mixinTypeNames,
+ JcrLexicon.UUID,
+ value,
+ false,
+ false);
+ PropertyInfo<JcrPropertyPayload> propInfo = createPropertyInfo(nodePayload,
+ uuidProperty,
+ propDefn,
+ PropertyType.STRING,
+ null);
+ props.put(JcrLexicon.UUID, propInfo);
} else {
- NodeInfo parentInfo = findNodeInfo(parent);
- Path parentPath = getPathFor(parentInfo);
- ChildNode child = parentInfo.getChildren().getChild(info.getUuid());
- result = pathFactory.create(parentPath, child.getSegment());
+ // Make sure there is NOT a "jcr:uuid" property ...
+ props.remove(JcrLexicon.UUID);
}
- pathCache.put(uuid, result);
- }
- assert result != null;
- return result;
- }
+ // Make sure the "dna:uuid" property did not get in there ...
+ props.remove(DnaLexicon.UUID);
- Path getPathFor( PropertyInfo propertyInfo ) throws ItemNotFoundException, RepositoryException {
- Path nodePath = getPathFor(propertyInfo.getNodeUuid());
- return pathFactory.create(nodePath, propertyInfo.getPropertyName());
- }
+ // Make sure the single-valued multi-property names are stored as a property ...
+ if (newSingleMultiPropertyNames != null) {
+ PropertyInfo<JcrPropertyPayload> info = createSingleMultipleProperty(nodePayload,
+ null,
+ newSingleMultiPropertyNames);
+ props.put(info.getName(), info);
+ }
- Path getPathFor( PropertyId propertyId ) throws ItemNotFoundException, RepositoryException {
- return getPathFor(findPropertyInfo(propertyId));
- }
+ // Set the information on the node ...
+ node.loadedWith(persistentNode.getChildren(), props, persistentNode.getExpirationTime());
+ node.setPayload(nodePayload);
+ }
- protected Name getNameOf( UUID nodeUuid ) throws ItemNotFoundException, InvalidItemStateException, RepositoryException {
- findNodeInfoForRoot();
- if (nodeUuid == root) return nameFactory.create("");
- // Get the parent ...
- NodeInfo info = findNodeInfo(nodeUuid);
- NodeInfo parent = findNodeInfo(info.getParent());
- ChildNode child = parent.getChildren().getChild(info.getUuid());
- return child.getName();
- }
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.graph.session.GraphSession.NodeOperations#postSetProperty(org.jboss.dna.graph.session.GraphSession.Node,
+ * org.jboss.dna.graph.property.Name, org.jboss.dna.graph.session.GraphSession.PropertyInfo)
+ */
+ @Override
+ public void postSetProperty( Node<JcrNodePayload, JcrPropertyPayload> node,
+ Name propertyName,
+ PropertyInfo<JcrPropertyPayload> oldProperty ) {
+ super.postSetProperty(node, propertyName, oldProperty);
- protected int getSnsIndexOf( UUID nodeUuid ) throws ItemNotFoundException, InvalidItemStateException, RepositoryException {
- findNodeInfoForRoot();
- if (nodeUuid == root) return 1;
- // Get the parent ...
- NodeInfo info = findNodeInfo(nodeUuid);
- NodeInfo parent = findNodeInfo(info.getParent());
- ChildNode child = parent.getChildren().getChild(info.getUuid());
- return child.getSnsIndex();
- }
+ if (propertyName.equals(DnaIntLexicon.MULTI_VALUED_PROPERTIES)) return;
+ if (propertyName.equals(JcrLexicon.MIXIN_TYPES)) {
+ // Add all of the values from the property ...
+ Set<Name> mixinTypeNames = new HashSet<Name>();
+ NameFactory nameFactory = context().getValueFactories().getNameFactory();
+ for (Object value : node.getProperty(propertyName).getProperty()) {
+ mixinTypeNames.add(nameFactory.create(value));
+ }
+ node.setPayload(node.getPayload().with(new ArrayList<Name>(mixinTypeNames)));
+ }
- /**
- * Load from the underlying repository graph the information for the node with the supplied UUID. This method returns the
- * information for the requested node (after placing it in the cache), but this method may (at its discretion) also load and
- * cache information for other nodes.
- * <p>
- * Note that this method does not check the cache before loading from the repository graph.
- * </p>
- *
- * @param path the path of the node, if known; may be null only if the UUID is supplied
- * @param uuid the UUID of the node, if known; may be null only if the path is supplied
- * @return the information for the node
- * @throws ItemNotFoundException if the node does not exist in the repository
- * @throws RepositoryException if there was an error obtaining this information from the repository
- */
- protected ImmutableNodeInfo loadFromGraph( Path path,
- UUID uuid ) throws ItemNotFoundException, RepositoryException {
- // Load the node information from the store ...
- try {
- // See if there is a path for this uuid ...
- Location location = Location.create(path, uuid);
- org.jboss.dna.graph.Node node = store.getNodeAt(location);
- ImmutableNodeInfo info = createNodeInfoFrom(node, null);
- this.cachedNodes.put(info.getUuid(), info);
- return info;
- } catch (org.jboss.dna.graph.property.PathNotFoundException e) {
- throw new ItemNotFoundException(JcrI18n.itemNotFoundWithUuid.text(uuid, workspaceName, e.getLocalizedMessage()));
- } catch (RepositorySourceException e) {
- throw new RepositoryException(
- JcrI18n.errorWhileFindingNodeWithUuid.text(uuid, workspaceName, e.getLocalizedMessage()),
- e);
+ // If the property is multi-valued but has only a single value, we need to record that this property
+ // is actually a multi-valued property definition ...
+ PropertyInfo<JcrPropertyPayload> changedProperty = node.getProperty(propertyName);
+ if (changedProperty.isMultiValued()) {
+ // We're changing a multi-valued property ...
+ if (changedProperty.getProperty().isSingle()) {
+ // There's only one actual value in this property, so we record the name of this property in a hidden property
+ updateSingleMultipleProperty(node, propertyName, true);
+ } else {
+ // There are multiple actual values, so we don't need to name this property in the hidden property ...
+ updateSingleMultipleProperty(node, propertyName, false);
+ }
+ }
}
- }
- /**
- * Load from the underlying repository graph the information for the node with the supplied UUID. This method returns the
- * information for the requested node (after placing it in the cache), but this method may (at its discretion) also load and
- * cache information for other nodes.
- * <p>
- * Note that this method does not check the cache before loading from the repository graph.
- * </p>
- *
- * @param path the path to the node; may not be null
- * @param parentInfo the parent information; may be null if not known
- * @return the information for the node
- * @throws PathNotFoundException if the node does not exist in the repository
- * @throws RepositoryException if there was an error obtaining this information from the repository
- */
- protected ImmutableNodeInfo loadFromGraph( Path path,
- NodeInfo parentInfo ) throws PathNotFoundException, RepositoryException {
- // Load the node information from the store ...
- try {
- org.jboss.dna.graph.Node node = store.getNodeAt(path);
- ImmutableNodeInfo info = createNodeInfoFrom(node, parentInfo);
- this.cachedNodes.put(info.getUuid(), info);
- return info;
- } catch (org.jboss.dna.graph.property.PathNotFoundException e) {
- throw new PathNotFoundException(JcrI18n.pathNotFound.text(path, workspaceName));
- } catch (RepositorySourceException e) {
- throw new RepositoryException(JcrI18n.errorWhileFindingNodeWithPath.text(path, workspaceName));
- }
- }
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.graph.session.GraphSession.Operations#preSave(org.jboss.dna.graph.session.GraphSession.Node)
+ */
+ @Override
+ public void preSave( org.jboss.dna.graph.session.GraphSession.Node<JcrNodePayload, JcrPropertyPayload> node )
+ throws ValidationException {
+ JcrNodePayload payload = node.getPayload();
- /**
- * Create the {@link NodeInfo} object given the DNA graph node and the parent node information (if it is available).
- *
- * @param graphNode the DNA graph node; may not be null
- * @param parentInfo the information for the parent node, or null if the supplied graph node represents the root node, or if
- * the parent information is not known
- * @return the node information; never null
- * @throws RepositoryException if there is an error determining the child {@link NodeDefinition} for the supplied node,
- * preventing the node information from being constructed
- */
- private ImmutableNodeInfo createNodeInfoFrom( org.jboss.dna.graph.Node graphNode,
- NodeInfo parentInfo ) throws RepositoryException {
- // Now get the DNA node's UUID and find the DNA property containing the UUID ...
- Location location = graphNode.getLocation();
- UUID uuid = location.getUuid();
- org.jboss.dna.graph.property.Property uuidProperty = null;
- if (uuid != null) {
- // Check for an identification property ...
- uuidProperty = location.getIdProperty(JcrLexicon.UUID);
- if (uuidProperty == null) {
- uuidProperty = propertyFactory.create(JcrLexicon.UUID, uuid);
+ Name primaryTypeName = payload.getPrimaryTypeName();
+ List<Name> mixinTypeNames = payload.getMixinTypeNames();
+ Set<JcrNodeDefinition> satisfiedChildNodes = new HashSet<JcrNodeDefinition>();
+ Set<JcrPropertyDefinition> satisfiedProperties = new HashSet<JcrPropertyDefinition>();
+
+ for (org.jboss.dna.graph.session.GraphSession.PropertyInfo<JcrPropertyPayload> property : node.getProperties()) {
+ JcrPropertyPayload propPayload = property.getPayload();
+ JcrPropertyDefinition definition = findBestPropertyDefintion(primaryTypeName,
+ mixinTypeNames,
+ property.getProperty(),
+ propPayload.getPropertyType(),
+ property.getProperty().isSingle(),
+ false);
+ if (definition == null) {
+ throw new ValidationException(JcrI18n.noDefinition.text("property",
+ readable(property.getName()),
+ readable(node.getPath()),
+ readable(primaryTypeName),
+ readable(mixinTypeNames)));
+ }
+
+ satisfiedProperties.add(definition);
}
- }
- if (uuidProperty == null) {
- uuidProperty = graphNode.getProperty(JcrLexicon.UUID);
- 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
- }
+
+ for (org.jboss.dna.graph.session.GraphSession.Node<JcrNodePayload, JcrPropertyPayload> child : node.getChildren()) {
+ int snsCount = node.getChildrenCount(child.getName());
+ JcrNodeDefinition definition = nodeTypes().findChildNodeDefinition(primaryTypeName,
+ mixinTypeNames,
+ child.getName(),
+ child.getPayload().getPrimaryTypeName(),
+ snsCount,
+ false);
+ if (definition == null) {
+ throw new ValidationException(JcrI18n.noDefinition.text("child node",
+ readable(child.getName()),
+ readable(node.getPath()),
+ readable(primaryTypeName),
+ readable(mixinTypeNames)));
}
+ satisfiedChildNodes.add(definition);
}
- if (uuid == null) {
- // Look for the DNA UUID property ...
- org.jboss.dna.graph.property.Property dnaUuidProperty = graphNode.getProperty(DnaLexicon.UUID);
- if (dnaUuidProperty != null) {
- // Grab the first 'good' UUID value ...
- for (Object uuidValue : dnaUuidProperty) {
- try {
- uuid = factories.getUuidFactory().create(uuidValue);
- break;
- } catch (ValueFormatException e) {
- // Ignore; just continue with the next property value
+
+ JcrNodeType primaryType = nodeTypes().getNodeType(primaryTypeName);
+ for (JcrPropertyDefinition definition : primaryType.getPropertyDefinitions()) {
+ if (definition.isMandatory() && !definition.isProtected() && !satisfiedProperties.contains(definition)) {
+ throw new ValidationException(JcrI18n.noDefinition.text("property",
+ definition.getName(),
+ readable(node.getPath()),
+ readable(primaryTypeName),
+ readable(mixinTypeNames)));
+ }
+ }
+ for (JcrNodeDefinition definition : primaryType.getChildNodeDefinitions()) {
+ if (definition.isMandatory() && !definition.isProtected() && !satisfiedChildNodes.contains(definition)) {
+ throw new ValidationException(JcrI18n.noDefinition.text("child node",
+ definition.getName(),
+ readable(node.getPath()),
+ readable(primaryTypeName),
+ readable(mixinTypeNames)));
+ }
+ }
+
+ if (mixinTypeNames != null) {
+ for (Name mixinTypeName : mixinTypeNames) {
+ JcrNodeType mixinType = nodeTypes().getNodeType(mixinTypeName);
+ for (JcrPropertyDefinition definition : mixinType.getPropertyDefinitions()) {
+ if (definition.isMandatory() && !definition.isProtected() && !satisfiedProperties.contains(definition)) {
+ throw new ValidationException(JcrI18n.noDefinition.text("child node",
+ definition.getName(),
+ readable(node.getPath()),
+ readable(primaryTypeName),
+ readable(mixinTypeNames)));
}
}
+ for (JcrNodeDefinition definition : mixinType.getChildNodeDefinitions()) {
+ if (definition.isMandatory() && !definition.isProtected() && !satisfiedChildNodes.contains(definition)) {
+ throw new ValidationException(JcrI18n.noDefinition.text("child node",
+ definition.getName(),
+ readable(node.getPath()),
+ readable(primaryTypeName),
+ readable(mixinTypeNames)));
+ }
+ }
+
}
}
}
- if (uuid == null) uuid = UUID.randomUUID();
- if (uuidProperty == null) uuidProperty = propertyFactory.create(JcrLexicon.UUID, uuid);
- // Either the UUID is not known, or there was no node. Either way, we have to create the node ...
- if (uuid == null) uuid = UUID.randomUUID();
-
- // Look for the primary type of the node ...
- Map<Name, Property> graphProperties = graphNode.getPropertiesByName();
- final boolean isRoot = location.getPath().isRoot();
- Name primaryTypeName = null;
- org.jboss.dna.graph.property.Property primaryTypeProperty = graphNode.getProperty(JcrLexicon.PRIMARY_TYPE);
- if (primaryTypeProperty != null && !primaryTypeProperty.isEmpty()) {
- try {
- primaryTypeName = factories.getNameFactory().create(primaryTypeProperty.getFirstValue());
- } catch (ValueFormatException e) {
- // use the default ...
+ protected final Set<Name> getSingleMultiPropertyNames( Property dnaProperty,
+ Location location ) {
+ Set<Name> multiValuedPropertyNames = new HashSet<Name>();
+ for (Object value : dnaProperty) {
+ try {
+ multiValuedPropertyNames.add(nameFactory.create(value));
+ } catch (ValueFormatException e) {
+ String msg = "{0} value \"{1}\" on {2} in \"{3}\" workspace is not a valid name and is being ignored";
+ Logger.getLogger(getClass()).trace(e,
+ msg,
+ readable(DnaIntLexicon.MULTI_VALUED_PROPERTIES),
+ value,
+ readable(location),
+ workspaceName());
+ }
}
+ return multiValuedPropertyNames;
}
- if (primaryTypeName == null) {
- // We have to have a primary type, so use the default ...
- if (isRoot) {
- primaryTypeName = DnaLexicon.ROOT;
- primaryTypeProperty = propertyFactory.create(JcrLexicon.PRIMARY_TYPE, primaryTypeName);
- } else {
- primaryTypeName = defaultPrimaryTypeName;
- primaryTypeProperty = defaultPrimaryTypeProperty;
- }
- // We have to add this property to the graph node...
- graphProperties = new HashMap<Name, Property>(graphProperties);
- graphProperties.put(primaryTypeProperty.getName(), primaryTypeProperty);
- }
- assert primaryTypeProperty != null;
- assert primaryTypeProperty.isEmpty() == false;
+ }
- // Look for a node definition stored on the node ...
- JcrNodeDefinition definition = null;
- org.jboss.dna.graph.property.Property nodeDefnProperty = graphProperties.get(DnaIntLexicon.NODE_DEFINITON);
- if (nodeDefnProperty != null && !nodeDefnProperty.isEmpty()) {
- String nodeDefinitionString = stringFactory.create(nodeDefnProperty.getFirstValue());
- NodeDefinitionId id = NodeDefinitionId.fromString(nodeDefinitionString, nameFactory);
- definition = nodeTypes().getNodeDefinition(id);
- }
- // Figure out the node definition for this node ...
- if (isRoot) {
- if (definition == null) definition = nodeTypes().getRootNodeDefinition();
- } else {
- // We need the parent ...
- Path path = location.getPath();
- if (parentInfo == null) {
- Path parentPath = path.getParent();
- parentInfo = findNodeInfo(null, parentPath.getNormalizedPath());
+ @Immutable
+ final class JcrAuthorizer implements GraphSession.Authorizer {
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.graph.session.GraphSession.Authorizer#checkPermissions(org.jboss.dna.graph.property.Path,
+ * org.jboss.dna.graph.session.GraphSession.Authorizer.Action)
+ */
+ public void checkPermissions( Path path,
+ Action action ) throws AccessControlException {
+ String jcrAction = null;
+ switch (action) {
+ case ADD_NODE:
+ jcrAction = JcrSession.JCR_ADD_NODE_PERMISSION;
+ break;
+ case READ:
+ jcrAction = JcrSession.JCR_READ_PERMISSION;
+ break;
+ case REMOVE:
+ jcrAction = JcrSession.JCR_REMOVE_PERMISSION;
+ break;
+ case SET_PROPERTY:
+ jcrAction = JcrSession.JCR_SET_PROPERTY_PERMISSION;
+ break;
}
- if (definition == null) {
- Name childName = path.getLastSegment().getName();
- int numExistingChildrenWithSameName = parentInfo.getChildren().getCountOfSameNameSiblingsWithName(childName);
- definition = nodeTypes().findChildNodeDefinition(parentInfo.getPrimaryTypeName(),
- parentInfo.getMixinTypeNames(),
- childName,
- primaryTypeName,
- numExistingChildrenWithSameName,
- false);
- }
- if (definition == null) {
- String msg = JcrI18n.nodeDefinitionCouldNotBeDeterminedForNode.text(path, workspaceName);
- throw new RepositorySourceException(sourceName(), msg);
- }
+ session().checkPermission(path, jcrAction);
}
+ }
- // ------------------------------------------------------
- // Set the node's properties ...
- // ------------------------------------------------------
- boolean referenceable = false;
+ @Immutable
+ final static class JcrPropertyPayload {
+ private final PropertyDefinitionId propertyDefinitionId;
+ private final int jcrPropertyType;
+ private final SoftReference<AbstractJcrProperty> jcrProperty;
- // Start with the primary type ...
- JcrNodeType primaryType = nodeTypes().getNodeType(primaryTypeName);
- if (primaryType == null) {
- Path path = location.getPath();
- String msg = JcrI18n.missingNodeTypeForExistingNode.text(primaryTypeName.getString(namespaces), path, workspaceName);
- throw new RepositorySourceException(sourceName(), msg);
+ JcrPropertyPayload( PropertyDefinitionId propertyDefinitionId,
+ int jcrPropertyType,
+ AbstractJcrProperty jcrProperty ) {
+ assert jcrProperty != null;
+ this.propertyDefinitionId = propertyDefinitionId;
+ this.jcrPropertyType = jcrPropertyType;
+ this.jcrProperty = new SoftReference<AbstractJcrProperty>(jcrProperty);
}
- if (primaryType.isNodeType(JcrMixLexicon.REFERENCEABLE)) referenceable = true;
- // The process the mixin types ...
- Property mixinTypesProperty = graphProperties.get(JcrLexicon.MIXIN_TYPES);
- List<Name> mixinTypeNames = null;
- if (mixinTypesProperty != null && !mixinTypesProperty.isEmpty()) {
- for (Object mixinTypeValue : mixinTypesProperty) {
- Name mixinTypeName = nameFactory.create(mixinTypeValue);
- if (mixinTypeNames == null) mixinTypeNames = new LinkedList<Name>();
- mixinTypeNames.add(mixinTypeName);
- JcrNodeType mixinType = nodeTypes().getNodeType(mixinTypeName);
- if (mixinType == null) continue;
- if (!referenceable && mixinType.isNodeType(JcrMixLexicon.REFERENCEABLE)) referenceable = true;
- }
+ JcrPropertyPayload( PropertyDefinitionId propertyDefinitionId,
+ int jcrPropertyType,
+ SoftReference<AbstractJcrProperty> jcrProperty ) {
+ this.propertyDefinitionId = propertyDefinitionId;
+ this.jcrPropertyType = jcrPropertyType;
+ this.jcrProperty = jcrProperty;
}
- // Create the set of multi-valued property names ...
- Set<Name> multiValuedPropertyNames = EMPTY_NAMES;
- Set<Name> newSingleMultiPropertyNames = null;
- Property multiValuedPropNamesProp = graphProperties.get(DnaIntLexicon.MULTI_VALUED_PROPERTIES);
- if (multiValuedPropNamesProp != null && !multiValuedPropNamesProp.isEmpty()) {
- multiValuedPropertyNames = getSingleMultiPropertyNames(multiValuedPropNamesProp, location.getPath(), uuid);
+ /**
+ * @return jcrProperty
+ */
+ public AbstractJcrProperty getJcrProperty() {
+ return jcrProperty.get();
}
- // Now create the JCR property object wrappers around the other properties ...
- Map<Name, PropertyInfo> props = new HashMap<Name, PropertyInfo>();
- for (Property dnaProp : graphProperties.values()) {
- Name name = dnaProp.getName();
+ /**
+ * @return jcrPropertyType
+ */
+ public int getPropertyType() {
+ return jcrPropertyType;
+ }
- // Is this is single-valued property?
- boolean isSingle = dnaProp.isSingle();
- // Make sure that this isn't a multi-valued property with one value ...
- if (isSingle && multiValuedPropertyNames.contains(name)) isSingle = false;
+ /**
+ * @return propertyDefinitionId
+ */
+ public PropertyDefinitionId getPropertyDefinitionId() {
+ return propertyDefinitionId;
+ }
- // Figure out the JCR property type for this property ...
- int propertyType = PropertyTypeUtil.jcrPropertyTypeFor(dnaProp);
- PropertyDefinition propertyDefinition = findBestPropertyDefintion(primaryTypeName,
- mixinTypeNames,
- dnaProp,
- propertyType,
- isSingle,
- false);
+ public JcrPropertyPayload with( PropertyDefinitionId propertyDefinitionId ) {
+ return new JcrPropertyPayload(propertyDefinitionId, jcrPropertyType, jcrProperty);
+ }
- // If there still is no property type defined ...
- if (propertyDefinition == null && INCLUDE_PROPERTIES_NOT_ALLOWED_BY_NODE_TYPE_OR_MIXINS) {
- // We can use the "nt:unstructured" property definitions for any property ...
- NodeType unstructured = nodeTypes().getNodeType(JcrNtLexicon.UNSTRUCTURED);
- for (PropertyDefinition anyDefinition : unstructured.getDeclaredPropertyDefinitions()) {
- if (anyDefinition.isMultiple()) {
- propertyDefinition = anyDefinition;
- break;
- }
- }
- }
- if (propertyDefinition == null) {
- // We're supposed to skip this property (since we don't have a definition for it) ...
- continue;
- }
+ public JcrPropertyPayload with( int jcrPropertyType ) {
+ return new JcrPropertyPayload(propertyDefinitionId, jcrPropertyType, jcrProperty);
+ }
- // Figure out if this is a multi-valued property ...
- boolean isMultiple = propertyDefinition.isMultiple();
- if (!isMultiple && dnaProp.isEmpty()) {
- // Only multi-valued properties can have no values; so if not multi-valued, then skip ...
- continue;
- }
+ public JcrPropertyPayload with( AbstractJcrProperty jcrProperty ) {
+ return new JcrPropertyPayload(propertyDefinitionId, jcrPropertyType, jcrProperty);
+ }
+ }
- // Update the list of single-valued multi-property names ...
- if (isMultiple && isSingle) {
- if (newSingleMultiPropertyNames == null) newSingleMultiPropertyNames = new HashSet<Name>();
- newSingleMultiPropertyNames.add(name);
- }
+ @Immutable
+ final static class JcrNodePayload {
+ private final SessionCache cache;
+ private final Node<JcrNodePayload, JcrPropertyPayload> owner;
+ private final Name primaryTypeName;
+ private final List<Name> mixinTypeNames;
+ private final NodeDefinitionId nodeDefinitionId;
+ private SoftReference<AbstractJcrNode> jcrNode;
- // Figure out the property type ...
- int definitionType = propertyDefinition.getRequiredType();
- if (definitionType != PropertyType.UNDEFINED) {
- propertyType = definitionType;
- }
+ JcrNodePayload( SessionCache cache,
+ Node<JcrNodePayload, JcrPropertyPayload> owner,
+ Name primaryTypeName,
+ List<Name> mixinTypeNames,
+ NodeDefinitionId nodeDefinitionId ) {
+ assert owner != null;
+ assert cache != null;
+ this.cache = cache;
+ this.owner = owner;
+ this.primaryTypeName = primaryTypeName;
+ this.mixinTypeNames = mixinTypeNames;
+ this.nodeDefinitionId = nodeDefinitionId;
+ this.jcrNode = new SoftReference<AbstractJcrNode>(null);
+ }
- // Record the property in the node information ...
- PropertyId propId = new PropertyId(uuid, name);
- JcrPropertyDefinition defn = (JcrPropertyDefinition)propertyDefinition;
- PropertyInfo propInfo = new PropertyInfo(propId, defn.getId(), propertyType, dnaProp, defn.isMultiple(), false, false);
- props.put(name, propInfo);
+ JcrNodePayload( SessionCache cache,
+ Node<JcrNodePayload, JcrPropertyPayload> owner,
+ Name primaryTypeName,
+ List<Name> mixinTypeNames,
+ NodeDefinitionId nodeDefinitionId,
+ SoftReference<AbstractJcrNode> jcrNode ) {
+ assert jcrNode != null;
+ assert owner != null;
+ assert cache != null;
+ this.cache = cache;
+ this.owner = owner;
+ this.primaryTypeName = primaryTypeName;
+ this.mixinTypeNames = mixinTypeNames;
+ this.nodeDefinitionId = nodeDefinitionId;
+ this.jcrNode = jcrNode;
}
- // Now add the "jcr:uuid" property if and only if referenceable ...
- if (referenceable) {
- // We know that this property is single-valued
- JcrValue value = new JcrValue(factories(), this, PropertyType.STRING, uuid);
- PropertyDefinition propertyDefinition = nodeTypes().findPropertyDefinition(primaryTypeName,
- mixinTypeNames,
- JcrLexicon.UUID,
- value,
- false,
- false);
- PropertyId propId = new PropertyId(uuid, JcrLexicon.UUID);
- JcrPropertyDefinition defn = (JcrPropertyDefinition)propertyDefinition;
- PropertyInfo propInfo = new PropertyInfo(propId, defn.getId(), PropertyType.STRING, uuidProperty, defn.isMultiple(),
- false, false);
- props.put(JcrLexicon.UUID, propInfo);
- } else {
- // Make sure there is NOT a "jcr:uuid" property ...
- props.remove(JcrLexicon.UUID);
+ /**
+ * @return primaryTypeName
+ */
+ public Name getPrimaryTypeName() {
+ return this.primaryTypeName;
}
- // Make sure the "dna:uuid" property did not get in there ...
- props.remove(DnaLexicon.UUID);
- // Make sure the single-valued multi-property names are stored as a property ...
- if (newSingleMultiPropertyNames != null) {
- PropertyInfo info = createSingleMultiplePropertyInfo(uuid,
- primaryTypeName,
- mixinTypeNames,
- newSingleMultiPropertyNames);
- props.put(info.getPropertyName(), info);
+ /**
+ * Get the names of the mixin types for this node.
+ *
+ * @return the unmodifiable list of mixin type names; never null but possibly empty
+ */
+ public List<Name> getMixinTypeNames() {
+ return this.mixinTypeNames != null ? this.mixinTypeNames : Collections.<Name>emptyList();
}
- // Create the node information ...
- UUID parentUuid = parentInfo != null ? parentInfo.getUuid() : null;
- List<Location> locations = graphNode.getChildren();
- Children children = locations.isEmpty() ? new EmptyChildren(parentUuid) : new ImmutableChildren(parentUuid, locations);
- props = Collections.unmodifiableMap(props);
- return new ImmutableNodeInfo(location, primaryTypeName, mixinTypeNames, definition.getId(), parentUuid, children, props);
- }
-
- protected final PropertyInfo createSingleMultiplePropertyInfo( UUID uuid,
- Name primaryTypeName,
- List<Name> mixinTypeNames,
- Set<Name> newSingleMultiPropertyNames ) {
- int number = newSingleMultiPropertyNames.size();
- String[] names = new String[number];
- JcrValue[] values = new JcrValue[number];
- if (number == 1) {
- String str = newSingleMultiPropertyNames.iterator().next().getString(namespaces);
- names[0] = str;
- values[0] = new JcrValue(factories(), this, PropertyType.STRING, str);
- } else {
- int index = 0;
- for (Name name : newSingleMultiPropertyNames) {
- String str = name.getString(namespaces);
- names[index] = str;
- values[index] = new JcrValue(factories(), this, PropertyType.STRING, str);
- ++index;
- }
+ /**
+ * @return definition
+ */
+ public NodeDefinitionId getDefinitionId() {
+ return this.nodeDefinitionId;
}
- PropertyDefinition propertyDefinition = nodeTypes().findPropertyDefinition(primaryTypeName,
- mixinTypeNames,
- DnaIntLexicon.MULTI_VALUED_PROPERTIES,
- values,
- false);
- Property dnaProp = propertyFactory.create(DnaIntLexicon.MULTI_VALUED_PROPERTIES,
- newSingleMultiPropertyNames.iterator().next());
- PropertyId propId = new PropertyId(uuid, dnaProp.getName());
- JcrPropertyDefinition defn = (JcrPropertyDefinition)propertyDefinition;
- return new PropertyInfo(propId, defn.getId(), PropertyType.STRING, dnaProp, defn.isMultiple(), true, false);
- }
- protected final Set<Name> getSingleMultiPropertyNames( Property dnaProperty,
- Path knownPath,
- UUID knownUuid ) {
- Set<Name> multiValuedPropertyNames = new HashSet<Name>();
- for (Object value : dnaProperty) {
- try {
- multiValuedPropertyNames.add(nameFactory.create(value));
- } catch (ValueFormatException e) {
- String msg = "{0} value \"{1}\" on {2} in \"{3}\" workspace is not a valid name and is being ignored";
- String path = null;
- if (knownPath != null) {
- path = knownPath.getString(namespaces);
+ /**
+ * Get the JCR node instance.
+ *
+ * @return jcrNode
+ */
+ public AbstractJcrNode getJcrNode() {
+ AbstractJcrNode node = jcrNode.get();
+ if (node == null) {
+ if (owner.isRoot()) {
+ node = new JcrRootNode(cache, owner.getNodeId(), owner.getLocation());
} else {
- assert knownUuid != null;
- try {
- path = getPathFor(knownUuid).getString(namespaces);
- } catch (RepositoryException err) {
- path = knownUuid.toString();
- }
+ node = new JcrNode(cache, owner.getNodeId(), owner.getLocation());
}
- Logger.getLogger(getClass()).trace(e,
- msg,
- DnaIntLexicon.MULTI_VALUED_PROPERTIES.getString(namespaces),
- value,
- path,
- workspaceName());
+ jcrNode = new SoftReference<AbstractJcrNode>(node);
}
+ return jcrNode.get();
}
- return multiValuedPropertyNames;
- }
- /**
- * This method finds the {@link NodeInfo} for the node with the supplied UUID and marks it as being deleted, and does the same
- * for all decendants (e.g., children, grandchildren, great-grandchildren, etc.) that have been cached or changed.
- * <p>
- * Note that this method only processes those nodes that are actually represented in this cache. Any branches that are not
- * loaded are not processed. This is an acceptable assumption, since all ancestors of a cached node should also be cached.
- * </p>
- * <p>
- * Also be aware that the returned count of deleted node info representations will only reflect the total number of nodes in
- * the branch if and only if all branch nodes were cached. In all other cases, the count returned will be fewer than the
- * number of actual nodes in the branch.
- * </p>
- *
- * @param uuid the UUID of the node that should be marked as deleted; may not be null
- * @return the number of node info representations that were marked as deleted
- */
- protected int deleteNodeInfos( UUID uuid ) {
- Queue<UUID> nodesToDelete = new LinkedList<UUID>();
- int numDeleted = 0;
- nodesToDelete.add(uuid);
- while (!nodesToDelete.isEmpty()) {
- UUID toDelete = nodesToDelete.remove();
- // Remove the node info from the changed map ...
- NodeInfo info = changedNodes.remove(toDelete);
- if (info == null) {
- // Wasn't changed, so remove it from the cache map ...
- info = cachedNodes.remove(toDelete);
- }
- // Whether or not we found an info, add it to the deleted map ...
- this.deletedNodes.put(toDelete, info);
+ public JcrNodePayload with( Name primaryTypeName ) {
+ return new JcrNodePayload(cache, owner, primaryTypeName, mixinTypeNames, nodeDefinitionId, jcrNode);
+ }
- // Remove it from the path cache ...
- this.pathCache.remove(toDelete);
+ public JcrNodePayload with( List<Name> mixinTypeNames ) {
+ return new JcrNodePayload(cache, owner, primaryTypeName, mixinTypeNames, nodeDefinitionId, jcrNode);
+ }
- if (info != null) {
- // Get all the children and add them to the queue ...
- for (ChildNode child : info.getChildren()) {
- nodesToDelete.add(child.getUuid());
- }
- }
- ++numDeleted;
+ public JcrNodePayload with( NodeDefinitionId nodeDefinitionId ) {
+ return new JcrNodePayload(cache, owner, primaryTypeName, mixinTypeNames, nodeDefinitionId, jcrNode);
}
- return numDeleted;
+
+ public JcrNodePayload with( AbstractJcrNode jcrNode ) {
+ return new JcrNodePayload(cache, owner, primaryTypeName, mixinTypeNames, nodeDefinitionId,
+ new SoftReference<AbstractJcrNode>(jcrNode));
+ }
}
+
}
Deleted: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/ChangedChildren.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/ChangedChildren.java 2009-07-09 16:23:09 UTC (rev 1081)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/ChangedChildren.java 2009-07-09 16:26:04 UTC (rev 1082)
@@ -1,128 +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.
- *
- * 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.jcr.cache;
-
-import java.util.List;
-import java.util.ListIterator;
-import java.util.UUID;
-import net.jcip.annotations.NotThreadSafe;
-import org.jboss.dna.graph.property.Name;
-import org.jboss.dna.graph.property.Path;
-import org.jboss.dna.graph.property.PathFactory;
-
-/**
- * A {@link NotThreadSafe non-thread safe} implementation of {@link Children} that can be modified in place. This is typically
- * used to capture changes made within a session.
- */
-@NotThreadSafe
-public class ChangedChildren extends ImmutableChildren {
-
- public ChangedChildren( Children original ) {
- super(original);
- }
-
- /**
- * Creates an empty instance.
- *
- * @param parentUuid the UUID of the parent node
- */
- protected ChangedChildren( UUID parentUuid ) {
- super(parentUuid);
- }
-
- protected ChangedChildren( ImmutableChildren original,
- Name additionalChildName,
- Path.Segment beforeChild,
- UUID childUuid,
- PathFactory pathFactory ) {
- super(original, additionalChildName, beforeChild, childUuid, pathFactory);
- }
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.jcr.cache.ImmutableChildren#with(org.jboss.dna.graph.property.Name, java.util.UUID,
- * org.jboss.dna.graph.property.PathFactory)
- */
- @Override
- public ChangedChildren with( Name newChildName,
- UUID newChildUuid,
- PathFactory pathFactory ) {
- // Simply add the node to this object ...
- super.add(newChildName, newChildUuid, pathFactory);
- return this;
- }
-
- /**
- * Create another Children object that is equivalent to this node but with the supplied child added before the named node.
- *
- * @param newChildName the name of the new child; may not be null
- * @param beforeChild the path segment of the child before which this node should be added; may not be null
- * @param newChildUuid the UUID of the new child; may not be null
- * @param pathFactory the factory that can be used to create Path and/or Path.Segment instances.
- * @return the new Children object; never null
- */
- public ChangedChildren with( Name newChildName,
- Path.Segment beforeChild,
- UUID newChildUuid,
- PathFactory pathFactory ) {
- return new ChangedChildren(this, newChildName, beforeChild, newChildUuid, pathFactory);
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.jcr.cache.ImmutableChildren#without(java.util.UUID, org.jboss.dna.graph.property.PathFactory)
- */
- @Override
- public ChangedChildren without( UUID childUuid,
- PathFactory pathFactory ) {
- // Remove the object that has the same UUID (regardless of the current SNS index) ...
- ChildNode toBeRemoved = childrenByUuid.get(childUuid);
- if (toBeRemoved == null) {
- return this;
- }
- // Remove the child from this object, then adjust the remaining child node instances that follow it ...
- Name childName = toBeRemoved.getName();
- List<ChildNode> childrenWithSameName = childrenByName.get(childName);
- int snsIndex = toBeRemoved.getSnsIndex();
- if (snsIndex > childrenWithSameName.size()) {
- // The child node (with that SNS index) is no longer here) ...
- return this;
- }
- ListIterator<ChildNode> iter = childrenWithSameName.listIterator(--snsIndex);
- assert iter.hasNext();
- ChildNode willBeRemoved = iter.next();
- assert willBeRemoved == toBeRemoved;
- childrenByUuid.remove(toBeRemoved.getUuid());
- iter.remove(); // removes the item that was last returned from 'next()'
- while (iter.hasNext()) {
- ChildNode next = iter.next();
- ChildNode newNext = next.with(pathFactory.createSegment(childName, ++snsIndex));
- childrenByUuid.put(newNext.getUuid(), newNext);
- iter.set(newNext);
- }
- return this;
- }
-
-}
Deleted: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/ChangedNodeInfo.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/ChangedNodeInfo.java 2009-07-09 16:23:09 UTC (rev 1081)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/ChangedNodeInfo.java 2009-07-09 16:26:04 UTC (rev 1082)
@@ -1,496 +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.
- *
- * 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.jcr.cache;
-
-import java.util.Collection;
-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 net.jcip.annotations.NotThreadSafe;
-import org.jboss.dna.graph.JcrLexicon;
-import org.jboss.dna.graph.Location;
-import org.jboss.dna.graph.property.Name;
-import org.jboss.dna.graph.property.NameFactory;
-import org.jboss.dna.graph.property.Path;
-import org.jboss.dna.graph.property.PathFactory;
-import org.jboss.dna.graph.property.ValueFactories;
-import org.jboss.dna.graph.property.ValueFactory;
-import org.jboss.dna.graph.property.Path.Segment;
-import org.jboss.dna.jcr.DnaIntLexicon;
-import org.jboss.dna.jcr.NodeDefinitionId;
-
-/**
- * The information that describes a node. This is the information that is kept in the cache.
- * <p>
- * Each instance maintains a reference to the original (usually immutable) NodeInfo representation that was probably read from the
- * repository.
- */
-@NotThreadSafe
-public class ChangedNodeInfo implements NodeInfo {
-
- protected static final PropertyInfo DELETED_PROPERTY = null;
-
- /**
- * A reference to the original representation of the node.
- */
- private final NodeInfo original;
-
- /**
- * The new parent for this node if it has been changed, or null if the parent has not be changed.
- */
- private UUID newParent;
-
- /**
- * The updated children, or null if the children have not been changed from the original's.
- */
- private ChangedChildren changedChildren;
-
- /**
- * This map, if it is non-null, contains the changed properties, overriding whatever is in the original. If a property is
- * removed from the original, an entry is added to this map with the name of the removed property and a null PropertyInfo.
- */
- private Map<Name, PropertyInfo> changedProperties;
-
- /**
- * The updated list of mixin node type names. This is merely a cached version of what's already in the
- * {@link JcrLexicon#MIXIN_TYPES "jcr:mixinTypes"} property.
- */
- private List<Name> changedMixinTypeNames;
-
- /**
- * The updated node definition, which may be changed when this node is moved to a different parent (with a different node
- * type)
- */
- private NodeDefinitionId changedDefinitionId;
-
- private List<UUID> peers;
-
- private Set<Name> singleMultiPropertyNames;
-
- /**
- * Create an immutable NodeInfo instance.
- *
- * @param original the original node information, may not be null
- */
- public ChangedNodeInfo( NodeInfo original ) {
- assert original != null;
- this.original = original;
- }
-
- /**
- * Returns the peer nodes for this changed node.
- * <p>
- * Peer nodes are nodes that must be saved with this node (e.g., the other changed node in a
- * {@link javax.jcr.Session#move(String, String)} operation.
- * </p>
- *
- * @return a collection of the UUIDs for any other nodes that must be saved with this node; may be null
- */
- public final Collection<UUID> getPeers() {
- return peers;
- }
-
- /**
- * Adds a peer node to this change.
- * <p>
- * Peer nodes are nodes that must be saved with this node (e.g., the other changed node in a
- * {@link javax.jcr.Session#move(String, String)} operation.
- * </p>
- *
- * @param peerUuid the UUID of the peer node
- */
- public void addPeer( UUID peerUuid ) {
- if (peers == null) {
- peers = new LinkedList<UUID>();
- }
- peers.add(peerUuid);
- }
-
- public boolean setSingleMultiProperty( Name name ) {
- if (singleMultiPropertyNames == null) singleMultiPropertyNames = new HashSet<Name>();
- return singleMultiPropertyNames.add(name);
- }
-
- public boolean removeSingleMultiProperty( Name name ) {
- return singleMultiPropertyNames == null ? false : singleMultiPropertyNames.remove(name);
- }
-
- public Set<Name> getSingleMultiPropertyNames() {
- return singleMultiPropertyNames;
- }
-
- /**
- * Return the original node information. May be null if this is a new node.
- *
- * @return the original node information
- */
- public NodeInfo getOriginal() {
- return original;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.jcr.cache.NodeInfo#getOriginalLocation()
- */
- public Location getOriginalLocation() {
- return original.getOriginalLocation();
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.jcr.cache.NodeInfo#getUuid()
- */
- public UUID getUuid() {
- return original.getUuid();
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.jcr.cache.NodeInfo#getParent()
- */
- public UUID getParent() {
- // Even if this is used for recording changes to the root node (which has no parent),
- // the root node cannot be moved to a different node (and no other node can be moved to
- // the root). Therefore, if this represents the root node, the original's parent UUID will
- // be the correct parent (null), and this representation will not need to have a different
- // (non-null) value.
- if (newParent != null) return newParent;
- return original.getParent();
- }
-
- /**
- * Record that this node has been moved under a new parent. This method does <i>not</i> change the ChildNode references in the
- * old or new parent.
- *
- * @param parent the new parent, or null if the original's parent should be used
- * @return the previous parent (either the original's or the last new parent); may be null
- */
- public UUID setParent( UUID parent ) {
- UUID result = newParent != null ? newParent : original.getParent(); // may still be null
- newParent = parent;
- return result;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.jcr.cache.NodeInfo#getPrimaryTypeName()
- */
- public Name getPrimaryTypeName() {
- return original.getPrimaryTypeName();
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.jcr.cache.NodeInfo#getMixinTypeNames()
- */
- public List<Name> getMixinTypeNames() {
- if (changedMixinTypeNames != null) return changedMixinTypeNames;
- return original.getMixinTypeNames();
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.jcr.cache.NodeInfo#getDefinitionId()
- */
- public NodeDefinitionId getDefinitionId() {
- if (changedDefinitionId != null) return changedDefinitionId;
- return original.getDefinitionId();
- }
-
- /**
- * Set the identifier of the node definition for this node. This should normally be changed by
- * {@link #setProperty(PropertyInfo, ValueFactories) setting} the {@link DnaIntLexicon#NODE_DEFINITON} property. However,
- * since that property is not always allowed, this method provides a way to set it locally (without requiring a property).
- *
- * @param definitionId the new property definition identifier; may not be null
- * @see #setProperty(PropertyInfo, ValueFactories)
- */
- public void setDefinitionId( NodeDefinitionId definitionId ) {
- if (!getDefinitionId().equals(definitionId)) {
- assert definitionId != null;
- changedDefinitionId = definitionId;
- }
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.jcr.cache.NodeInfo#getChildren()
- */
- public Children getChildren() {
- if (changedChildren != null) return changedChildren;
- return original.getChildren();
- }
-
- /**
- * Get the UUIDs for the children for this node that have been removed since the node was last persisted.
- *
- * @return a collection of the UUIDs of the removed children; never null but possibly empty
- */
- public Collection<UUID> getUuidsForRemovedChildren() {
- if (original == null) return Collections.emptySet();
-
- Set<UUID> removedChildren = new HashSet<UUID>();
- for (ChildNode originalChildNode : original.getChildren()) {
- if (!this.changedChildren.childrenByUuid.containsKey(originalChildNode.getUuid())) {
- removedChildren.add(originalChildNode.getUuid());
- }
- }
- return removedChildren;
- }
-
- /**
- * Add a child to the children. This method does nothing if the child is already in the children.
- *
- * @param childName the name of the child that is to be added; may not be null
- * @param childUuid the UUID of the child that is to be added; may not be null
- * @param factory the path factory that should be used to create a {@link Segment} for the new {@link ChildNode} object
- * @return the child node that was just added; never null
- */
- public ChildNode addChild( Name childName,
- UUID childUuid,
- PathFactory factory ) {
- if (changedChildren == null) {
- // We need to capture the original children as a changed contained ...
- changedChildren = new ChangedChildren(original.getChildren());
- }
- return changedChildren.add(childName, childUuid, factory);
- }
-
- /**
- * Add a child to the children. This method does nothing if the child is already in the children.
- *
- * @param childName the name of the child that is to be added; may not be null
- * @param childUuid the UUID of the child that is to be added; may not be null
- * @param beforeChild the segment for the child that the new child should be added before; may not be null
- * @param factory the path factory that should be used to create a {@link Segment} for the new {@link ChildNode} object
- */
- public void addChild( Name childName,
- Path.Segment beforeChild,
- UUID childUuid,
- PathFactory factory ) {
- if (changedChildren == null) {
- // We need to capture the original children as a changed contained ...
- changedChildren = new ChangedChildren(original.getChildren());
- }
- changedChildren = changedChildren.with(childName, beforeChild, childUuid, factory);
- }
-
- /**
- * Remove a child from the children. This method only uses the child's UUID to identify the contained ChildNode instance that
- * should be removed.
- *
- * @param childUUID the UUID of the child that is to be removed; may not be null
- * @param factory the path factory that should be used to create a {@link Segment} for replacement {@link ChildNode} objects
- * for nodes with the same name that and higher same-name-sibiling indexes.
- * @return the child node that was removed, or null if no such child could be removed
- */
- public ChildNode removeChild( UUID childUUID,
- PathFactory factory ) {
- ChildNode deleted = null;
- if (changedChildren == null) {
- // Create the changed children. First check whether there are 0 or 1 child ...
- Children existing = original.getChildren();
- int numExisting = existing.size();
- if (numExisting == 0) {
- // nothing to do, so return the original's children
- return null;
- }
- deleted = existing.getChild(childUUID);
- if (deleted == null) {
- // The requested child doesn't exist in the children, so return ...
- return null;
- }
- if (numExisting == 1) {
- // We're removing the only child in the original ...
- changedChildren = new ChangedChildren(existing.getParentUuid());
- return existing.getChild(childUUID);
- }
- // There is at least one child, so create the new children container ...
- assert existing instanceof InternalChildren;
- InternalChildren internal = (InternalChildren)existing;
- changedChildren = internal.without(childUUID, factory);
- } else {
- deleted = changedChildren.getChild(childUUID);
- changedChildren = changedChildren.without(childUUID, factory);
- }
- return deleted;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.jcr.cache.NodeInfo#hasProperties()
- */
- public boolean hasProperties() {
- if (changedProperties == null) return original.hasProperties();
- int numUnchanged = original.getPropertyCount();
- int numChangedOrDeleted = changedProperties.size();
- if (numUnchanged > numChangedOrDeleted) return true; // more unchanged than could be deleted
- // They could all be changed or deleted, so we need to find one changed property ...
- for (Map.Entry<Name, PropertyInfo> entry : changedProperties.entrySet()) {
- if (entry.getValue() != DELETED_PROPERTY) return true;
- }
- return false; // all properties must have been deleted ...
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.jcr.cache.NodeInfo#getPropertyCount()
- */
- public int getPropertyCount() {
- int numUnchanged = original.getPropertyCount();
- if (changedProperties == null) return numUnchanged;
- return getPropertyNames().size();
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.jcr.cache.NodeInfo#getPropertyNames()
- */
- public Set<Name> getPropertyNames() {
- if (changedProperties != null) {
- Set<Name> result = new HashSet<Name>(original.getPropertyNames());
- for (Map.Entry<Name, PropertyInfo> entry : changedProperties.entrySet()) {
- if (entry.getValue() != DELETED_PROPERTY) {
- result.add(entry.getKey());
- } else {
- result.remove(entry.getKey());
- }
- }
- return result; // don't make unmod wrapper, since we've already made a copy ...
- }
- return original.getPropertyNames();
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.jcr.cache.NodeInfo#getProperty(org.jboss.dna.graph.property.Name)
- */
- public PropertyInfo getProperty( Name name ) {
- if (changedProperties != null && changedProperties.containsKey(name)) {
- return changedProperties.get(name); // either the changed PropertyInfo, or null if property was deleted
- }
- return original.getProperty(name);
- }
-
- public PropertyInfo setProperty( PropertyInfo newProperty,
- ValueFactories factories ) {
- Name name = newProperty.getPropertyName();
- PropertyInfo previous = null;
- if (changedProperties == null) {
- // There were no changes made yet ...
-
- // Create the map of changed properties ...
- changedProperties = new HashMap<Name, PropertyInfo>();
- changedProperties.put(name, newProperty);
-
- // And return the original property (or null if there was none) ...
- previous = original.getProperty(name);
- } else if (changedProperties.containsKey(name)) {
- // The property was already changed, in which case we need to return the changed one ...
- previous = changedProperties.put(name, newProperty);
- } else {
- // Otherwise, the property was not yet changed or deleted ...
- previous = original.getProperty(name);
- changedProperties.put(name, newProperty);
- }
- // If this property was the "jcr:mixinTypes" property, update the cached values ...
- if (name.equals(JcrLexicon.MIXIN_TYPES)) {
- if (changedMixinTypeNames == null) {
- changedMixinTypeNames = new LinkedList<Name>();
- } else {
- changedMixinTypeNames.clear();
- }
- NameFactory nameFactory = factories.getNameFactory();
- for (Object value : newProperty.getProperty()) {
- changedMixinTypeNames.add(nameFactory.create(value));
- }
- } else if (name.equals(DnaIntLexicon.NODE_DEFINITON)) {
- ValueFactory<String> stringFactory = factories.getStringFactory();
- String value = stringFactory.create(newProperty.getProperty().getFirstValue());
- changedDefinitionId = NodeDefinitionId.fromString(value, factories.getNameFactory());
- }
-
- return previous;
- }
-
- public PropertyInfo removeProperty( Name name ) {
- if (changedProperties == null) {
- // Make sure the property was in the original ...
- PropertyInfo existing = original.getProperty(name);
- if (existing == null) {
- // The named property didn't exist in the original, nor was it added and deleted in this object ...
- return null;
- }
-
- // Create the map of changed properties ...
- changedProperties = new HashMap<Name, PropertyInfo>();
- changedProperties.put(name, DELETED_PROPERTY);
- return existing;
- }
- // The property may already have been changed, in which case we need to return the changed one ...
- if (changedProperties.containsKey(name)) {
- PropertyInfo changed = changedProperties.put(name, null);
- // The named property was indeed deleted ...
- return changed;
- }
- // Otherwise, the property was not yet changed or deleted ...
- PropertyInfo changed = original.getProperty(name);
- changedProperties.put(name, null);
- return changed;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.jcr.cache.NodeInfo#isNew()
- */
- public boolean isNew() {
- return false;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.jcr.cache.NodeInfo#isModified()
- */
- public boolean isModified() {
- return true;
- }
-}
Deleted: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/ChildNode.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/ChildNode.java 2009-07-09 16:23:09 UTC (rev 1081)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/ChildNode.java 2009-07-09 16:26:04 UTC (rev 1082)
@@ -1,139 +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.
- *
- * 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.jcr.cache;
-
-import java.util.UUID;
-import net.jcip.annotations.Immutable;
-import org.jboss.dna.graph.property.Name;
-import org.jboss.dna.graph.property.Path;
-
-/**
- * The representation of a child node. This is an immutable representation of a child node within the collection of its siblings
- * as the collection appeared at some point in time. This should be used as a guide to determine how long to hold onto references.
- * <p>
- * For example, adding and removing children may affect the {@link #getSnsIndex() same-name-sibling index} of the children, so
- * these kinds of operations will result in the replacement of old ChildObject instances. Therefore, clients should generally find
- * the ChildNode instances in a {@link Children} container, use the ChildNode objects quickly, then discard their references.
- * </p>
- * <p>
- * There may be times when a client does wish to keep a representation of a ChildNode as it appeared at some moment in time, and
- * so it may want to hold onto references to ChildNode objects for longer durations. This is fine, as long as it is understood
- * that at some point the referenced ChildNode may no longer represent the current state.
- * </p>
- */
-@Immutable
-public final class ChildNode {
-
- private final UUID uuid;
- private final Path.Segment segment;
-
- public ChildNode( UUID uuid,
- Path.Segment segment ) {
- assert uuid != null;
- assert segment != null;
- this.uuid = uuid;
- this.segment = segment;
- }
-
- /**
- * Get the UUID of the node.
- *
- * @return the node's UUID; never null
- */
- public UUID getUuid() {
- return uuid;
- }
-
- /**
- * Get the path segment for this node.
- *
- * @return the path segment; never null
- */
- public Path.Segment getSegment() {
- return segment;
- }
-
- /**
- * Get the name of the node.
- *
- * @return the node's current name; never null
- */
- public Name getName() {
- return segment.getName();
- }
-
- /**
- * Get the same-name-sibling index of the node.
- *
- * @return the node's SNS index; always positive
- */
- public int getSnsIndex() {
- return segment.getIndex();
- }
-
- /**
- * {@inheritDoc}
- *
- * @see java.lang.Object#hashCode()
- */
- @Override
- public int hashCode() {
- return uuid.hashCode();
- }
-
- /**
- * {@inheritDoc}
- *
- * @see java.lang.Object#equals(java.lang.Object)
- */
- @Override
- public boolean equals( Object obj ) {
- if (obj == this) return true;
- if (obj instanceof ChildNode) {
- return this.uuid.equals(((ChildNode)obj).uuid);
- }
- return false;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see java.lang.Object#toString()
- */
- @Override
- public String toString() {
- return uuid.toString() + " ( " + getSegment() + " )";
- }
-
- /**
- * Obtain a new instance that uses the same {@link #getUuid() UUID} but the supplied path segment.
- *
- * @param newSegment the new segment; may not be null
- * @return the new instance; never null
- */
- public ChildNode with( Path.Segment newSegment ) {
- return new ChildNode(uuid, newSegment);
- }
-
-}
Deleted: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/Children.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/Children.java 2009-07-09 16:23:09 UTC (rev 1081)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/Children.java 2009-07-09 16:26:04 UTC (rev 1082)
@@ -1,84 +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.
- *
- * 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.jcr.cache;
-
-import java.util.Iterator;
-import java.util.UUID;
-import org.jboss.dna.graph.property.Name;
-import org.jboss.dna.graph.property.Path;
-
-/**
- * Class that maintains the ordered list of {@link ChildNode} instances yet allows fast access to the children with a specified
- * name.
- */
-public interface Children extends Iterable<ChildNode> {
-
- /**
- * Get the number of children.
- *
- * @return the number of children
- */
- int size();
-
- /**
- * The UUID of the parent node.
- *
- * @return the parent node's UUID
- */
- UUID getParentUuid();
-
- /**
- * Get the child with the given UUID.
- *
- * @param uuid the UUID of the child node
- * @return the child node, or null if there is no child with the supplied UUID
- */
- ChildNode getChild( UUID uuid );
-
- /**
- * Get the child given the path segment.
- *
- * @param segment the path segment for the child, which includes the {@link Path.Segment#getName() name} and
- * {@link Path.Segment#getIndex() one-based same-name-sibling index}; may not be null
- * @return the information for the child node, or null if no such child existed
- */
- ChildNode getChild( Path.Segment segment );
-
- /**
- * Get the same-name-sibling children that all share the supplied name, in order of increasing SNS index.
- *
- * @param name the name for the children; may not be null
- * @return the children with the supplied name; never null
- */
- Iterator<ChildNode> getChildren( Name name );
-
- /**
- * Get the number of same-name-siblings that all share the supplied name.
- *
- * @param name the name for the children; may not be null
- * @return the number of same-name-siblings with the supplied name
- */
- int getCountOfSameNameSiblingsWithName( Name name );
-
-}
Deleted: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/EmptyChildren.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/EmptyChildren.java 2009-07-09 16:23:09 UTC (rev 1081)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/EmptyChildren.java 2009-07-09 16:26:04 UTC (rev 1082)
@@ -1,144 +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.
- *
- * 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.jcr.cache;
-
-import java.util.Iterator;
-import java.util.UUID;
-import net.jcip.annotations.Immutable;
-import org.jboss.dna.common.collection.EmptyIterator;
-import org.jboss.dna.graph.property.Name;
-import org.jboss.dna.graph.property.PathFactory;
-import org.jboss.dna.graph.property.Path.Segment;
-
-/**
- * An immutable implementation of {@link Children}.
- */
-@Immutable
-public final class EmptyChildren implements Children, InternalChildren {
-
- static final Iterator<ChildNode> EMPTY_ITERATOR = new EmptyIterator<ChildNode>();
-
- private final UUID parentUuid;
-
- public EmptyChildren( UUID parentUuid ) {
- this.parentUuid = parentUuid;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.jcr.cache.Children#size()
- */
- public int size() {
- return 0;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see java.lang.Iterable#iterator()
- */
- public Iterator<ChildNode> iterator() {
- return EMPTY_ITERATOR;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.jcr.cache.Children#getParentUuid()
- */
- public UUID getParentUuid() {
- return parentUuid;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.jcr.cache.Children#getChild(java.util.UUID)
- */
- public ChildNode getChild( UUID uuid ) {
- return null;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.jcr.cache.Children#getChild(org.jboss.dna.graph.property.Path.Segment)
- */
- public ChildNode getChild( Segment segment ) {
- return null;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.jcr.cache.Children#getChildren(org.jboss.dna.graph.property.Name)
- */
- public Iterator<ChildNode> getChildren( Name name ) {
- return EMPTY_ITERATOR;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.jcr.cache.Children#getCountOfSameNameSiblingsWithName(org.jboss.dna.graph.property.Name)
- */
- public int getCountOfSameNameSiblingsWithName( Name name ) {
- return 0;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.jcr.cache.InternalChildren#with(org.jboss.dna.graph.property.Name, java.util.UUID,
- * org.jboss.dna.graph.property.PathFactory)
- */
- public ChangedChildren with( Name newChildName,
- UUID newChildUuid,
- PathFactory pathFactory ) {
- ChangedChildren result = new ChangedChildren(this);
- result.add(newChildName, newChildUuid, pathFactory);
- return result;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.jcr.cache.InternalChildren#without(java.util.UUID, org.jboss.dna.graph.property.PathFactory)
- */
- public ChangedChildren without( UUID childUuid,
- PathFactory pathFactory ) {
- return new ChangedChildren(this.parentUuid);
- }
-
- /**
- * {@inheritDoc}
- *
- * @see java.lang.Object#toString()
- */
- @Override
- public String toString() {
- return "";
- }
-}
Deleted: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/ImmutableChildren.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/ImmutableChildren.java 2009-07-09 16:23:09 UTC (rev 1081)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/ImmutableChildren.java 2009-07-09 16:26:04 UTC (rev 1082)
@@ -1,251 +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.
- *
- * 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.jcr.cache;
-
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.UUID;
-import net.jcip.annotations.Immutable;
-import org.jboss.dna.common.collection.ReadOnlyIterator;
-import org.jboss.dna.graph.Location;
-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.Path.Segment;
-import com.google.common.collect.LinkedListMultimap;
-import com.google.common.collect.ListMultimap;
-
-/**
- * An immutable implementation of {@link Children}.
- */
-@Immutable
-public class ImmutableChildren implements Children, InternalChildren {
- protected final UUID parentUuid;
- protected final Map<UUID, ChildNode> childrenByUuid;
- protected final ListMultimap<Name, ChildNode> childrenByName;
-
- public ImmutableChildren( UUID parentUuid,
- Iterable<Location> children ) {
- this(parentUuid);
- for (Location childLocation : children) {
- UUID childUuid = childLocation.getUuid();
- Path.Segment segment = childLocation.getPath().getLastSegment();
- Name name = segment.getName();
- ChildNode child = new ChildNode(childUuid, segment);
- this.childrenByName.put(name, child);
- this.childrenByUuid.put(childUuid, child);
- }
- }
-
- public ImmutableChildren( UUID parentUuid ) {
- this.parentUuid = parentUuid;
- this.childrenByUuid = new HashMap<UUID, ChildNode>();
- this.childrenByName = new LinkedListMultimap<Name, ChildNode>();
- }
-
- protected ImmutableChildren( Children original ) {
- this.parentUuid = original.getParentUuid();
- this.childrenByUuid = new HashMap<UUID, ChildNode>();
- this.childrenByName = new LinkedListMultimap<Name, ChildNode>();
- Iterator<ChildNode> iter = original.iterator();
- while (iter.hasNext()) {
- ChildNode child = iter.next();
- this.childrenByName.put(child.getName(), child);
- this.childrenByUuid.put(child.getUuid(), child);
- }
- }
-
- protected ImmutableChildren( ImmutableChildren original,
- Name additionalChildName,
- Path.Segment beforeChild,
- UUID childUuid,
- PathFactory pathFactory ) {
- assert beforeChild != null;
-
- this.parentUuid = original.getParentUuid();
- this.childrenByUuid = new HashMap<UUID, ChildNode>();
- this.childrenByName = new LinkedListMultimap<Name, ChildNode>();
-
- int snsIndex = 1;
- boolean found = false;
- ChildNode additionalChild = null;
- for (ChildNode child : original.childrenByName.values()) {
- this.childrenByUuid.put(child.getUuid(), child);
- if (beforeChild.equals(child.getSegment())) {
- Path.Segment segment = pathFactory.createSegment(additionalChildName, snsIndex++);
- additionalChild = new ChildNode(childUuid, segment);
- childrenByName.put(child.getName(), additionalChild);
- found = true;
- }
-
- if (found &&(child.getName().equals(additionalChildName))) {
- Path.Segment newSegment = pathFactory.createSegment(additionalChildName, snsIndex++);
- childrenByName.put(child.getName(), child.with(newSegment));
- }
- else {
- childrenByName.put(child.getName(), child);
- }
- }
-
- assert additionalChild != null;
- this.childrenByUuid.put(childUuid, additionalChild);
- }
-
- /**
- * Utility method that adds a child with the supplied name. This method is not exposed publicly, ensuring that this class
- * remains publicly immutable. Subclasses that use this method (in places other than constructors) will no longer be
- * {@link Immutable immutable}.
- *
- * @param additionalChildName
- * @param childUuid
- * @param pathFactory
- * @return the child node that was just added; never null
- */
- protected ChildNode add( Name additionalChildName,
- UUID childUuid,
- PathFactory pathFactory ) {
- ChildNode existing = this.childrenByUuid.get(childUuid);
- if (existing != null) return existing;
-
- List<ChildNode> childrenWithName = this.childrenByName.get(additionalChildName);
- Path.Segment segment = pathFactory.createSegment(additionalChildName, childrenWithName.size() + 1);
- ChildNode additionalChild = new ChildNode(childUuid, segment);
- this.childrenByName.put(additionalChildName, additionalChild);
- this.childrenByUuid.put(childUuid, additionalChild);
- return additionalChild;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.jcr.cache.Children#size()
- */
- public int size() {
- return childrenByName.size();
- }
-
- /**
- * {@inheritDoc}
- *
- * @see java.lang.Iterable#iterator()
- */
- public Iterator<ChildNode> iterator() {
- return new ReadOnlyIterator<ChildNode>(this.childrenByName.values().iterator());
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.jcr.cache.Children#getParentUuid()
- */
- public UUID getParentUuid() {
- return parentUuid;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.jcr.cache.Children#getChild(java.util.UUID)
- */
- public ChildNode getChild( UUID uuid ) {
- return this.childrenByUuid.get(uuid);
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.jcr.cache.Children#getChild(org.jboss.dna.graph.property.Path.Segment)
- */
- public ChildNode getChild( Segment segment ) {
- List<ChildNode> childrenWithName = this.childrenByName.get(segment.getName());
- int snsIndex = segment.getIndex();
- if (childrenWithName.size() < snsIndex) return null;
- return childrenWithName.get(snsIndex - 1);
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.jcr.cache.Children#getChildren(org.jboss.dna.graph.property.Name)
- */
- public Iterator<ChildNode> getChildren( Name name ) {
- return new ReadOnlyIterator<ChildNode>(this.childrenByName.get(name).iterator());
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.jcr.cache.Children#getCountOfSameNameSiblingsWithName(org.jboss.dna.graph.property.Name)
- */
- public int getCountOfSameNameSiblingsWithName( Name name ) {
- return this.childrenByName.get(name).size();
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.jcr.cache.InternalChildren#with(org.jboss.dna.graph.property.Name, java.util.UUID,
- * org.jboss.dna.graph.property.PathFactory)
- */
- public ChangedChildren with( Name newChildName,
- UUID newChildUuid,
- PathFactory pathFactory ) {
- // Create a mutable version ...
- ChangedChildren newChildren = new ChangedChildren(this);
- return newChildren.with(newChildName, newChildUuid, pathFactory);
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.jcr.cache.InternalChildren#without(java.util.UUID, org.jboss.dna.graph.property.PathFactory)
- */
- public ChangedChildren without( UUID childUuid,
- PathFactory pathFactory ) {
- if (this.childrenByUuid.containsKey(childUuid) && this.size() == 1) {
- return new ChangedChildren(this.parentUuid);
- }
- ChangedChildren newChildren = new ChangedChildren(this);
- return newChildren.without(childUuid, pathFactory);
- }
-
- /**
- * {@inheritDoc}
- *
- * @see java.lang.Object#toString()
- */
- @Override
- public String toString() {
- StringBuilder sb = new StringBuilder();
- boolean first = true;
- for (ChildNode child : childrenByName.values()) {
- if (!first) sb.append(", ");
- else first = false;
- sb.append(child.getName()).append('[').append(child.getSnsIndex()).append(']');
- }
- return sb.toString();
- }
-}
Deleted: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/ImmutableNodeInfo.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/ImmutableNodeInfo.java 2009-07-09 16:23:09 UTC (rev 1081)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/ImmutableNodeInfo.java 2009-07-09 16:26:04 UTC (rev 1082)
@@ -1,207 +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.
- *
- * 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.jcr.cache;
-
-import java.util.Collections;
-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.Location;
-import org.jboss.dna.graph.property.Name;
-import org.jboss.dna.jcr.NodeDefinitionId;
-
-/**
- * The information that describes a node. This is the information that is kept in the cache.
- */
-@Immutable
-public class ImmutableNodeInfo implements NodeInfo {
- private final Location originalLocation;
- private final UUID uuid;
- private final UUID parent;
- private final Name primaryTypeName;
- private final NodeDefinitionId definition;
- private final Children children;
- private final Map<Name, PropertyInfo> properties;
- private final List<Name> mixinTypeNames;
-
- /**
- * Create an immutable NodeInfo instance.
- *
- * @param originalLocation the original location
- * @param primaryTypeName the name of the node's primary type
- * @param mixinTypeNames the names of the mixin types for this node, or null if there are none
- * @param definition the definition used when creating the node
- * @param parent the parent
- * @param children the immutable children; may be null if there are no children
- * @param properties the unmodifiable map of properties; may be null if there are no properties
- */
- public ImmutableNodeInfo( Location originalLocation,
- Name primaryTypeName,
- List<Name> mixinTypeNames,
- NodeDefinitionId definition,
- UUID parent,
- Children children,
- Map<Name, PropertyInfo> properties ) {
- this.originalLocation = originalLocation;
- this.primaryTypeName = primaryTypeName;
- this.definition = definition;
- this.parent = parent;
- this.uuid = this.originalLocation.getUuid();
- this.children = children != null ? children : new EmptyChildren(this.uuid);
- this.properties = properties != null ? properties : Collections.<Name, PropertyInfo>emptyMap();
- this.mixinTypeNames = mixinTypeNames != null ? mixinTypeNames : Collections.<Name>emptyList();
- assert this.uuid != null;
- assert this.definition != null;
- assert this.primaryTypeName != null;
- assert this.children != null;
- assert this.mixinTypeNames != null;
- assert this.properties != null;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.jcr.cache.NodeInfo#getOriginalLocation()
- */
- public Location getOriginalLocation() {
- return originalLocation;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.jcr.cache.NodeInfo#getUuid()
- */
- public UUID getUuid() {
- return uuid;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.jcr.cache.NodeInfo#getParent()
- */
- public UUID getParent() {
- return parent;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.jcr.cache.NodeInfo#getPrimaryTypeName()
- */
- public Name getPrimaryTypeName() {
- return primaryTypeName;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.jcr.cache.NodeInfo#getMixinTypeNames()
- */
- public List<Name> getMixinTypeNames() {
- return mixinTypeNames;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.jcr.cache.NodeInfo#getDefinitionId()
- */
- public NodeDefinitionId getDefinitionId() {
- return definition;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.jcr.cache.NodeInfo#getChildren()
- */
- public Children getChildren() {
- return children;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.jcr.cache.NodeInfo#hasProperties()
- */
- public boolean hasProperties() {
- return this.properties.size() != 0;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.jcr.cache.NodeInfo#getPropertyCount()
- */
- public int getPropertyCount() {
- return this.properties.size();
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.jcr.cache.NodeInfo#getPropertyNames()
- */
- public Set<Name> getPropertyNames() {
- return this.properties.keySet();
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.jcr.cache.NodeInfo#getProperty(org.jboss.dna.graph.property.Name)
- */
- public PropertyInfo getProperty( Name name ) {
- return this.properties.get(name);
- }
-
- /**
- * {@inheritDoc}
- *
- * @return {@code false} always as this object represents unmodified nodes only
- * @see org.jboss.dna.jcr.cache.NodeInfo#isNew()
- */
- public boolean isNew() {
- return false;
- }
-
- /**
- * {@inheritDoc}
- *
- * @return {@code false} always as this object represents unmodified nodes only
- * @see org.jboss.dna.jcr.cache.NodeInfo#isModified()
- */
- public boolean isModified() {
- return false;
- }
-
- @Override
- public String toString() {
- return this.uuid + " (" + primaryTypeName + ") {" + properties + "}";
- }
-}
Deleted: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/InternalChildren.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/InternalChildren.java 2009-07-09 16:23:09 UTC (rev 1081)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/InternalChildren.java 2009-07-09 16:26:04 UTC (rev 1082)
@@ -1,57 +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.
- *
- * 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.jcr.cache;
-
-import java.util.UUID;
-import org.jboss.dna.graph.property.Name;
-import org.jboss.dna.graph.property.PathFactory;
-
-/**
- * An internal interface for the {@link Children} implementations. Methods on this interface are used internally and should not be
- * used by components or clients.
- */
-interface InternalChildren extends Children {
-
- /**
- * Create another Children object that is equivalent to this node but with the supplied child added.
- *
- * @param newChildName the name of the new child; may not be null
- * @param newChildUuid the UUID of the new child; may not be null
- * @param pathFactory the factory that can be used to create Path and/or Path.Segment instances.
- * @return the new Children object; never null
- */
- ChangedChildren with( Name newChildName,
- UUID newChildUuid,
- PathFactory pathFactory );
-
- /**
- * Create another Children object that is equivalent to this node but without the supplied child.
- *
- * @param childUuid the UUID of the child to be removed; may not be null
- * @param pathFactory the factory that can be used to create Path and/or Path.Segment instances.
- * @return the new Children object; never null
- */
- ChangedChildren without( UUID childUuid,
- PathFactory pathFactory );
-}
Deleted: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/NewNodeInfo.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/NewNodeInfo.java 2009-07-09 16:23:09 UTC (rev 1081)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/NewNodeInfo.java 2009-07-09 16:26:04 UTC (rev 1082)
@@ -1,79 +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.
- *
- * 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.jcr.cache;
-
-import java.util.Map;
-import java.util.UUID;
-import org.jboss.dna.graph.Location;
-import org.jboss.dna.graph.property.Name;
-import org.jboss.dna.jcr.NodeDefinitionId;
-
-/**
- *
- */
-public class NewNodeInfo extends ChangedNodeInfo {
- /**
- * Create an immutable NodeInfo instance.
- *
- * @param originalLocation the original location
- * @param primaryTypeName the name of the node's primary type
- * @param definition the definition used when creating the node
- * @param parent the parent
- * @param properties the unmodifiable map of properties; may be null if there are no properties
- */
- public NewNodeInfo( Location originalLocation,
- Name primaryTypeName,
- NodeDefinitionId definition,
- UUID parent,
- Map<Name, PropertyInfo> properties ) {
- super(new ImmutableNodeInfo(originalLocation, primaryTypeName, null, definition, parent, null, properties));
- }
-
- /**
- * {@inheritDoc}
- * <p>
- * Always returns true.
- * </p>
- *
- * @see org.jboss.dna.jcr.cache.ChangedNodeInfo#isNew()
- */
- @Override
- public boolean isNew() {
- return true;
- }
-
- /**
- * {@inheritDoc}
- * <p>
- * Always returns false, since a new node is not persisted yet.
- * </p>
- *
- * @see org.jboss.dna.jcr.cache.ChangedNodeInfo#isModified()
- */
- @Override
- public boolean isModified() {
- return false;
- }
-
-}
Deleted: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/NodeInfo.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/NodeInfo.java 2009-07-09 16:23:09 UTC (rev 1081)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/NodeInfo.java 2009-07-09 16:26:04 UTC (rev 1082)
@@ -1,126 +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.
- *
- * 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.jcr.cache;
-
-import java.util.List;
-import java.util.Set;
-import java.util.UUID;
-import org.jboss.dna.graph.Location;
-import org.jboss.dna.graph.property.Name;
-import org.jboss.dna.jcr.NodeDefinitionId;
-
-/**
- * A representation of a node. This is the information that is kept in the cache.
- */
-public interface NodeInfo {
-
- /**
- * @return location
- */
- public Location getOriginalLocation();
-
- /**
- * @return uuid
- */
- public UUID getUuid();
-
- /**
- * @return parent
- */
- public UUID getParent();
-
- /**
- * @return primaryTypeName
- */
- public Name getPrimaryTypeName();
-
- /**
- * Get the names of the mixin types for this node.
- *
- * @return the unmodifiable list of mixin type names; never null but possibly empty
- */
- public List<Name> getMixinTypeNames();
-
- /**
- * @return definition
- */
- public NodeDefinitionId getDefinitionId();
-
- /**
- * Get the children for this node. Generally, clients should not hold onto the returned object but instead should simply use
- * it and discard the reference. This is because implementations are not required to return the same instance with each call
- * (although immutable implementations are expected to always return the same instance).
- *
- * @return the immutable children; never null but possibly empty
- */
- public Children getChildren();
-
- /**
- * Return true of this node has at least one property.
- *
- * @return true if there is at least one property, or false if there are none
- */
- public boolean hasProperties();
-
- /**
- * Return the number of properties on this node.
- *
- * @return the number of properties; never negative
- */
- public int getPropertyCount();
-
- /**
- * Get the names of the properties that are owned by this node.
- *
- * @return the unmodifiable set of property names
- */
- public Set<Name> getPropertyNames();
-
- /**
- * Get this node's property that has the supplied name.
- *
- * @param name the property name; may not be null
- * @return the property information, or null if this node has no property with the supplied name
- */
- public PropertyInfo getProperty( Name name );
-
- /**
- * Indicates whether the node represented by this {@link NodeInfo} is new (i.e., does not yet exist in the persistent
- * repository).
- *
- * @return {@code true} if the node represented by this {@link NodeInfo} has not yet been saved to the persistent repository.
- * @see javax.jcr.Item#isNew()
- */
- public boolean isNew();
-
- /**
- * Indicates whether the node represented by this {@link NodeInfo} is modified (i.e., exists in the persistent repository with
- * different child items).
- *
- * @return {@code true} if the immediate child items of the node represented by this {@link NodeInfo} have been modified since
- * the last time the node was saved to the persistent repository
- * @see javax.jcr.Item#isModified()
- */
- public boolean isModified();
-}
Deleted: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/PropertyInfo.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/PropertyInfo.java 2009-07-09 16:23:09 UTC (rev 1081)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/PropertyInfo.java 2009-07-09 16:26:04 UTC (rev 1082)
@@ -1,198 +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.
- *
- * 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.jcr.cache;
-
-import java.util.UUID;
-import javax.jcr.PropertyType;
-import net.jcip.annotations.Immutable;
-import org.jboss.dna.graph.property.Name;
-import org.jboss.dna.graph.property.Property;
-import org.jboss.dna.jcr.PropertyDefinitionId;
-import org.jboss.dna.jcr.PropertyId;
-
-/**
- * An immutable representation of the name and current value(s) for a property, along with the JCR metadata for the property,
- * including the {@link PropertyInfo#getDefinitionId() property definition} and {@link PropertyInfo#getPropertyType() property
- * type}.
- * <p>
- * This class is immutable, which means that clients should never hold onto an instance. Instead, clients can obtain an instance
- * by using a {@link PropertyId}, quickly use the information in the instance, and then immediately discard their reference. This
- * is because these instances are replaced and discarded whenever anything about the property changes.
- * </p>
- */
-@Immutable
-public class PropertyInfo {
- private final PropertyId propertyId;
- private final PropertyDefinitionId definitionId;
- private final Property dnaProperty;
- private final int propertyType;
- private final boolean multiValued;
- private final boolean isNew;
- private final boolean isModified;
-
- public PropertyInfo( PropertyId propertyId,
- PropertyDefinitionId definitionId,
- int propertyType,
- Property dnaProperty,
- boolean multiValued,
- boolean isNew,
- boolean isModified ) {
- this.propertyId = propertyId;
- this.definitionId = definitionId;
- this.propertyType = propertyType;
- this.dnaProperty = dnaProperty;
- this.multiValued = multiValued;
- this.isNew = isNew;
- this.isModified = isModified;
-
- assert isNew ? !isModified : true;
- assert isModified ? !isNew : true;
- }
-
- /**
- * Get the durable identifier for this property.
- *
- * @return propertyId
- */
- public PropertyId getPropertyId() {
- return propertyId;
- }
-
- /**
- * Get the UUID of the node to which this property belongs.
- *
- * @return the owner node's UUID; never null
- */
- public UUID getNodeUuid() {
- return propertyId.getNodeId();
- }
-
- /**
- * The identifier for the property definition.
- *
- * @return the property definition ID; never null
- */
- public PropertyDefinitionId getDefinitionId() {
- return definitionId;
- }
-
- /**
- * Get the DNA Property, which contains the name and value(s)
- *
- * @return the property; never null
- */
- public Property getProperty() {
- return dnaProperty;
- }
-
- /**
- * Get the property name.
- *
- * @return the property name; never null
- */
- public Name getPropertyName() {
- return dnaProperty.getName();
- }
-
- /**
- * Get the JCR {@link PropertyType} for this property.
- *
- * @return the property type
- */
- public int getPropertyType() {
- return propertyType;
- }
-
- /**
- * @return multiValued
- */
- public boolean isMultiValued() {
- return multiValued;
- }
-
- /**
- * Indicates whether this property/value combination is new (i.e., does not yet exist in the persistent repository).
- *
- * @return {@code true} if the property has not yet been saved to the persistent repository.
- * @see javax.jcr.Item#isNew()
- */
- public boolean isNew() {
- return this.isNew;
- }
-
- /**
- * Indicates whether this property/value combination is modified (i.e., exists in the persistent repository with a different
- * value or values).
- *
- * @return {@code true} if the property has been modified since the last time it was saved to the persistent repository
- * @see javax.jcr.Item#isModified()
- */
- public boolean isModified() {
- return this.isModified;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see java.lang.Object#hashCode()
- */
- @Override
- public int hashCode() {
- return propertyId.hashCode();
- }
-
- /**
- * {@inheritDoc}
- *
- * @see java.lang.Object#equals(java.lang.Object)
- */
- @Override
- public boolean equals( Object obj ) {
- if (obj == this) return true;
- if (obj instanceof PropertyInfo) {
- return propertyId.equals(((PropertyInfo)obj).getPropertyId());
- }
- return false;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see java.lang.Object#toString()
- */
- @Override
- public String toString() {
- StringBuilder sb = new StringBuilder();
- sb.append(propertyId);
- sb.append(" defined by ").append(definitionId);
- sb.append(" of type ").append(PropertyType.nameFromValue(propertyType));
- if (dnaProperty.isSingle()) {
- sb.append(" with value ");
- } else {
- sb.append(" with values ");
- }
- sb.append(dnaProperty.getValuesAsArray());
- return sb.toString();
- }
-}
Modified: trunk/dna-jcr/src/main/resources/org/jboss/dna/jcr/JcrI18n.properties
===================================================================
--- trunk/dna-jcr/src/main/resources/org/jboss/dna/jcr/JcrI18n.properties 2009-07-09 16:23:09 UTC (rev 1081)
+++ trunk/dna-jcr/src/main/resources/org/jboss/dna/jcr/JcrI18n.properties 2009-07-09 16:26:04 UTC (rev 1082)
@@ -69,15 +69,16 @@
childNotFoundUnderNode = The child "{0}" could not be found under "{1}" in workspace "{2}"
errorWhileFindingNodeWithUuid = Error while finding the node with UUID "{0}" in workspace "{1}": {2}
errorWhileFindingNodeWithPath = Error while finding the node "{0}" in workspace "{1}"
-nodeDefinitionCouldNotBeDeterminedForNode = Unable to determine a valid node definition for the node "{0}" in workspace "{1}"
+nodeDefinitionCouldNotBeDeterminedForNode = Unable to determine a valid node definition for the node "{0}" in workspace "{1}" of "{2}"
noSnsDefinitionForNode = A node definition that allows same name siblings could not be found for the node "{0}" in workspace "{1}"
-missingNodeTypeForExistingNode = Missing primary node type "{0}" for node {1} in workspace "{2}"
+missingNodeTypeForExistingNode = Missing primary node type "{0}" for node {1} in workspace "{2}" of "{3}"
unableToCreateNodeWithPrimaryTypeThatDoesNotExist = Unable to create child "{1}" in workspace "{2}" because the node type "{0}" does not exist
unableToCreateNodeWithNoDefaultPrimaryTypeOnChildNodeDefinition = Unable to create child "{2}" in workspace "{3}" because the node definition "{0}" on the "{1}" node type has no default primary type
unableToSaveNodeThatWasCreatedSincePreviousSave = Unable to save node "{0}" in workspace "{1}" because it was created since the last save
unableToSetMultiValuedPropertyUsingSingleValue = Unable to set existing multi-valued property "{0}" on node "{1}" in workspace "{2}" using single-value setter methods
unableToSetSingleValuedPropertyUsingMultipleValues = Unable to set existing single-valued property "{0}" on node "{1}" in workspace "{2}" using multi-value setter methods
-unableToRefreshBranchSinceAtLeastOneNodeMovedToParentOutsideOfBranch = Unable to refresh "{0}" in workspace "{2}" because at least one of its decendants was moved to another node outside of the branch that is not being refreshed
+unableToRefreshBranchBecauseChangesDependOnChangesToNodesOutsideOfBranch = Unable to refresh "{0}" in workspace "{1}" because it contains changes that depend on changes to nodes outside of this branch
+unableToSaveBranchBecauseChangesDependOnChangesToNodesOutsideOfBranch = Unable to save "{0}" in workspace "{1}" because it contains changes that depend on changes to nodes outside of this branch
allPropertyValuesMustHaveSameType = All values of property "{0}" on node "{3}" in workspace "{4}" must all be {2} values (values were: {1})
cannotRemoveNodeFromClone = The node at "{0}" with UUID "{1}" exists in the current workspace but cannot be removed because it is a mandatory child node
Modified: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/AbstractJcrNodeTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/AbstractJcrNodeTest.java 2009-07-09 16:23:09 UTC (rev 1081)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/AbstractJcrNodeTest.java 2009-07-09 16:26:04 UTC (rev 1082)
@@ -4,13 +4,13 @@
* 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.
+ * 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
@@ -24,694 +24,654 @@
package org.jboss.dna.jcr;
import static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.IsNot.not;
import static org.hamcrest.core.IsNull.notNullValue;
+import static org.hamcrest.core.IsNull.nullValue;
+import static org.hamcrest.core.IsSame.sameInstance;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.stub;
-import java.util.UUID;
import javax.jcr.Item;
import javax.jcr.ItemNotFoundException;
import javax.jcr.ItemVisitor;
-import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.PathNotFoundException;
-import javax.jcr.Property;
-import javax.jcr.PropertyType;
import javax.jcr.Repository;
-import javax.jcr.RepositoryException;
import javax.jcr.UnsupportedRepositoryOperationException;
-import javax.jcr.Value;
import javax.jcr.Workspace;
+import javax.jcr.nodetype.NodeType;
import javax.jcr.version.Version;
-import org.jboss.dna.graph.ExecutionContext;
-import org.jboss.dna.graph.property.Name;
-import org.jboss.dna.graph.property.Path;
-import org.jboss.dna.jcr.cache.ChangedChildren;
-import org.jboss.dna.jcr.cache.Children;
-import org.jboss.dna.jcr.cache.EmptyChildren;
-import org.jboss.dna.jcr.cache.NodeInfo;
-import org.jboss.dna.jcr.cache.PropertyInfo;
+import org.jboss.dna.graph.Graph;
+import org.jboss.dna.graph.connector.inmemory.InMemoryRepositorySource;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;
-import org.mockito.MockitoAnnotations;
-import org.mockito.MockitoAnnotations.Mock;
/**
- * @author jverhaeg
+ *
*/
-public class AbstractJcrNodeTest {
+public class AbstractJcrNodeTest extends AbstractJcrTest {
- static class MockAbstractJcrNode extends AbstractJcrNode {
+ private AbstractJcrNode rootNode;
+ private AbstractJcrNode cars;
+ private AbstractJcrNode hybrid;
+ private AbstractJcrNode prius;
+ private AbstractJcrNode highlander;
+ private AbstractJcrNode altima;
- MockAbstractJcrNode( SessionCache cache,
- UUID uuid ) {
- super(cache, uuid);
- }
-
- @Override
- boolean isRoot() {
- return false;
- }
-
- @Override
- public int getDepth() {
- return 0;
- }
-
- public int getIndex() {
- return 0;
- }
-
- public String getName() throws RepositoryException {
- return cache.getPathFor(nodeInfo()).getLastSegment().getString(namespaces());
- }
-
- @Override
- public AbstractJcrNode getParent() throws RepositoryException {
- return cache.findJcrNode(nodeInfo().getParent());
- }
-
- public String getPath() throws RepositoryException {
- return cache.getPathFor(nodeInfo()).getString(namespaces());
- }
-
- public void remove() {
- throw new UnsupportedOperationException();
- }
+ @Override
+ @Before
+ public void beforeEach() throws Exception {
+ super.beforeEach();
+ rootNode = cache.findJcrRootNode();
+ cars = cache.findJcrNode(null, path("/Cars"));
+ hybrid = cache.findJcrNode(null, path("/Cars/Hybrid"));
+ prius = cache.findJcrNode(null, path("/Cars/Hybrid/Toyota Prius"));
+ highlander = cache.findJcrNode(null, path("/Cars/Hybrid/Toyota Highlander"));
+ altima = cache.findJcrNode(null, path("/Cars/Hybrid/Nissan Altima"));
}
- private ExecutionContext context;
- private UUID uuid;
- private AbstractJcrNode node;
- private Children children;
- @Mock
- private SessionCache cache;
- @Mock
- private JcrSession session;
- @Mock
- private JcrNodeTypeManager nodeTypes;
- @Mock
- private NodeInfo info;
+ /*
+ * Visitors
+ */
- @Before
- public void before() throws Exception {
- MockitoAnnotations.initMocks(this);
- context = new ExecutionContext();
- context.getNamespaceRegistry().register("acme", "http://www.example.com");
- uuid = UUID.randomUUID();
- stub(cache.session()).toReturn(session);
- stub(cache.context()).toReturn(context);
- stub(cache.workspaceName()).toReturn("my workspace");
- stub(cache.findNodeInfo(uuid)).toReturn(info);
- stub(cache.getPathFor(info)).toReturn(path("/a/b/c/d"));
- stub(session.nodeTypeManager()).toReturn(nodeTypes);
- node = new MockAbstractJcrNode(cache, uuid);
-
- // Create the children container for the node ...
- children = new EmptyChildren(uuid);
- stub(info.getChildren()).toReturn(children);
+ @Test
+ public void shouldAllowVisitation() throws Exception {
+ ItemVisitor visitor = Mockito.mock(ItemVisitor.class);
+ hybrid.accept(visitor);
+ Mockito.verify(visitor).visit(hybrid);
}
- protected Name name( String name ) {
- return context.getValueFactories().getNameFactory().create(name);
+ @Test( expected = IllegalArgumentException.class )
+ public void shouldNotAllowVisitationIfNoVisitor() throws Exception {
+ hybrid.accept(null);
}
- protected Path relativePath( String relativePath ) {
- return context.getValueFactories().getPathFactory().create(relativePath);
- }
+ /*
+ * Ancestors
+ */
- protected Path path( String absolutePath ) {
- return context.getValueFactories().getPathFactory().create(absolutePath);
+ @Test( expected = ItemNotFoundException.class )
+ public void shouldNotAllowNegativeAncestorDepth() throws Exception {
+ hybrid.getAncestor(-1);
}
- protected Value stringValueFor( Object value ) {
- return new JcrValue(context.getValueFactories(), cache, PropertyType.STRING, value);
+ @Test
+ public void shouldReturnRootForAncestorOfDepthZero() throws Exception {
+ assertThat(hybrid.getAncestor(0), is((Item)rootNode));
}
- protected void addChild( Name childName,
- UUID childUuid ) {
- if (children instanceof EmptyChildren) {
- children = ((EmptyChildren)children).with(childName, childUuid, context.getValueFactories().getPathFactory());
- } else if (children instanceof ChangedChildren) {
- children = ((ChangedChildren)children).with(childName, childUuid, context.getValueFactories().getPathFactory());
- }
- stub(info.getChildren()).toReturn(children);
+ @Test
+ public void shouldReturnAncestorAtLevelOneForAncestorOfDepthOne() throws Exception {
+ assertThat(hybrid.getAncestor(1), is((Item)cars));
}
@Test
- public void shouldAllowVisitation() throws Exception {
- ItemVisitor visitor = Mockito.mock(ItemVisitor.class);
- node.accept(visitor);
- Mockito.verify(visitor).visit(node);
+ public void shouldReturnSelfForAncestorOfDepthEqualToDepthOfNode() throws Exception {
+ assertThat(hybrid.getAncestor(hybrid.getDepth()), is((Item)hybrid));
}
- @Test( expected = IllegalArgumentException.class )
- public void shouldNotAllowVisitationIfNoVisitor() throws Exception {
- node.accept(null);
- }
-
@Test( expected = ItemNotFoundException.class )
- public void shouldNotAllowNegativeAncestorDepth() throws Exception {
- node.getAncestor(-1);
+ public void shouldFailToReturnAncestorWhenDepthIsGreaterThanNodeDepth() throws Exception {
+ hybrid.getAncestor(hybrid.getDepth() + 1);
}
@Test
- public void shouldProvideAncestor() throws Exception {
- assertThat(node.getAncestor(0), is((Item)node));
+ public void shouldIndicateIsNode() {
+ assertThat(prius.isNode(), is(true));
}
+ /*
+ * Property-related methods
+ */
+
@Test
public void shouldReturnPropertyFromGetPropertyWithValidName() throws Exception {
- PropertyId propertyId = new PropertyId(uuid, name("test"));
- AbstractJcrProperty property = mock(AbstractJcrProperty.class);
- stub(cache.findJcrProperty(propertyId)).toReturn(property);
- assertThat(node.getProperty("test"), is((Property)property));
+ javax.jcr.Property property = prius.getProperty("vehix:model");
+ assertThat(property, is(notNullValue()));
+ assertThat(property.getName(), is("vehix:model"));
+ assertThat(property.getString(), is("Prius"));
}
@Test
public void shouldReturnPropertyFromGetPropertyWithValidRelativePath() throws Exception {
- PropertyId propertyId = new PropertyId(uuid, name("test"));
- AbstractJcrProperty property = mock(AbstractJcrProperty.class);
- stub(cache.findJcrProperty(propertyId)).toReturn(property);
- assertThat(node.getProperty("test"), is((Property)property));
+ javax.jcr.Property property = prius.getProperty("./vehix:model");
+ assertThat(property, is(notNullValue()));
+ assertThat(property.getName(), is("vehix:model"));
+ assertThat(property.getString(), is("Prius"));
}
@Test( expected = PathNotFoundException.class )
public void shouldFailToReturnPropertyFromGetPropertyWithNameOfPropertyThatDoesNotExist() throws Exception {
- node.getProperty("nonExistantProperty");
+ prius.getProperty("nonExistantProperty");
}
@Test( expected = IllegalArgumentException.class )
public void shouldFailToReturnPropertyFromGetPropertyWithAbsolutePath() throws Exception {
- node.getProperty("/test");
+ prius.getProperty("/test");
}
@Test( expected = PathNotFoundException.class )
public void shouldFailToReturnPropertyFromGetPropertyWithRelativePathToNonExistantItem() throws Exception {
- node.getProperty("../bogus/path");
+ prius.getProperty("../bogus/path");
}
@Test
public void shouldReturnPropertyFromGetPropertyWithRelativePathToPropertyOnOtherNode() throws Exception {
- AbstractJcrProperty property = mock(AbstractJcrProperty.class);
- stub(cache.findJcrItem(uuid, relativePath("../good/path"))).toReturn(property);
- assertThat(node.getProperty("../good/path"), is((Property)property));
+ javax.jcr.Property property = prius.getProperty("../Nissan Altima/vehix:model");
+ assertThat(property, is(notNullValue()));
+ assertThat(property.getName(), is("vehix:model"));
+ assertThat(property.getString(), is("Altima"));
}
@Test( expected = PathNotFoundException.class )
public void shouldReturnPropertyFromGetPropertyWithRelativePathToOtherNode() throws Exception {
- AbstractJcrNode otherNode = mock(AbstractJcrNode.class);
- stub(cache.findJcrItem(uuid, relativePath("../good/path"))).toReturn(otherNode);
- node.getProperty("../good/path");
+ prius.getProperty("../Nissan Altima");
}
- /*
- * More comprehensive tests of addMixin, removeMixin, and canAddMixin require additional setup
- * and are in MixinTest
- */
+ @Test( expected = IllegalArgumentException.class )
+ public void shouldNotAllowGetPropertyWithNullPath() throws Exception {
+ prius.getProperty((String)null);
+ }
- @Test( expected = UnsupportedOperationException.class )
- public void shoudNotAllowCancelMerge() throws Exception {
- node.cancelMerge(null);
+ @Test( expected = IllegalArgumentException.class )
+ public void shouldNotAllowGetPropertyWithEmptyPath() throws Exception {
+ prius.getProperty("");
}
- @Test( expected = UnsupportedRepositoryOperationException.class )
- public void shoudNotAllowCheckin() throws Exception {
- node.checkin();
+ @Test
+ public void shouldReturnTrueFromHasPropertyWithValidName() throws Exception {
+ assertThat(prius.hasProperty("vehix:model"), is(true));
}
- @Test( expected = UnsupportedRepositoryOperationException.class )
- public void shoudNotAllowCheckout() throws Exception {
- node.checkout();
+ @Test
+ public void shouldReturnTrueFromHasPropertyWithValidRelativePath() throws Exception {
+ assertThat(prius.hasProperty("./vehix:model"), is(true));
}
- @Test( expected = UnsupportedOperationException.class )
- public void shoudNotAllowDoneMerge() throws Exception {
- node.doneMerge(null);
+ @Test
+ public void shouldReturnFalseFromHasPropertyWithNameOfPropertyThatDoesNotExist() throws Exception {
+ assertThat(prius.hasProperty("non-existant"), is(false));
}
- @Test( expected = UnsupportedRepositoryOperationException.class )
- public void shoudNotAllowGetBaseVersion() throws Exception {
- node.getBaseVersion();
+ @Test
+ public void shouldReturnFalseFromHasPropertyWithRelativePathToNonExistantItem() throws Exception {
+ assertThat(prius.hasProperty("../Nissan Altima/non-existant"), is(false));
}
- @Test( expected = UnsupportedRepositoryOperationException.class )
- public void shoudNotAllowGetLock() throws Exception {
- node.getLock();
+ @Test
+ public void shouldReturnTrueFromHasPropertyWithRelativePathToPropertyOnOtherNode() throws Exception {
+ assertThat(prius.hasProperty("../Nissan Altima/vehix:model"), is(true));
}
+ @Test
+ public void shouldReturnFalseFromHasPropertyWithRelativePathToOtherNode() throws Exception {
+ assertThat(prius.hasProperty("../Nissan Altima"), is(false));
+ }
+
@Test( expected = IllegalArgumentException.class )
- public void shouldNotAllowGetPropertyWithNullPath() throws Exception {
- node.getProperty((String)null);
+ public void shouldNotAllowHasPropertyWithAbsolutePath() throws Exception {
+ prius.hasProperty("/Cars/Hybrid/Toyota Prius/vehix:model");
}
@Test( expected = IllegalArgumentException.class )
- public void shouldNotAllowGetPropertyWithEmptyPath() throws Exception {
- node.getProperty("");
+ public void shouldNotAllowHasPropertyWithNullPath() throws Exception {
+ prius.hasProperty((String)null);
}
+ @Test( expected = IllegalArgumentException.class )
+ public void shouldNotAllowHasPropertyWithEmptyPath() throws Exception {
+ prius.hasProperty("");
+ }
+
@Test
+ public void shouldReturnFalseFromHasPropertyIfPathIsParentPath() throws Exception {
+ assertThat(prius.hasProperty(".."), is(false));
+ }
+
+ @Test
+ public void shouldReturnFalseFromHasPropertyIfPathIsSelfPath() throws Exception {
+ assertThat(prius.hasProperty("."), is(false));
+ }
+
+ @Test
+ public void shouldReturnTrueFromHasPropertiesIfNodeHasAtLeastOneProperty() throws Exception {
+ assertThat(prius.hasProperties(), is(true));
+ }
+
+ @Test
+ public void shouldReturnFalseFromHasPropertiesIfNodeHasNoProperties() throws Exception {
+ // can't really test this, since all nodes have at least one property ...
+ // assertThat(child.hasProperties(), is(false));
+ }
+
+ /*
+ * getNode() and related methods
+ */
+
+ @Test
public void shouldReturnChildNodeFromGetNodeWithValidName() throws Exception {
- AbstractJcrNode child = mock(AbstractJcrNode.class);
- UUID childUuid = UUID.randomUUID();
- addChild(name("child"), childUuid);
- stub(cache.findJcrNode(childUuid)).toReturn(child);
- assertThat(node.getNode("child"), is((Node)child));
+ assertThat(hybrid.getNode("Toyota Prius"), is((javax.jcr.Node)prius));
+ assertThat(hybrid.getNode("Toyota Prius"), is(sameInstance((javax.jcr.Node)prius)));
}
@Test
public void shouldReturnNonChildNodeFromGetNodeWithValidRelativePath() throws Exception {
- AbstractJcrNode otherNode = mock(AbstractJcrNode.class);
- stub(cache.findJcrItem(uuid, path("../other/node"))).toReturn(otherNode);
- assertThat(node.getNode("../other/node"), is((Node)otherNode));
+ assertThat(altima.getNode("../Toyota Prius"), is((javax.jcr.Node)prius));
+ assertThat(altima.getNode("../Toyota Prius"), is(sameInstance((javax.jcr.Node)prius)));
}
@Test( expected = PathNotFoundException.class )
public void shouldFailToReturnNodeFromGetNodeWithValidRelativePathToProperty() throws Exception {
- AbstractJcrProperty property = mock(AbstractJcrProperty.class);
- stub(cache.findJcrItem(uuid, path("../other/node"))).toReturn(property);
- node.getNode("../other/node");
+ altima.getNode("../Toyota Prius/vehix:model");
}
@Test( expected = PathNotFoundException.class )
public void shouldFailToReturnNodeFromGetNodeWithValidRelativePathToNoNodeOrProperty() throws Exception {
- node.getNode("../other/node");
+ altima.getNode("../../nonExistant");
}
@Test
public void shouldReturnSelfFromGetNodeWithRelativePathContainingOnlySelfReference() throws Exception {
- assertThat(node.getNode("."), is((Node)node));
+ assertThat(hybrid.getNode("."), is((javax.jcr.Node)hybrid));
+ assertThat(hybrid.getNode("."), is(sameInstance((javax.jcr.Node)hybrid)));
}
@Test
+ public void shouldReturnSelfFromGetNodeWithRelativePathResolvingToSelf() throws Exception {
+ assertThat(hybrid.getNode("Toyota Prius/.."), is((javax.jcr.Node)hybrid));
+ assertThat(hybrid.getNode("Toyota Prius/.."), is(sameInstance((javax.jcr.Node)hybrid)));
+ }
+
+ @Test
public void shouldReturnParentFromGetNodeWithRelativePathContainingOnlyParentReference() throws Exception {
- AbstractJcrNode parent = mock(AbstractJcrNode.class);
- UUID parentUuid = UUID.randomUUID();
- stub(info.getParent()).toReturn(parentUuid);
- stub(cache.findJcrNode(parentUuid)).toReturn(parent);
- assertThat(node.getNode(".."), is((Node)parent));
+ assertThat(prius.getNode("../.."), is((javax.jcr.Node)cars));
+ assertThat(prius.getNode("../.."), is(sameInstance((javax.jcr.Node)cars)));
}
@Test( expected = PathNotFoundException.class )
public void shouldFailToReturnChildNodeFromGetNodeWithNameOfChildThatDoesNotExist() throws Exception {
- node.getNode("something");
+ altima.getNode("nonExistant");
}
@Test( expected = IllegalArgumentException.class )
public void shouldNotAllowGetNodeWithNoPath() throws Exception {
- node.getNode(null);
+ prius.getNode(null);
}
@Test
public void shouldProvideNodeIterator() throws Exception {
- AbstractJcrNode child = mock(AbstractJcrNode.class);
- UUID childUuid = UUID.randomUUID();
- addChild(name("child"), childUuid);
- stub(cache.findJcrNode(childUuid)).toReturn(child);
- NodeIterator iter = node.getNodes();
+ NodeIterator iter = hybrid.getNodes();
assertThat(iter, notNullValue());
- assertThat(iter.getSize(), is(1L));
- assertThat(iter.next(), is((Object)child));
+ assertThat(iter.getSize(), is(3L));
+ assertThat(iter.next(), is((Object)prius));
+ assertThat(iter.next(), is((Object)highlander));
+ assertThat(iter.next(), is((Object)altima));
+ assertThat(iter.hasNext(), is(false));
}
@Test
- public void shoudReturnItemFromGetPrimaryItemIfItExists() throws Exception {
- // Define the node type ...
- Name primaryTypeName = name("thePrimaryType");
- JcrNodeType primaryType = mock(JcrNodeType.class);
- stub(nodeTypes.getNodeType(primaryTypeName)).toReturn(primaryType);
- stub(primaryType.getPrimaryItemName()).toReturn("thePrimaryItemName");
- // Define the node info to use this primary type ...
- stub(info.getPrimaryTypeName()).toReturn(primaryTypeName);
- // Now make an item with the appropriate name ...
- AbstractJcrNode child = mock(AbstractJcrNode.class);
- stub(cache.findJcrItem(uuid, path("thePrimaryItemName"))).toReturn(child);
- // Now call the method ...
- assertThat(node.getPrimaryItem(), is((Item)child));
+ public void shouldReturnTrueFromHasNodeWithValidName() throws Exception {
+ assertThat(hybrid.hasNode("Toyota Prius"), is(true));
}
- @Test( expected = ItemNotFoundException.class )
- public void shoudFailToReturnItemFromGetPrimaryItemIfPrimaryTypeDoesNotHavePrimaryItemName() throws Exception {
- // Define the node type ...
- Name primaryTypeName = name("thePrimaryType");
- JcrNodeType primaryType = mock(JcrNodeType.class);
- stub(nodeTypes.getNodeType(primaryTypeName)).toReturn(primaryType);
- stub(primaryType.getPrimaryItemName()).toReturn(null);
- // Define the node info to use this primary type ...
- stub(info.getPrimaryTypeName()).toReturn(primaryTypeName);
- // Now call the method ...
- node.getPrimaryItem();
+ @Test
+ public void shouldReturnTrueFromHasNodeWithValidRelativePath() throws Exception {
+ assertThat(altima.hasNode("../Toyota Prius"), is(true));
}
- @Test( expected = ItemNotFoundException.class )
- public void shoudFailToReturnItemFromGetPrimaryItemIfThePrimaryTypeAsInvalidPrimaryItemName() throws Exception {
- // Define the node type ...
- Name primaryTypeName = name("thePrimaryType");
- JcrNodeType primaryType = mock(JcrNodeType.class);
- stub(nodeTypes.getNodeType(primaryTypeName)).toReturn(primaryType);
- stub(primaryType.getPrimaryItemName()).toReturn("/this/is/not/valid");
- // Define the node info to use this primary type ...
- stub(info.getPrimaryTypeName()).toReturn(primaryTypeName);
- // Now call the method ...
- node.getPrimaryItem();
+ @Test
+ public void shouldReturnFalseFromHasNodeWithValidRelativePathToProperty() throws Exception {
+ assertThat(altima.hasNode("../Toyota Prius/vehix:model"), is(false));
}
- @Test( expected = ItemNotFoundException.class )
- public void shoudFailToReturnItemFromGetPrimaryItemIfTheNodeHasNoItemMatchingThatSpecifiedByThePrimaryType() throws Exception {
- // Define the node type ...
- Name primaryTypeName = name("thePrimaryType");
- JcrNodeType primaryType = mock(JcrNodeType.class);
- stub(nodeTypes.getNodeType(primaryTypeName)).toReturn(primaryType);
- stub(primaryType.getPrimaryItemName()).toReturn("thePrimaryItemName");
- // Define the node info to use this primary type ...
- stub(info.getPrimaryTypeName()).toReturn(primaryTypeName);
- // Now call the method ...
- stub(cache.findJcrItem(uuid, path("thePrimaryItemName"))).toThrow(new ItemNotFoundException());
- node.getPrimaryItem();
+ @Test
+ public void shouldReturnFalseFromHasNodeWithWithValidRelativePathToNoNodeOrProperty() throws Exception {
+ assertThat(altima.hasNode("../../nonExistant"), is(false));
+ assertThat(altima.hasNode("../nonExistant"), is(false));
+ assertThat(altima.hasNode("nonExistant"), is(false));
}
- // @Test
- // public void shouldReturnEmptyIteratorFromGetReferencesWhenThereAreNoProperties() throws Exception {
- // // Set up two properties (one containing references, the other not) ...
- // List<AbstractJcrProperty> props = Arrays.asList(new AbstractJcrProperty[] {});
- // stub(cache.findJcrPropertiesFor(uuid)).toReturn(props);
- // // Now call the method ...
- // PropertyIterator iter = node.getReferences();
- // assertThat(iter.getSize(), is(0L));
- // assertThat(iter.hasNext(), is(false));
- // }
- //
- // @Test
- // public void shouldReturnEmptyIteratorFromGetReferencesWhenThereAreNoReferenceProperties() throws Exception {
- // // Set up two properties (one containing references, the other not) ...
- // AbstractJcrProperty propertyA = mock(AbstractJcrProperty.class);
- // AbstractJcrProperty propertyB = mock(AbstractJcrProperty.class);
- // List<AbstractJcrProperty> props = Arrays.asList(new AbstractJcrProperty[] {propertyA, propertyB});
- // stub(cache.findJcrPropertiesFor(uuid)).toReturn(props);
- // stub(propertyA.getType()).toReturn(PropertyType.LONG);
- // stub(propertyB.getType()).toReturn(PropertyType.BOOLEAN);
- // // Now call the method ...
- // PropertyIterator iter = node.getReferences();
- // assertThat(iter.getSize(), is(0L));
- // assertThat(iter.hasNext(), is(false));
- // }
- //
- // @Test
- // public void shouldReturnIteratorFromGetReferencesWhenThereIsAtLeastOneReferenceProperty() throws Exception {
- // // Set up two properties (one containing references, the other not) ...
- // AbstractJcrProperty propertyA = mock(AbstractJcrProperty.class);
- // AbstractJcrProperty propertyB = mock(AbstractJcrProperty.class);
- // List<AbstractJcrProperty> props = Arrays.asList(new AbstractJcrProperty[] {propertyA, propertyB});
- // stub(cache.findJcrPropertiesFor(uuid)).toReturn(props);
- // stub(propertyA.getType()).toReturn(PropertyType.LONG);
- // stub(propertyB.getType()).toReturn(PropertyType.REFERENCE);
- // // Now call the method ...
- // PropertyIterator iter = node.getReferences();
- // assertThat(iter.getSize(), is(1L));
- // assertThat(iter.next(), is(sameInstance((Object)propertyB)));
- // assertThat(iter.hasNext(), is(false));
- // }
+ @Test
+ public void shouldReturnTrueFromHasNodeWithRelativePathContainingOnlySelfReference() throws Exception {
+ assertThat(hybrid.hasNode("."), is(true));
+ }
@Test
- public void shouldProvideSession() throws Exception {
- assertThat((JcrSession)node.getSession(), is(session));
+ public void shouldReturnTrueFromHasNodeWithRelativePathResolvingToSelf() throws Exception {
+ assertThat(hybrid.hasNode("Toyota Prius/.."), is(true));
}
- @Test( expected = UnsupportedRepositoryOperationException.class )
- public void shouldNotAllowGetVersionHistory() throws Exception {
- node.getVersionHistory();
+ @Test
+ public void shouldReturnTrueFromHasNodeWithRelativePathContainingOnlyParentReference() throws Exception {
+ assertThat(prius.hasNode("../.."), is(true));
}
- @Test( expected = IllegalArgumentException.class )
- public void shouldNotAllowNullPathInHasNode() throws Exception {
- node.hasNode((String)null);
+ @Test
+ public void shouldReturnFalseFromHasNodeWithNameOfChildThatDoesNotExist() throws Exception {
+ assertThat(altima.hasNode("nonExistant"), is(false));
}
@Test( expected = IllegalArgumentException.class )
- public void shouldNotAllowEmptyPathInHasNode() throws Exception {
- node.hasNode("");
+ public void shouldNotAllowHasNodeWithNoPath() throws Exception {
+ prius.hasNode(null);
}
@Test( expected = IllegalArgumentException.class )
public void shouldNotAbsolutePathInHasNode() throws Exception {
- node.hasNode("/a/b/c");
+ cars.hasNode("/a/b/c");
}
@Test
- public void shouldReturnTrueFromHasNodeWithSelfReference() throws Exception {
- assertThat(node.hasNode("."), is(true));
+ public void shouldReturnTrueFromHasNodesIfThereIsAtLeastOneChild() throws Exception {
+ assertThat(hybrid.hasNodes(), is(true));
}
@Test
- public void shouldReturnTrueFromHasNodeWithParentReferenceIfNotRootNode() throws Exception {
- assertThat(node.hasNode(".."), is(!node.isRoot()));
+ public void shouldReturnFalseFromHasNodesIfThereAreNoChildren() throws Exception {
+ assertThat(prius.hasNodes(), is(false));
}
- @Test
- public void shouldReturnTrueFromHasNodeIfRelativePathIdentifiesExistingNode() throws Exception {
- AbstractJcrNode otherNode = mock(AbstractJcrNode.class);
- stub(cache.findJcrNode(uuid, path("../other/node"))).toReturn(otherNode);
- assertThat(node.hasNode("../other/node"), is(true));
+ /*
+ * More comprehensive tests of addMixin, removeMixin, and canAddMixin require additional setup
+ * and are in MixinTest
+ */
+
+ @Test( expected = UnsupportedOperationException.class )
+ public void shouldNotAllowCancelMerge() throws Exception {
+ hybrid.cancelMerge(null);
}
- @Test
- public void shouldReturnTrueFromHasNodeIfChildWithNameExists() throws Exception {
- addChild(name("child"), UUID.randomUUID());
- assertThat(node.hasNode("child[1]"), is(true));
- assertThat(node.hasNode("child[2]"), is(false));
- addChild(name("child"), UUID.randomUUID());
- assertThat(node.hasNode("child[2]"), is(true));
- assertThat(node.hasNode("child[3]"), is(false));
+ @Test( expected = UnsupportedRepositoryOperationException.class )
+ public void shouldNotAllowCheckin() throws Exception {
+ hybrid.checkin();
}
+ @Test( expected = UnsupportedRepositoryOperationException.class )
+ public void shouldNotAllowCheckout() throws Exception {
+ hybrid.checkout();
+ }
+
+ @Test( expected = UnsupportedOperationException.class )
+ public void shouldNotAllowDoneMerge() throws Exception {
+ hybrid.doneMerge(null);
+ }
+
+ @Test( expected = UnsupportedRepositoryOperationException.class )
+ public void shouldNotAllowGetBaseVersion() throws Exception {
+ hybrid.getBaseVersion();
+ }
+
+ @Test( expected = UnsupportedRepositoryOperationException.class )
+ public void shouldNotAllowGetLock() throws Exception {
+ hybrid.getLock();
+ }
+
@Test
- public void shouldReturnFalseFromHasNodeWithNameOfChildThatDoesNotExist() throws Exception {
- assertThat(node.hasNode("something"), is(false));
+ public void shouldNotAllowHoldsLock() throws Exception {
+ assertThat(hybrid.holdsLock(), is(false));
}
@Test
- public void shouldReturnFalseFromHasNodesIfThereAreNoChildren() throws Exception {
- assertThat(node.hasNodes(), is(false));
+ public void shouldNotAllowIsCheckedOut() throws Exception {
+ assertThat(hybrid.isCheckedOut(), is(false));
}
@Test
- public void shouldReturnTrueFromHasNodesIfThereIsAtLeastOneChild() throws Exception {
- addChild(name("child"), UUID.randomUUID());
- assertThat(node.hasNodes(), is(true));
+ public void shouldNotAllowIsLocked() throws Exception {
+ assertThat(hybrid.isLocked(), is(false));
}
- @Test( expected = IllegalArgumentException.class )
- public void shouldNotAllowNullPathInHasProperty() throws Exception {
- node.hasProperty((String)null);
+ @Test( expected = UnsupportedRepositoryOperationException.class )
+ public void shouldNotAllowLock() throws Exception {
+ hybrid.lock(false, false);
}
- @Test( expected = IllegalArgumentException.class )
- public void shouldNotAllowEmptyPathInHasProperty() throws Exception {
- node.hasProperty("");
+ @Test( expected = UnsupportedOperationException.class )
+ public void shouldNotAllowMerge() throws Exception {
+ hybrid.merge(null, false);
}
- @Test( expected = IllegalArgumentException.class )
- public void shouldNotAbsolutePathInHasProperty() throws Exception {
- node.hasProperty("/a/b/c");
+ @Test( expected = NullPointerException.class )
+ public void shouldNotAllowOrderBeforeWithNullArgs() throws Exception {
+ hybrid.orderBefore(null, null);
}
- @Test
- public void shouldReturnTrueFromHasPropertyIfPathIsRelativePathToOtherNodeWithNamedProperty() throws Exception {
- AbstractJcrProperty property = mock(AbstractJcrProperty.class);
- stub(cache.findJcrItem(uuid, relativePath("../good/path"))).toReturn(property);
- assertThat(node.hasProperty("../good/path"), is(true));
+ @Test( expected = UnsupportedRepositoryOperationException.class )
+ public void shouldNotAllowRestoreVersionName() throws Exception {
+ hybrid.restore((String)null, false);
}
- @Test
- public void shouldReturnFalseFromHasPropertyIfPathIsRelativePathToOtherNodeWithoutNamedProperty() throws Exception {
- stub(cache.findJcrItem(uuid, relativePath("../good/path"))).toThrow(new PathNotFoundException());
- assertThat(node.hasProperty("../good/path"), is(false));
+ @Test( expected = UnsupportedRepositoryOperationException.class )
+ public void shouldNotAllowRestoreVersion() throws Exception {
+ hybrid.restore((Version)null, false);
}
- @Test
- public void shouldReturnFalseFromHasPropertyIfPathIsParentPath() throws Exception {
- assertThat(node.hasProperty(".."), is(false));
+ @Test( expected = UnsupportedRepositoryOperationException.class )
+ public void shouldNotAllowRestoreVersionAtPath() throws Exception {
+ hybrid.restore(null, null, false);
}
- @Test
- public void shouldReturnFalseFromHasPropertyIfPathIsSelfPath() throws Exception {
- assertThat(node.hasProperty("."), is(false));
+ @Test( expected = UnsupportedRepositoryOperationException.class )
+ public void shouldNotAllowRestoreByLabel() throws Exception {
+ hybrid.restoreByLabel(null, false);
}
- @Test
- public void shouldReturnTrueFromHasPropertyIfPathIsNameAndNodeHasProperty() throws Exception {
- PropertyInfo propertyInfo = mock(PropertyInfo.class);
- stub(cache.findPropertyInfo(new PropertyId(uuid, name("prop")))).toReturn(propertyInfo);
- assertThat(node.hasProperty("prop"), is(true));
+ @Test( expected = UnsupportedRepositoryOperationException.class )
+ public void shouldNotAllowUnlock() throws Exception {
+ hybrid.unlock();
}
+ /*
+ * Primary-type and -item methods
+ */
+
@Test
- public void shouldReturnFalseFromHasPropertyIfPathIsNameAndNodeDoesNotHaveProperty() throws Exception {
- stub(cache.findPropertyInfo(new PropertyId(uuid, name("prop")))).toReturn(null);
- assertThat(node.hasProperty("prop"), is(false));
+ public void shouldReturnItemFromGetPrimaryNodeType() throws Exception {
+ NodeType carType = nodeTypes.getNodeType("vehix:car");
+ assertThat(carType, is(notNullValue()));
+ assertThat(prius.getPrimaryNodeType(), is(carType));
}
@Test
- public void shouldReturnTrueFromHasPropertiesIfNodeHasAtLeastOneProperty() throws Exception {
- stub(info.hasProperties()).toReturn(true);
- assertThat(node.hasProperties(), is(true));
+ public void shouldReturnItemFromGetPrimaryItemIfItExists() throws Exception {
+ NodeType carType = nodeTypes.getNodeType("vehix:car");
+ assertThat(carType, is(notNullValue()));
+ assertThat(carType.getPrimaryItemName(), is("vehix:model"));
+ assertThat(prius.getPrimaryItem(), is(sameInstance((Item)prius.getProperty("vehix:model"))));
}
- @Test
- public void shouldReturnFalseFromHasPropertiesIfNodeHasNoProperties() throws Exception {
- stub(info.hasProperties()).toReturn(false);
- assertThat(node.hasProperties(), is(false));
+ @Test( expected = ItemNotFoundException.class )
+ public void shouldFailToReturnItemFromGetPrimaryItemIfPrimaryTypeDoesNotHavePrimaryItemName() throws Exception {
+ // Get nt:unstructured and verify it has no primary item name ...
+ NodeType ntUnstructured = nodeTypes.getNodeType("nt:unstructured");
+ assertThat(ntUnstructured, is(notNullValue()));
+ assertThat(ntUnstructured.getPrimaryItemName(), is(nullValue()));
+
+ // Now check using a node that has the "nt:unstructured" primary type ...
+ cars.getPrimaryItem();
}
- @Test
- public void shouldNotAllowHoldsLock() throws Exception {
- assertThat(node.holdsLock(), is(false));
+ @Test( expected = ItemNotFoundException.class )
+ public void shouldFailToReturnItemFromGetPrimaryItemIfTheNodeHasNoItemMatchingThatSpecifiedByThePrimaryType()
+ throws Exception {
+ // Find the "vehix:car" type ...
+ NodeType carType = nodeTypes.getNodeType("vehix:car");
+ assertThat(carType, is(notNullValue()));
+ assertThat(carType.getPrimaryItemName(), is("vehix:model"));
+ assertThat(prius.getPrimaryItem(), is(sameInstance((Item)prius.getProperty("vehix:model"))));
+
+ // Now remove the "vehix:model" property so there is no such item ...
+ prius.getProperty("vehix:model").remove();
+ prius.getPrimaryItem();
}
+ /*
+ * Miscellaneous methods
+ */
+
@Test
- public void shouldNotAllowIsCheckedOut() throws Exception {
- assertThat(node.isCheckedOut(), is(false));
+ public void shouldProvideSession() throws Exception {
+ assertThat((JcrSession)prius.getSession(), is(jcrSession));
}
- @Test
- public void shouldNotAllowIsLocked() throws Exception {
- assertThat(node.isLocked(), is(false));
+ @Test( expected = UnsupportedRepositoryOperationException.class )
+ public void shouldNotAllowGetVersionHistory() throws Exception {
+ cars.getVersionHistory();
}
- @Test
- public void shouldIndicateIsNode() {
- assertThat(node.isNode(), is(true));
+ /*
+ * Same-ness
+ */
+
+ @Test( expected = IllegalArgumentException.class )
+ public void shouldNotAllowIsSameWithNoItem() throws Exception {
+ hybrid.isSame(null);
}
@Test
public void shouldReturnFalseFromIsSameIfTheRepositoryInstanceIsDifferent() throws Exception {
- Workspace workspace1 = mock(Workspace.class);
- Repository repository1 = mock(Repository.class);
- stub(session.getWorkspace()).toReturn(workspace1);
- stub(session.getRepository()).toReturn(repository1);
- stub(workspace1.getName()).toReturn("workspace1");
+ // Set up the store ...
+ InMemoryRepositorySource source2 = new InMemoryRepositorySource();
+ source2.setName("store");
+ Graph store2 = Graph.create(source2, context);
+ store2.importXmlFrom(AbstractJcrTest.class.getClassLoader().getResourceAsStream("cars.xml")).into("/");
+ JcrSession jcrSession2 = mock(JcrSession.class);
+ stub(jcrSession2.nodeTypeManager()).toReturn(nodeTypes);
+ SessionCache cache2 = new SessionCache(jcrSession2, store2.getCurrentWorkspaceName(), context, nodeTypes, store2);
Workspace workspace2 = mock(Workspace.class);
- JcrSession session2 = Mockito.mock(JcrSession.class);
Repository repository2 = mock(Repository.class);
- SessionCache cache2 = mock(SessionCache.class);
- stub(session2.getWorkspace()).toReturn(workspace2);
- stub(session2.getRepository()).toReturn(repository2);
+ stub(jcrSession2.getWorkspace()).toReturn(workspace2);
+ stub(jcrSession2.getRepository()).toReturn(repository2);
stub(workspace2.getName()).toReturn("workspace1");
- stub(cache2.session()).toReturn(session2);
- UUID uuid2 = uuid;
- Node node2 = new MockAbstractJcrNode(cache2, uuid2);
- assertThat(node.isSame(node2), is(false));
+ // Use the same id and location ...
+ javax.jcr.Node prius2 = cache2.findJcrNode(null, path("/Cars/Hybrid/Toyota Prius"));
+ assertThat(prius2.isSame(prius), is(false));
}
@Test
public void shouldReturnFalseFromIsSameIfTheWorkspaceNameIsDifferent() throws Exception {
- Workspace workspace1 = mock(Workspace.class);
- Repository repository1 = mock(Repository.class);
- stub(session.getWorkspace()).toReturn(workspace1);
- stub(session.getRepository()).toReturn(repository1);
- stub(workspace1.getName()).toReturn("workspace1");
+ // Set up the store ...
+ InMemoryRepositorySource source2 = new InMemoryRepositorySource();
+ source2.setName("store");
+ Graph store2 = Graph.create(source2, context);
+ store2.importXmlFrom(AbstractJcrTest.class.getClassLoader().getResourceAsStream("cars.xml")).into("/");
+ JcrSession jcrSession2 = mock(JcrSession.class);
+ stub(jcrSession2.nodeTypeManager()).toReturn(nodeTypes);
+ SessionCache cache2 = new SessionCache(jcrSession2, store2.getCurrentWorkspaceName(), context, nodeTypes, store2);
Workspace workspace2 = mock(Workspace.class);
- JcrSession session2 = Mockito.mock(JcrSession.class);
- SessionCache cache2 = mock(SessionCache.class);
- stub(session2.getWorkspace()).toReturn(workspace2);
- stub(session2.getRepository()).toReturn(repository1);
+ Repository repository2 = mock(Repository.class);
+ stub(jcrSession2.getWorkspace()).toReturn(workspace2);
+ stub(jcrSession2.getRepository()).toReturn(repository2);
stub(workspace2.getName()).toReturn("workspace2");
- stub(cache2.session()).toReturn(session2);
- UUID uuid2 = uuid;
- Node node2 = new MockAbstractJcrNode(cache2, uuid2);
- assertThat(node.isSame(node2), is(false));
+ // Use the same id and location; use 'Toyota Prius'
+ // since the UUID is defined in 'cars.xml' and therefore will be the same
+ javax.jcr.Node prius2 = cache2.findJcrNode(null, path("/Cars/Hybrid/Toyota Prius"));
+ prius2.addMixin("mix:referenceable");
+ prius.addMixin("mix:referenceable");
+ String priusUuid2 = prius2.getUUID();
+ String priusUuid = prius.getUUID();
+ assertThat(priusUuid, is(priusUuid2));
+ assertThat(prius2.isSame(prius), is(false));
}
@Test
public void shouldReturnFalseFromIsSameIfTheNodeUuidIsDifferent() throws Exception {
- Workspace workspace1 = mock(Workspace.class);
- Repository repository1 = mock(Repository.class);
- stub(session.getWorkspace()).toReturn(workspace1);
- stub(session.getRepository()).toReturn(repository1);
- stub(workspace1.getName()).toReturn("workspace1");
+ // Set up the store ...
+ InMemoryRepositorySource source2 = new InMemoryRepositorySource();
+ source2.setName("store");
+ Graph store2 = Graph.create(source2, context);
+ store2.importXmlFrom(AbstractJcrTest.class.getClassLoader().getResourceAsStream("cars.xml")).into("/");
+ JcrSession jcrSession2 = mock(JcrSession.class);
+ stub(jcrSession2.nodeTypeManager()).toReturn(nodeTypes);
+ SessionCache cache2 = new SessionCache(jcrSession2, store2.getCurrentWorkspaceName(), context, nodeTypes, store2);
Workspace workspace2 = mock(Workspace.class);
- JcrSession session2 = Mockito.mock(JcrSession.class);
- SessionCache cache2 = mock(SessionCache.class);
- stub(session2.getWorkspace()).toReturn(workspace2);
- stub(session2.getRepository()).toReturn(repository1);
+ Repository repository2 = mock(Repository.class);
+ stub(jcrSession2.getWorkspace()).toReturn(workspace2);
+ stub(jcrSession2.getRepository()).toReturn(repository2);
stub(workspace2.getName()).toReturn("workspace1");
- stub(cache2.session()).toReturn(session2);
- UUID uuid2 = UUID.randomUUID();
- Node node2 = new MockAbstractJcrNode(cache2, uuid2);
- assertThat(node.isSame(node2), is(false));
+ // Use the same id and location; use 'Nissan Altima'
+ // since the UUIDs will be different (cars.xml doesn't define on this node) ...
+ javax.jcr.Node altima2 = cache2.findJcrNode(null, path("/Cars/Hybrid/Nissan Altima"));
+ altima2.addMixin("mix:referenceable");
+ altima.addMixin("mix:referenceable");
+ String altimaUuid = altima.getUUID();
+ String altimaUuid2 = altima2.getUUID();
+ assertThat(altimaUuid, is(not(altimaUuid2)));
+ assertThat(altima2.isSame(altima), is(false));
}
@Test
public void shouldReturnTrueFromIsSameIfTheNodeUuidAndWorkspaceNameAndRepositoryInstanceAreSame() throws Exception {
- Workspace workspace1 = mock(Workspace.class);
- Repository repository1 = mock(Repository.class);
- stub(session.getWorkspace()).toReturn(workspace1);
- stub(session.getRepository()).toReturn(repository1);
- stub(workspace1.getName()).toReturn("workspace1");
+ // Set up the store ...
+ InMemoryRepositorySource source2 = new InMemoryRepositorySource();
+ source2.setName("store");
+ Graph store2 = Graph.create(source2, context);
+ store2.importXmlFrom(AbstractJcrTest.class.getClassLoader().getResourceAsStream("cars.xml")).into("/");
+ JcrSession jcrSession2 = mock(JcrSession.class);
+ stub(jcrSession2.nodeTypeManager()).toReturn(nodeTypes);
+ SessionCache cache2 = new SessionCache(jcrSession2, store2.getCurrentWorkspaceName(), context, nodeTypes, store2);
Workspace workspace2 = mock(Workspace.class);
- JcrSession session2 = Mockito.mock(JcrSession.class);
- SessionCache cache2 = mock(SessionCache.class);
- stub(session2.getWorkspace()).toReturn(workspace2);
- stub(session2.getRepository()).toReturn(repository1);
+ stub(jcrSession2.getWorkspace()).toReturn(workspace2);
+ stub(jcrSession2.getRepository()).toReturn(repository);
stub(workspace2.getName()).toReturn("workspace1");
- stub(cache2.session()).toReturn(session2);
- UUID uuid2 = uuid;
- Node node2 = new MockAbstractJcrNode(cache2, uuid2);
- assertThat(node.isSame(node2), is(true));
+ // Use the same id and location ...
+ javax.jcr.Node prius2 = cache2.findJcrNode(null, path("/Cars/Hybrid/Toyota Prius"));
+ prius2.addMixin("mix:referenceable");
+ prius.addMixin("mix:referenceable");
+ String priusUuid = prius.getUUID();
+ String priusUuid2 = prius2.getUUID();
+ assertThat(priusUuid, is(priusUuid2));
+ assertThat(prius2.isSame(prius), is(true));
}
- @Test( expected = IllegalArgumentException.class )
- public void shouldNotAllowIsSameWithNoItem() throws Exception {
- node.isSame(null);
+ @Test
+ public void shouldAlwaysHaveCorrespondenceIdForRootNodeThatContainsSelfPath() throws Exception {
+ CorrespondenceId id = rootNode.getCorrespondenceId();
+ assertThat(id.getReferenceableId(), is(rootNode.getUUID()));
+ assertThat(id.getRelativePath().size(), is(1));
+ assertThat(id.getRelativePath().getLastSegment().isSelfReference(), is(true));
}
- @Test( expected = UnsupportedRepositoryOperationException.class )
- public void shouldNotAllowLock() throws Exception {
- node.lock(false, false);
- }
+ @Test
+ public void shouldAlwaysHaveCorrespondenceId() throws Exception {
+ assertThat(cars.isReferenceable(), is(false));
+ CorrespondenceId id = cars.getCorrespondenceId();
+ assertThat(id.getReferenceableId(), is(rootNode.getUUID()));
+ assertThat(id.getRelativePath().size(), is(1));
+ assertThat(id.getRelativePath(), is(path("Cars")));
- @Test( expected = UnsupportedOperationException.class )
- public void shouldNotAllowMerge() throws Exception {
- node.merge(null, false);
- }
+ assertThat(hybrid.isReferenceable(), is(false));
+ id = hybrid.getCorrespondenceId();
+ assertThat(id.getReferenceableId(), is(rootNode.getUUID()));
+ assertThat(id.getRelativePath().size(), is(2));
+ assertThat(id.getRelativePath(), is(path("Cars/Hybrid")));
- @Test( expected = NullPointerException.class )
- public void shouldNotAllowOrderBeforeWithNullArgs() throws Exception {
- node.orderBefore(null, null);
+ altima.addMixin("mix:referenceable");
+ assertThat(altima.isReferenceable(), is(true));
+ id = altima.getCorrespondenceId();
+ assertThat(id.getReferenceableId(), is(altima.getUUID()));
+ assertThat(id.getRelativePath().size(), is(1));
+ assertThat(id.getRelativePath(), is(path(".")));
}
- @Test( expected = UnsupportedRepositoryOperationException.class )
- public void shouldNotAllowRestoreVersionName() throws Exception {
- node.restore((String)null, false);
+ @Test
+ public void shouldAddNodeWhenIntermediateNodesDoExist() throws Exception {
+ javax.jcr.Node newNode = rootNode.addNode("Cars/Hybrid/CreateThis", "nt:unstructured");
+ assertThat(newNode.getName(), is("CreateThis"));
+ assertThat(newNode.getParent(), is(sameInstance((javax.jcr.Node)hybrid)));
}
- @Test( expected = UnsupportedRepositoryOperationException.class )
- public void shouldNotAllowRestoreVersion() throws Exception {
- node.restore((Version)null, false);
+ @Test( expected = PathNotFoundException.class )
+ public void shouldFailToAddNodeWhenIntermediateNodesDoNotExist() throws Exception {
+ rootNode.addNode("Cars/nonExistant/CreateThis", "nt:unstructured");
}
-
- @Test( expected = UnsupportedRepositoryOperationException.class )
- public void shouldNotAllowRestoreVersionAtPath() throws Exception {
- node.restore(null, null, false);
- }
-
- @Test( expected = UnsupportedRepositoryOperationException.class )
- public void shouldNotAllowRestoreByLabel() throws Exception {
- node.restoreByLabel(null, false);
- }
-
- @Test( expected = UnsupportedRepositoryOperationException.class )
- public void shouldNotAllowUnlock() throws Exception {
- node.unlock();
- }
-
}
Modified: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/AbstractJcrPropertyTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/AbstractJcrPropertyTest.java 2009-07-09 16:23:09 UTC (rev 1081)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/AbstractJcrPropertyTest.java 2009-07-09 16:26:04 UTC (rev 1082)
@@ -4,13 +4,13 @@
* 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.
+ * 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
@@ -24,463 +24,237 @@
package org.jboss.dna.jcr;
import static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.IsNot.not;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.stub;
-import java.io.InputStream;
-import java.util.Calendar;
-import java.util.UUID;
import javax.jcr.Item;
import javax.jcr.ItemNotFoundException;
import javax.jcr.ItemVisitor;
import javax.jcr.Node;
-import javax.jcr.Property;
import javax.jcr.Repository;
import javax.jcr.Session;
-import javax.jcr.Value;
import javax.jcr.Workspace;
-import org.jboss.dna.graph.ExecutionContext;
-import org.jboss.dna.graph.property.Name;
-import org.jboss.dna.graph.property.Path;
-import org.jboss.dna.jcr.cache.NodeInfo;
-import org.jboss.dna.jcr.cache.PropertyInfo;
+import org.jboss.dna.graph.Graph;
+import org.jboss.dna.graph.connector.inmemory.InMemoryRepositorySource;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;
-import org.mockito.MockitoAnnotations;
-import org.mockito.MockitoAnnotations.Mock;
/**
- * @author jverhaeg
+ *
*/
-public class AbstractJcrPropertyTest {
+public class AbstractJcrPropertyTest extends AbstractJcrTest {
- private PropertyId propertyId;
- private PropertyInfo info;
- private ExecutionContext executionContext;
- private JcrNode node;
- private AbstractJcrProperty prop;
- @Mock
- private JcrSession session;
- @Mock
- private SessionCache cache;
+ protected AbstractJcrNode rootNode;
+ protected AbstractJcrNode cars;
+ protected AbstractJcrNode prius;
+ protected AbstractJcrNode altima;
+ protected AbstractJcrProperty altimaModel;
+ @Override
@Before
- public void before() throws Exception {
- MockitoAnnotations.initMocks(this);
- executionContext = new ExecutionContext();
- stub(session.getExecutionContext()).toReturn(executionContext);
-
- UUID uuid = UUID.randomUUID();
- node = new JcrNode(cache, uuid);
- propertyId = new PropertyId(uuid, JcrLexicon.MIMETYPE);
- prop = new MockAbstractJcrProperty(cache, propertyId);
-
- info = mock(PropertyInfo.class);
- stub(info.getPropertyId()).toReturn(propertyId);
- stub(info.getPropertyName()).toReturn(propertyId.getPropertyName());
-
- stub(cache.session()).toReturn(session);
- stub(cache.context()).toReturn(executionContext);
- stub(cache.findJcrProperty(propertyId)).toReturn(prop);
- stub(cache.findPropertyInfo(propertyId)).toReturn(info);
- stub(cache.getPathFor(info)).toReturn(path("/a/b/c/jcr:mimeType"));
- stub(cache.getPathFor(propertyId)).toReturn(path("/a/b/c/jcr:mimeType"));
- stub(cache.getPathFor(uuid)).toReturn(path("/a/b/c"));
-
- NodeInfo nodeInfo = mock(NodeInfo.class);
- stub(cache.findJcrNode(uuid)).toReturn(node);
- stub(cache.findNodeInfo(uuid)).toReturn(nodeInfo);
- stub(cache.getPathFor(uuid)).toReturn(path("/a/b/c"));
- stub(cache.getPathFor(nodeInfo)).toReturn(path("/a/b/c"));
+ public void beforeEach() throws Exception {
+ super.beforeEach();
+ rootNode = cache.findJcrRootNode();
+ cars = cache.findJcrNode(null, path("/Cars"));
+ prius = cache.findJcrNode(null, path("/Cars/Hybrid/Toyota Prius"));
+ altima = cache.findJcrNode(null, path("/Cars/Hybrid/Nissan Altima"));
+ altimaModel = cache.findJcrProperty(altima.nodeId, altima.path(), Vehicles.Lexicon.MODEL);
}
- protected Name name( String name ) {
- return executionContext.getValueFactories().getNameFactory().create(name);
- }
-
- protected Path path( String path ) {
- return executionContext.getValueFactories().getPathFactory().create(path);
- }
-
@Test
public void shouldAllowVisitation() throws Exception {
ItemVisitor visitor = Mockito.mock(ItemVisitor.class);
- prop.accept(visitor);
- Mockito.verify(visitor).visit(prop);
+ altimaModel.accept(visitor);
+ Mockito.verify(visitor).visit(altimaModel);
}
@Test( expected = IllegalArgumentException.class )
public void shouldNotAllowVisitationIfNoVisitor() throws Exception {
- prop.accept(null);
+ altimaModel.accept(null);
}
@Test( expected = ItemNotFoundException.class )
public void shouldNotAllowNegativeAncestorDepth() throws Exception {
- stub(node.getAncestor(-2)).toThrow(new IllegalArgumentException());
- prop.getAncestor(-1);
+ altimaModel.getAncestor(-1);
}
@Test
- public void shouldProvideAncestor() throws Exception {
- assertThat(prop.getAncestor(prop.getDepth()), is((Item)prop));
- assertThat(prop.getAncestor(prop.getDepth() - 1), is((Item)node));
+ public void shouldReturnRootForAncestorOfDepthZero() throws Exception {
+ assertThat(altimaModel.getAncestor(0), is((Item)rootNode));
}
+ @Test
+ public void shouldReturnAncestorAtLevelOneForAncestorOfDepthOne() throws Exception {
+ assertThat(altimaModel.getAncestor(1), is((Item)cars));
+ }
+
+ @Test
+ public void shouldReturnSelfForAncestorOfDepthEqualToDepthOfNode() throws Exception {
+ assertThat(altimaModel.getAncestor(altimaModel.getDepth()), is((Item)altimaModel));
+ assertThat(altimaModel.getAncestor(altimaModel.getDepth() - 1), is((Item)altima));
+ }
+
@Test( expected = ItemNotFoundException.class )
- public void shouldNotAllowAncestorDepthGreaterThanPropertyDepth() throws Exception {
- prop.getAncestor(prop.getDepth() + 1);
+ public void shouldFailToReturnAncestorWhenDepthIsGreaterThanNodeDepth() throws Exception {
+ altimaModel.getAncestor(40);
}
@Test
- public void shouldProvideDepth() throws Exception {
- assertThat(prop.getDepth(), is(4));
+ public void shouldIndicateIsNotNode() {
+ assertThat(altimaModel.isNode(), is(false));
}
@Test
public void shouldProvideExecutionContext() throws Exception {
- assertThat(prop.context(), is(executionContext));
+ assertThat(altimaModel.context(), is(context));
}
@Test
public void shouldProvideName() throws Exception {
- assertThat(prop.getName(), is("jcr:mimeType"));
+ assertThat(altimaModel.getName(), is("vehix:model"));
}
@Test
public void shouldProvideParent() throws Exception {
- assertThat(prop.getParent(), is((Node)node));
+ assertThat(altimaModel.getParent(), is((Node)altima));
}
@Test
public void shouldProvidePath() throws Exception {
- assertThat(prop.getPath(), is("/a/b/c/jcr:mimeType"));
+ assertThat(altimaModel.getPath(), is(altima.getPath() + "/vehix:model"));
}
@Test
public void shouldProvideSession() throws Exception {
- assertThat(prop.getSession(), is((Session)session));
+ assertThat(altimaModel.getSession(), is((Session)jcrSession));
}
@Test
- public void shouldIndicateIsNotANode() {
- assertThat(prop.isNode(), is(false));
- }
+ public void shouldReturnFalseFromIsSameIfTheRepositoryInstanceIsDifferent() throws Exception {
+ // Set up the store ...
+ InMemoryRepositorySource source2 = new InMemoryRepositorySource();
+ source2.setName("store");
+ Graph store2 = Graph.create(source2, context);
+ store2.importXmlFrom(AbstractJcrTest.class.getClassLoader().getResourceAsStream("cars.xml")).into("/");
+ JcrSession jcrSession2 = mock(JcrSession.class);
+ stub(jcrSession2.nodeTypeManager()).toReturn(nodeTypes);
+ SessionCache cache2 = new SessionCache(jcrSession2, store2.getCurrentWorkspaceName(), context, nodeTypes, store2);
- @Test
- public void shouldIndicateSameAsPropertyWithSameNodeAndSamePropertyName() throws Exception {
- Repository repository = mock(Repository.class);
- Workspace workspace = mock(Workspace.class);
Workspace workspace2 = mock(Workspace.class);
- stub(workspace.getName()).toReturn("workspace");
- stub(workspace2.getName()).toReturn("workspace");
- JcrSession session2 = mock(JcrSession.class);
- SessionCache cache2 = mock(SessionCache.class);
- stub(session2.getRepository()).toReturn(repository);
- stub(session.getRepository()).toReturn(repository);
- stub(session2.getWorkspace()).toReturn(workspace2);
- stub(session.getWorkspace()).toReturn(workspace);
- stub(cache2.session()).toReturn(session2);
- stub(cache2.context()).toReturn(executionContext);
+ Repository repository2 = mock(Repository.class);
+ stub(jcrSession2.getWorkspace()).toReturn(workspace2);
+ stub(jcrSession2.getRepository()).toReturn(repository2);
+ stub(workspace2.getName()).toReturn("workspace1");
- // Make the other node have the same UUID ...
- UUID uuid = node.internalUuid();
- NodeInfo nodeInfo = mock(NodeInfo.class);
- PropertyInfo propertyInfo = mock(PropertyInfo.class);
- AbstractJcrNode otherNode = new JcrNode(cache2, uuid);
- stub(propertyInfo.getPropertyId()).toReturn(propertyId);
- stub(propertyInfo.getPropertyName()).toReturn(propertyId.getPropertyName());
- stub(cache2.findJcrNode(uuid)).toReturn(otherNode);
- stub(cache2.findNodeInfo(uuid)).toReturn(nodeInfo);
- stub(cache2.getPathFor(uuid)).toReturn(path("/a/b/c"));
- stub(cache2.getPathFor(nodeInfo)).toReturn(path("/a/b/c"));
- stub(cache2.findPropertyInfo(propertyId)).toReturn(info);
+ // Use the same id and location ...
+ javax.jcr.Node prius2 = cache2.findJcrNode(null, path("/Cars/Hybrid/Toyota Prius"));
+ assertThat(prius2.isSame(prius), is(false));
- assertThat(node.isSame(otherNode), is(true));
-
- Property prop = new MockAbstractJcrProperty(cache, propertyId);
- Property otherProp = new MockAbstractJcrProperty(cache2, propertyId);
- assertThat(prop.isSame(otherProp), is(true));
+ // Check the properties ...
+ javax.jcr.Property model = prius.getProperty("vehix:model");
+ javax.jcr.Property model2 = prius2.getProperty("vehix:model");
+ assertThat(model.isSame(model2), is(false));
}
@Test
- public void shouldIndicateDifferentThanNodeWithDifferentParent() throws Exception {
- Repository repository = mock(Repository.class);
- Workspace workspace = mock(Workspace.class);
+ public void shouldReturnFalseFromIsSameIfTheWorkspaceNameIsDifferent() throws Exception {
+ // Set up the store ...
+ InMemoryRepositorySource source2 = new InMemoryRepositorySource();
+ source2.setName("store");
+ Graph store2 = Graph.create(source2, context);
+ store2.importXmlFrom(AbstractJcrTest.class.getClassLoader().getResourceAsStream("cars.xml")).into("/");
+ JcrSession jcrSession2 = mock(JcrSession.class);
+ stub(jcrSession2.nodeTypeManager()).toReturn(nodeTypes);
+ SessionCache cache2 = new SessionCache(jcrSession2, store2.getCurrentWorkspaceName(), context, nodeTypes, store2);
+
Workspace workspace2 = mock(Workspace.class);
- stub(workspace.getName()).toReturn("workspace");
- stub(workspace2.getName()).toReturn("workspace");
- JcrSession session2 = mock(JcrSession.class);
- SessionCache cache2 = mock(SessionCache.class);
- stub(session2.getRepository()).toReturn(repository);
- stub(session.getRepository()).toReturn(repository);
- stub(session2.getWorkspace()).toReturn(workspace2);
- stub(session.getWorkspace()).toReturn(workspace);
- stub(cache2.session()).toReturn(session2);
- stub(cache2.context()).toReturn(executionContext);
+ Repository repository2 = mock(Repository.class);
+ stub(jcrSession2.getWorkspace()).toReturn(workspace2);
+ stub(jcrSession2.getRepository()).toReturn(repository2);
+ stub(workspace2.getName()).toReturn("workspace2");
- // Make the other node have a different UUID ...
- UUID uuid = UUID.randomUUID();
- PropertyId propertyId2 = new PropertyId(uuid, JcrLexicon.MIXIN_TYPES);
- NodeInfo nodeInfo = mock(NodeInfo.class);
- PropertyInfo propertyInfo = mock(PropertyInfo.class);
- AbstractJcrNode otherNode = new JcrNode(cache2, uuid);
- stub(propertyInfo.getPropertyId()).toReturn(propertyId2);
- stub(propertyInfo.getPropertyName()).toReturn(propertyId2.getPropertyName());
- stub(cache2.findJcrNode(uuid)).toReturn(otherNode);
- stub(cache2.findNodeInfo(uuid)).toReturn(nodeInfo);
- stub(cache2.getPathFor(uuid)).toReturn(path("/a/b/c"));
- stub(cache2.getPathFor(nodeInfo)).toReturn(path("/a/b/c"));
+ // Use the same id and location; use 'Toyota Prius'
+ // since the UUID is defined in 'cars.xml' and therefore will be the same
+ javax.jcr.Node prius2 = cache2.findJcrNode(null, path("/Cars/Hybrid/Toyota Prius"));
+ prius2.addMixin("mix:referenceable");
+ prius.addMixin("mix:referenceable");
+ String priusUuid2 = prius2.getUUID();
+ String priusUuid = prius.getUUID();
+ assertThat(priusUuid, is(priusUuid2));
+ assertThat(prius2.isSame(prius), is(false));
- assertThat(node.isSame(otherNode), is(false));
-
- Property prop = new MockAbstractJcrProperty(cache, propertyId);
- Property otherProp = new MockAbstractJcrProperty(cache2, propertyId2);
- assertThat(prop.isSame(otherProp), is(false));
+ // Check the properties ...
+ javax.jcr.Property model = prius.getProperty("vehix:model");
+ javax.jcr.Property model2 = prius2.getProperty("vehix:model");
+ assertThat(model.isSame(model2), is(false));
}
@Test
- public void shouldIndicateDifferentThanPropertyWithSameNodeWithDifferentPropertyName() throws Exception {
- Repository repository = mock(Repository.class);
- Workspace workspace = mock(Workspace.class);
+ public void shouldReturnFalseFromIsSameIfTheNodeUuidIsDifferent() throws Exception {
+ // Set up the store ...
+ InMemoryRepositorySource source2 = new InMemoryRepositorySource();
+ source2.setName("store");
+ Graph store2 = Graph.create(source2, context);
+ store2.importXmlFrom(AbstractJcrTest.class.getClassLoader().getResourceAsStream("cars.xml")).into("/");
+ JcrSession jcrSession2 = mock(JcrSession.class);
+ stub(jcrSession2.nodeTypeManager()).toReturn(nodeTypes);
+ SessionCache cache2 = new SessionCache(jcrSession2, store2.getCurrentWorkspaceName(), context, nodeTypes, store2);
+
Workspace workspace2 = mock(Workspace.class);
- stub(workspace.getName()).toReturn("workspace");
- stub(workspace2.getName()).toReturn("workspace");
- JcrSession session2 = mock(JcrSession.class);
- SessionCache cache2 = mock(SessionCache.class);
- stub(session2.getRepository()).toReturn(repository);
- stub(session.getRepository()).toReturn(repository);
- stub(session2.getWorkspace()).toReturn(workspace2);
- stub(session.getWorkspace()).toReturn(workspace);
- stub(cache2.session()).toReturn(session2);
- stub(cache2.context()).toReturn(executionContext);
+ Repository repository2 = mock(Repository.class);
+ stub(jcrSession2.getWorkspace()).toReturn(workspace2);
+ stub(jcrSession2.getRepository()).toReturn(repository2);
+ stub(workspace2.getName()).toReturn("workspace1");
- // Make the other node have the same UUID ...
- UUID uuid = node.internalUuid();
- NodeInfo nodeInfo = mock(NodeInfo.class);
- PropertyInfo propertyInfo = mock(PropertyInfo.class);
- PropertyId propertyId2 = new PropertyId(uuid, JcrLexicon.NAME);
- AbstractJcrNode otherNode = new JcrNode(cache2, uuid);
- stub(propertyInfo.getPropertyId()).toReturn(propertyId2);
- stub(propertyInfo.getPropertyName()).toReturn(propertyId2.getPropertyName());
- stub(cache2.findJcrNode(uuid)).toReturn(otherNode);
- stub(cache2.findNodeInfo(uuid)).toReturn(nodeInfo);
- stub(cache2.getPathFor(uuid)).toReturn(path("/a/b/c"));
- stub(cache2.getPathFor(nodeInfo)).toReturn(path("/a/b/c"));
- stub(cache2.findPropertyInfo(propertyId2)).toReturn(propertyInfo);
+ // Use the same id and location; use 'Nissan Altima'
+ // since the UUIDs will be different (cars.xml doesn't define on this node) ...
+ javax.jcr.Node altima2 = cache2.findJcrNode(null, path("/Cars/Hybrid/Nissan Altima"));
+ altima2.addMixin("mix:referenceable");
+ altima.addMixin("mix:referenceable");
+ String altimaUuid = altima.getUUID();
+ String altimaUuid2 = altima2.getUUID();
+ assertThat(altimaUuid, is(not(altimaUuid2)));
+ assertThat(altima2.isSame(altima), is(false));
- assertThat(node.isSame(otherNode), is(true));
-
- Property prop = new MockAbstractJcrProperty(cache, propertyId);
- Property otherProp = new MockAbstractJcrProperty(cache2, propertyId2);
- assertThat(prop.isSame(otherProp), is(false));
+ // Check the properties ...
+ javax.jcr.Property model = altima.getProperty("vehix:model");
+ javax.jcr.Property model2 = altima2.getProperty("vehix:model");
+ assertThat(model.isSame(model2), is(false));
}
- private class MockAbstractJcrProperty extends AbstractJcrProperty {
+ @Test
+ public void shouldReturnTrueFromIsSameIfTheNodeUuidAndWorkspaceNameAndRepositoryInstanceAreSame() throws Exception {
+ // Set up the store ...
+ InMemoryRepositorySource source2 = new InMemoryRepositorySource();
+ source2.setName("store");
+ Graph store2 = Graph.create(source2, context);
+ store2.importXmlFrom(AbstractJcrTest.class.getClassLoader().getResourceAsStream("cars.xml")).into("/");
+ JcrSession jcrSession2 = mock(JcrSession.class);
+ stub(jcrSession2.nodeTypeManager()).toReturn(nodeTypes);
+ SessionCache cache2 = new SessionCache(jcrSession2, store2.getCurrentWorkspaceName(), context, nodeTypes, store2);
- MockAbstractJcrProperty( SessionCache cache,
- PropertyId propertyId ) {
- super(cache, propertyId);
- }
+ Workspace workspace2 = mock(Workspace.class);
+ stub(jcrSession2.getWorkspace()).toReturn(workspace2);
+ stub(jcrSession2.getRepository()).toReturn(repository);
+ stub(workspace2.getName()).toReturn("workspace1");
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.jcr.AbstractJcrProperty#isMultiple()
- */
- @Override
- boolean isMultiple() {
- return false;
- }
+ // Use the same id and location ...
+ javax.jcr.Node prius2 = cache2.findJcrNode(null, path("/Cars/Hybrid/Toyota Prius"));
+ prius2.addMixin("mix:referenceable");
+ prius.addMixin("mix:referenceable");
+ String priusUuid = prius.getUUID();
+ String priusUuid2 = prius2.getUUID();
+ assertThat(priusUuid, is(priusUuid2));
+ assertThat(prius2.isSame(prius), is(true));
- /**
- * {@inheritDoc}
- *
- * @see javax.jcr.Property#getNode()
- */
- @SuppressWarnings( "synthetic-access" )
- public Node getNode() {
- return node;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see javax.jcr.Property#getBoolean()
- */
- public boolean getBoolean() {
- return false;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see javax.jcr.Property#getDate()
- */
- public Calendar getDate() {
- return null;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see javax.jcr.Property#getDouble()
- */
- public double getDouble() {
- return 0;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see javax.jcr.Property#getLength()
- */
- public long getLength() {
- return 0;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see javax.jcr.Property#getLengths()
- */
- public long[] getLengths() {
- return null;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see javax.jcr.Property#getLong()
- */
- public long getLong() {
- return 0;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see javax.jcr.Property#getStream()
- */
- public InputStream getStream() {
- return null;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see javax.jcr.Property#getString()
- */
- public String getString() {
- return null;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see javax.jcr.Property#getValue()
- */
- public Value getValue() {
- return null;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see javax.jcr.Property#getValues()
- */
- public Value[] getValues() {
- return null;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see javax.jcr.Property#setValue(javax.jcr.Value)
- */
- public void setValue( Value value ) {
- throw new UnsupportedOperationException();
- }
-
- /**
- * {@inheritDoc}
- *
- * @see javax.jcr.Property#setValue(javax.jcr.Value[])
- */
- public void setValue( Value[] values ) {
- throw new UnsupportedOperationException();
- }
-
- /**
- * {@inheritDoc}
- *
- * @see javax.jcr.Property#setValue(java.lang.String)
- */
- public void setValue( String value ) {
- throw new UnsupportedOperationException();
- }
-
- /**
- * {@inheritDoc}
- *
- * @see javax.jcr.Property#setValue(java.lang.String[])
- */
- public void setValue( String[] values ) {
- throw new UnsupportedOperationException();
- }
-
- /**
- * {@inheritDoc}
- *
- * @see javax.jcr.Property#setValue(java.io.InputStream)
- */
- public void setValue( InputStream value ) {
- throw new UnsupportedOperationException();
- }
-
- /**
- * {@inheritDoc}
- *
- * @see javax.jcr.Property#setValue(long)
- */
- public void setValue( long value ) {
- throw new UnsupportedOperationException();
- }
-
- /**
- * {@inheritDoc}
- *
- * @see javax.jcr.Property#setValue(double)
- */
- public void setValue( double value ) {
- throw new UnsupportedOperationException();
- }
-
- /**
- * {@inheritDoc}
- *
- * @see javax.jcr.Property#setValue(java.util.Calendar)
- */
- public void setValue( Calendar value ) {
- throw new UnsupportedOperationException();
- }
-
- /**
- * {@inheritDoc}
- *
- * @see javax.jcr.Property#setValue(boolean)
- */
- public void setValue( boolean value ) {
- throw new UnsupportedOperationException();
- }
-
- /**
- * {@inheritDoc}
- *
- * @see javax.jcr.Property#setValue(javax.jcr.Node)
- */
- public void setValue( Node value ) {
- throw new UnsupportedOperationException();
- }
+ // Check the properties ...
+ javax.jcr.Property model = prius.getProperty("vehix:model");
+ javax.jcr.Property model2 = prius2.getProperty("vehix:model");
+ javax.jcr.Property year2 = prius2.getProperty("vehix:year");
+ assertThat(model.isSame(model2), is(true));
+ assertThat(model.isSame(year2), is(false));
}
+
}
Modified: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/AbstractJcrTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/AbstractJcrTest.java 2009-07-09 16:23:09 UTC (rev 1081)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/AbstractJcrTest.java 2009-07-09 16:26:04 UTC (rev 1082)
@@ -1,84 +1,77 @@
+/*
+ * 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.jcr;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.stub;
import java.io.IOException;
-import java.util.Collections;
-import java.util.EnumMap;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import javax.jcr.Repository;
import javax.jcr.RepositoryException;
+import javax.jcr.Workspace;
import org.jboss.dna.graph.ExecutionContext;
import org.jboss.dna.graph.Graph;
-import org.jboss.dna.graph.MockSecurityContext;
-import org.jboss.dna.graph.SecurityContext;
import org.jboss.dna.graph.connector.RepositoryConnection;
import org.jboss.dna.graph.connector.RepositoryConnectionFactory;
import org.jboss.dna.graph.connector.RepositorySourceException;
import org.jboss.dna.graph.connector.inmemory.InMemoryRepositorySource;
-import org.jboss.dna.graph.property.NamespaceRegistry;
-import org.jboss.dna.jcr.nodetype.NodeTypeTemplate;
-import org.mockito.MockitoAnnotations;
-import org.mockito.MockitoAnnotations.Mock;
+import org.jboss.dna.graph.property.Name;
+import org.jboss.dna.graph.property.Path;
+import org.junit.Before;
+import org.junit.BeforeClass;
-public abstract class AbstractJcrTest {
+/**
+ *
+ */
+public class AbstractJcrTest {
-
- protected String workspaceName;
- protected ExecutionContext context;
+ protected static ExecutionContext context;
+ protected static RepositoryNodeTypeManager rntm;
protected InMemoryRepositorySource source;
- protected JcrWorkspace workspace;
- protected JcrSession session;
- protected Graph graph;
- protected RepositoryConnectionFactory connectionFactory;
- protected RepositoryNodeTypeManager repoTypeManager;
- protected Map<String, Object> sessionAttributes;
- protected Map<JcrRepository.Option, String> options;
- protected NamespaceRegistry registry;
- @Mock
- protected JcrRepository repository;
+ protected Graph store;
+ protected int numberOfConnections;
+ protected SessionCache cache;
+ protected JcrSession jcrSession;
+ protected JcrNodeTypeManager nodeTypes;
+ protected Workspace workspace;
+ protected Repository repository;
- protected void beforeEach() throws Exception {
- MockitoAnnotations.initMocks(this);
-
- workspaceName = "workspace1";
- final String repositorySourceName = "repository";
-
- // Set up the source ...
- source = new InMemoryRepositorySource();
- source.setName(workspaceName);
- source.setDefaultWorkspaceName(workspaceName);
-
- // Set up the execution context ...
+ /**
+ * Initialize the expensive activities, and in particular the RepositoryNodeTypeManager instance.
+ *
+ * @throws Exception
+ */
+ @BeforeClass
+ public static void beforeAll() throws Exception {
context = new ExecutionContext();
- // Register the test namespace
- context.getNamespaceRegistry().register(TestLexicon.Namespace.PREFIX, TestLexicon.Namespace.URI);
- // Set up the initial content ...
- graph = Graph.create(source, context);
- initializeContent();
-
- // Stub out the connection factory ...
- connectionFactory = new RepositoryConnectionFactory() {
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.graph.connector.RepositoryConnectionFactory#createConnection(java.lang.String)
- */
- @SuppressWarnings( "synthetic-access" )
- public RepositoryConnection createConnection( String sourceName ) throws RepositorySourceException {
- return repositorySourceName.equals(sourceName) ? source.getConnection() : null;
- }
- };
-
- // Stub out the repository, since we only need a few methods ...
- repoTypeManager = new RepositoryNodeTypeManager(context);
-
+ // Create the node type manager ...
+ context.getNamespaceRegistry().register(Vehicles.Lexicon.Namespace.PREFIX, Vehicles.Lexicon.Namespace.URI);
+ rntm = new RepositoryNodeTypeManager(context);
try {
- this.repoTypeManager.registerNodeTypes(new CndNodeTypeSource(new String[] {"/org/jboss/dna/jcr/jsr_170_builtins.cnd",
+ rntm.registerNodeTypes(new CndNodeTypeSource(new String[] {"/org/jboss/dna/jcr/jsr_170_builtins.cnd",
"/org/jboss/dna/jcr/dna_builtins.cnd"}));
- this.repoTypeManager.registerNodeTypes(new NodeTemplateNodeTypeSource(getTestTypes()));
-
+ rntm.registerNodeTypes(new NodeTemplateNodeTypeSource(Vehicles.getNodeTypes(context)));
} catch (RepositoryException re) {
re.printStackTrace();
throw new IllegalStateException("Could not load node type definition files", re);
@@ -86,41 +79,59 @@
ioe.printStackTrace();
throw new IllegalStateException("Could not access node type definition files", ioe);
}
+ }
- stub(repository.getRepositoryTypeManager()).toReturn(repoTypeManager);
- stub(repository.getRepositorySourceName()).toReturn(repositorySourceName);
- stub(repository.getConnectionFactory()).toReturn(connectionFactory);
+ /**
+ * Set up and initialize the store and session. This allows each test method to be independent; any changes made to the
+ * sessions or store state will not be seen by other tests.
+ *
+ * @throws Exception
+ */
+ @Before
+ public void beforeEach() throws Exception {
+ // Set up the store ...
+ source = new InMemoryRepositorySource();
+ source.setName("store");
+ // Use a connection factory so we can count the number of connections that were made
+ RepositoryConnectionFactory connectionFactory = new RepositoryConnectionFactory() {
+ public RepositoryConnection createConnection( String sourceName ) throws RepositorySourceException {
+ if (source.getName().equals(sourceName)) {
+ ++numberOfConnections;
+ return source.getConnection();
+ }
+ return null;
+ }
+ };
+ store = Graph.create(source.getName(), connectionFactory, context);
- initializeOptions();
- stub(repository.getOptions()).toReturn(options);
+ // Load the store with content ...
+ store.importXmlFrom(AbstractJcrTest.class.getClassLoader().getResourceAsStream("cars.xml")).into("/");
+ numberOfConnections = 0; // reset the number of connections
- // Set up the session attributes ...
- // Set up the session attributes ...
- sessionAttributes = new HashMap<String, Object>();
- sessionAttributes.put("attribute1", "value1");
+ nodeTypes = new JcrNodeTypeManager(context, rntm);
- // Now create the workspace ...
- SecurityContext mockSecurityContext = new MockSecurityContext(null,
- Collections.singleton(JcrSession.DNA_WRITE_PERMISSION));
- workspace = new JcrWorkspace(repository, workspaceName, context.with(mockSecurityContext), sessionAttributes);
+ // Stub the session ...
+ jcrSession = mock(JcrSession.class);
+ stub(jcrSession.nodeTypeManager()).toReturn(nodeTypes);
- // Create the session and log in ...
- session = (JcrSession)workspace.getSession();
- registry = session.getExecutionContext().getNamespaceRegistry();
+ cache = new SessionCache(jcrSession, store.getCurrentWorkspaceName(), context, nodeTypes, store);
+
+ workspace = mock(Workspace.class);
+ repository = mock(Repository.class);
+ stub(jcrSession.getWorkspace()).toReturn(workspace);
+ stub(jcrSession.getRepository()).toReturn(repository);
+ stub(workspace.getName()).toReturn("workspace1");
}
- protected List<NodeTypeTemplate> getTestTypes() {
- return Collections.emptyList();
+ protected Name name( String name ) {
+ return context.getValueFactories().getNameFactory().create(name);
}
- protected void initializeContent() {
-
+ protected Path relativePath( String relativePath ) {
+ return context.getValueFactories().getPathFactory().create(relativePath);
}
-
- protected void initializeOptions() {
- // Stub out the repository options ...
- options = new EnumMap<JcrRepository.Option, String>(JcrRepository.Option.class);
- options.put(JcrRepository.Option.PROJECT_NODE_TYPES, Boolean.FALSE.toString());
+ protected Path path( String absolutePath ) {
+ return context.getValueFactories().getPathFactory().create(absolutePath);
}
}
Modified: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrChildNodeIteratorTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrChildNodeIteratorTest.java 2009-07-09 16:23:09 UTC (rev 1081)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrChildNodeIteratorTest.java 2009-07-09 16:26:04 UTC (rev 1082)
@@ -27,52 +27,39 @@
import static org.hamcrest.core.IsSame.sameInstance;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.stub;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
-import java.util.UUID;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
-import org.jboss.dna.graph.property.basic.BasicName;
-import org.jboss.dna.graph.property.basic.BasicPathSegment;
-import org.jboss.dna.jcr.cache.ChildNode;
import org.junit.Before;
import org.junit.Test;
import org.mockito.MockitoAnnotations;
-import org.mockito.MockitoAnnotations.Mock;
/**
*
*/
public class JcrChildNodeIteratorTest {
- private List<ChildNode> children;
- private List<Node> childNodes;
+ private List<AbstractJcrNode> children;
private NodeIterator iter;
- @Mock
- private SessionCache cache;
@Before
public void beforeEach() throws Exception {
MockitoAnnotations.initMocks(this);
- children = new ArrayList<ChildNode>();
- childNodes = new ArrayList<Node>();
+ children = new ArrayList<AbstractJcrNode>();
for (int i = 0; i != 10; ++i) {
- UUID uuid = UUID.randomUUID();
- ChildNode child = new ChildNode(uuid, new BasicPathSegment(new BasicName("", "name"), i + 1));
- AbstractJcrNode node = mock(AbstractJcrNode.class);
- stub(cache.findJcrNode(uuid)).toReturn(node);
- children.add(child);
- childNodes.add(node);
+ // Create a child (node with payload and JCR node object, all mock) ...
+ AbstractJcrNode childJcrNode = mock(AbstractJcrNode.class);
+ children.add(childJcrNode);
}
- iter = new JcrChildNodeIterator(cache, children, children.size());
+ iter = new JcrChildNodeIterator(children, children.size());
}
@Test
public void shouldProperlyDetermineHasNext() {
- Iterator<Node> nodeIter = childNodes.iterator();
+ Iterator<AbstractJcrNode> nodeIter = children.iterator();
long position = 0L;
assertThat(iter.getPosition(), is(position));
while (iter.hasNext()) {
@@ -94,7 +81,7 @@
@Test
public void shouldHaveCorrectSize() {
- assertThat(iter.getSize(), is((long)childNodes.size()));
+ assertThat(iter.getSize(), is((long)children.size()));
}
@Test( expected = UnsupportedOperationException.class )
Modified: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrMultiValuePropertyTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrMultiValuePropertyTest.java 2009-07-09 16:23:09 UTC (rev 1081)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrMultiValuePropertyTest.java 2009-07-09 16:26:04 UTC (rev 1082)
@@ -26,176 +26,322 @@
import static org.hamcrest.core.Is.is;
import static org.hamcrest.core.IsNull.notNullValue;
import static org.junit.Assert.assertThat;
-import static org.mockito.Mockito.stub;
-import java.util.UUID;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import javax.jcr.Node;
+import javax.jcr.Property;
import javax.jcr.PropertyType;
import javax.jcr.Value;
import javax.jcr.ValueFormatException;
import javax.jcr.nodetype.PropertyDefinition;
-import org.jboss.dna.graph.ExecutionContext;
-import org.jboss.dna.graph.property.Name;
-import org.jboss.dna.jcr.cache.PropertyInfo;
+import org.jboss.dna.graph.property.DateTime;
+import org.jboss.dna.graph.property.DateTimeFactory;
+import org.jboss.dna.jcr.nodetype.NodeTypeDefinition;
+import org.jboss.dna.jcr.nodetype.PropertyDefinitionTemplate;
import org.junit.Before;
+import org.junit.BeforeClass;
import org.junit.Test;
-import org.mockito.MockitoAnnotations;
-import org.mockito.MockitoAnnotations.Mock;
/**
* @author jverhaeg
*/
-public class JcrMultiValuePropertyTest {
+public class JcrMultiValuePropertyTest extends AbstractJcrTest {
- private PropertyId propertyId;
- private JcrMultiValueProperty prop;
- private ExecutionContext executionContext;
- private org.jboss.dna.graph.property.Property dnaProperty;
- @Mock
- private SessionCache cache;
- @Mock
- private JcrSession session;
- @Mock
- private PropertyInfo propertyInfo;
- @Mock
- private JcrPropertyDefinition definition;
- @Mock
- private JcrNodeTypeManager nodeTypes;
+ private Property prop;
+ private byte[][] binaryValue;
+ private DateTime[] dateValue;
+ private double[] doubleValue;
+ private long[] longValue;
+ private String[] stringValue;
+ private boolean[] booleanValue;
+ private String[] nameValue;
+ private String[] pathValue;
+ private DateTimeFactory dateFactory;
+ protected AbstractJcrNode cars;
+ protected AbstractJcrNode altima;
+ /**
+ * Initialize the expensive activities, and in particular the RepositoryNodeTypeManager instance.
+ *
+ * @throws Exception
+ */
+ @BeforeClass
+ public static void beforeAll() throws Exception {
+ AbstractJcrTest.beforeAll();
+
+ // Define the node definition that will have all the different kinds of properties ...
+ JcrNodeTypeTemplate nodeType = new JcrNodeTypeTemplate(context);
+ nodeType.setMixin(true);
+ nodeType.setName("mixinWithAllPropTypes");
+ List<PropertyDefinitionTemplate> propDefns = nodeType.getPropertyDefinitionTemplates();
+
+ // Add a property for each type ...
+ JcrPropertyDefinitionTemplate binaryDefn = new JcrPropertyDefinitionTemplate(context);
+ binaryDefn.setName("binaryProperty");
+ binaryDefn.setRequiredType(PropertyType.BINARY);
+ binaryDefn.setMultiple(true);
+ propDefns.add(binaryDefn);
+
+ JcrPropertyDefinitionTemplate booleanDefn = new JcrPropertyDefinitionTemplate(context);
+ booleanDefn.setName("booleanProperty");
+ booleanDefn.setRequiredType(PropertyType.BOOLEAN);
+ booleanDefn.setMultiple(true);
+ propDefns.add(booleanDefn);
+
+ JcrPropertyDefinitionTemplate dateDefn = new JcrPropertyDefinitionTemplate(context);
+ dateDefn.setName("dateProperty");
+ dateDefn.setRequiredType(PropertyType.DATE);
+ dateDefn.setMultiple(true);
+ propDefns.add(dateDefn);
+
+ JcrPropertyDefinitionTemplate doubleDefn = new JcrPropertyDefinitionTemplate(context);
+ doubleDefn.setName("doubleProperty");
+ doubleDefn.setRequiredType(PropertyType.DOUBLE);
+ doubleDefn.setMultiple(true);
+ propDefns.add(doubleDefn);
+
+ JcrPropertyDefinitionTemplate longDefn = new JcrPropertyDefinitionTemplate(context);
+ longDefn.setName("longProperty");
+ longDefn.setRequiredType(PropertyType.LONG);
+ longDefn.setMultiple(true);
+ propDefns.add(longDefn);
+
+ JcrPropertyDefinitionTemplate nameDefn = new JcrPropertyDefinitionTemplate(context);
+ nameDefn.setName("nameProperty");
+ nameDefn.setRequiredType(PropertyType.NAME);
+ nameDefn.setMultiple(true);
+ propDefns.add(nameDefn);
+
+ JcrPropertyDefinitionTemplate pathDefn = new JcrPropertyDefinitionTemplate(context);
+ pathDefn.setName("pathProperty");
+ pathDefn.setRequiredType(PropertyType.PATH);
+ pathDefn.setMultiple(true);
+ propDefns.add(pathDefn);
+
+ JcrPropertyDefinitionTemplate refDefn = new JcrPropertyDefinitionTemplate(context);
+ refDefn.setName("referenceProperty");
+ refDefn.setRequiredType(PropertyType.REFERENCE);
+ refDefn.setMultiple(true);
+ propDefns.add(refDefn);
+
+ JcrPropertyDefinitionTemplate stringDefn = new JcrPropertyDefinitionTemplate(context);
+ stringDefn.setName("stringProperty");
+ stringDefn.setRequiredType(PropertyType.STRING);
+ stringDefn.setMultiple(true);
+ propDefns.add(stringDefn);
+
+ JcrPropertyDefinitionTemplate undefinedDefn = new JcrPropertyDefinitionTemplate(context);
+ undefinedDefn.setName("undefinedProperty");
+ undefinedDefn.setRequiredType(PropertyType.UNDEFINED);
+ undefinedDefn.setMultiple(true);
+ propDefns.add(undefinedDefn);
+
+ // Add the node type ...
+ Collection<NodeTypeDefinition> defns = new ArrayList<NodeTypeDefinition>();
+ defns.add(nodeType);
+ rntm.registerNodeTypes(defns, false);
+ }
+
+ @Override
@Before
- public void before() throws Exception {
- MockitoAnnotations.initMocks(this);
- executionContext = new ExecutionContext();
- stub(cache.session()).toReturn(session);
- stub(cache.context()).toReturn(executionContext);
- stub(session.nodeTypeManager()).toReturn(nodeTypes);
+ public void beforeEach() throws Exception {
+ super.beforeEach();
+ context.getNamespaceRegistry().register("acme", "http://example.com");
+ dateFactory = context.getValueFactories().getDateFactory();
- dnaProperty = executionContext.getPropertyFactory().create(JcrLexicon.MIMETYPE, true);
- stub(definition.getRequiredType()).toReturn(PropertyType.BOOLEAN);
- stub(definition.isMultiple()).toReturn(true);
- PropertyDefinitionId definitionId = new PropertyDefinitionId(name("nodeTypeName"), name("propDefnName"),
- PropertyType.BOOLEAN, true);
- stub(nodeTypes.getPropertyDefinition(definitionId)).toReturn(definition);
+ binaryValue = new byte[][] {"This is a binary value1".getBytes(), "This is a binary value2".getBytes()};
+ dateValue = new DateTime[] {dateFactory.create(), dateFactory.create().plusDays(1)};
+ doubleValue = new double[] {3.14159d, 1.0d};
+ longValue = new long[] {100L, 101L};
+ booleanValue = new boolean[] {true, false};
+ stringValue = new String[] {"stringValue1", "string value 2"};
+ nameValue = new String[] {"acme:SomeName1", "acme:SomeName2"};
+ pathValue = new String[] {"/Cars/Hybrid/Toyota Highlander/acme:SomethingElse", "/Cars/acme:Wow"};
- UUID uuid = UUID.randomUUID();
- propertyId = new PropertyId(uuid, JcrLexicon.MIMETYPE);
- prop = new JcrMultiValueProperty(cache, propertyId);
+ // Add the mixin to the 'Cars' node ...
+ cars = cache.findJcrNode(null, path("/Cars"));
+ cars.addMixin("mixinWithAllPropTypes");
- stub(cache.findPropertyInfo(propertyId)).toReturn(propertyInfo);
- stub(propertyInfo.getDefinitionId()).toReturn(definitionId);
- stub(propertyInfo.getPropertyType()).toReturn(PropertyType.BOOLEAN);
- stub(propertyInfo.isMultiValued()).toReturn(true);
- stub(propertyInfo.getProperty()).toReturn(dnaProperty);
+ altima = cache.findJcrNode(null, path("/Cars/Hybrid/Nissan Altima"));
+ altima.addMixin("mix:referenceable");
+
+ // Set each property ...
+ cars.setProperty("booleanProperty", values(booleanValue));
+ cars.setProperty("dateProperty", values(dateValue));
+ cars.setProperty("doubleProperty", values(doubleValue));
+ cars.setProperty("binaryProperty", values(binaryValue));
+ cars.setProperty("longProperty", values(longValue));
+ cars.setProperty("referenceProperty", values(new Node[] {altima}));
+ cars.setProperty("stringProperty", values(PropertyType.STRING, stringValue));
+ cars.setProperty("pathProperty", values(PropertyType.PATH, pathValue));
+ cars.setProperty("nameProperty", values(PropertyType.NAME, nameValue));
+ cars.setProperty("undefinedProperty", values(PropertyType.STRING, new String[] {"100", "200"}));
}
- protected Name name( String name ) {
- return executionContext.getValueFactories().getNameFactory().create(name);
+ protected Value[] values( boolean[] values ) throws Exception {
+ Value[] result = new Value[values.length];
+ for (int i = 0; i != values.length; ++i) {
+ result[i] = new JcrValue(context.getValueFactories(), cache, PropertyType.BOOLEAN, values[i]);
+ }
+ return result;
}
- @Test
- public void shouldProvideAppropriateType() throws Exception {
- assertThat(prop.getType(), is(definition.getRequiredType()));
+ protected Value[] values( long[] values ) throws Exception {
+ Value[] result = new Value[values.length];
+ for (int i = 0; i != values.length; ++i) {
+ result[i] = new JcrValue(context.getValueFactories(), cache, PropertyType.LONG, values[i]);
+ }
+ return result;
}
- @Test
- public void shouldProvidePropertyDefinition() throws Exception {
- assertThat(prop.getDefinition(), is((PropertyDefinition)definition));
+ protected Value[] values( double[] values ) throws Exception {
+ Value[] result = new Value[values.length];
+ for (int i = 0; i != values.length; ++i) {
+ result[i] = new JcrValue(context.getValueFactories(), cache, PropertyType.DOUBLE, values[i]);
+ }
+ return result;
}
+ protected Value[] values( byte[][] values ) throws Exception {
+ Value[] result = new Value[values.length];
+ for (int i = 0; i != values.length; ++i) {
+ result[i] = new JcrValue(context.getValueFactories(), cache, PropertyType.BINARY, values[i]);
+ }
+ return result;
+ }
+
+ protected Value[] values( DateTime[] values ) throws Exception {
+ Value[] result = new Value[values.length];
+ for (int i = 0; i != values.length; ++i) {
+ result[i] = new JcrValue(context.getValueFactories(), cache, PropertyType.DATE, values[i].toCalendar());
+ }
+ return result;
+ }
+
+ protected Value[] values( Node[] values ) throws Exception {
+ Value[] result = new Value[values.length];
+ for (int i = 0; i != values.length; ++i) {
+ result[i] = new JcrValue(context.getValueFactories(), cache, PropertyType.REFERENCE, values[i]);
+ }
+ return result;
+ }
+
+ protected Value[] values( int type,
+ String[] values ) throws Exception {
+ Value[] result = new Value[values.length];
+ for (int i = 0; i != values.length; ++i) {
+ result[i] = new JcrValue(context.getValueFactories(), cache, type, values[i]);
+ }
+ return result;
+ }
+
@Test
public void shouldIndicateHasMultipleValues() throws Exception {
+ prop = cars.getProperty("booleanProperty");
PropertyDefinition def = prop.getDefinition();
- assertThat(def, notNullValue());
assertThat(def.isMultiple(), is(true));
}
@Test( expected = ValueFormatException.class )
public void shouldNotProvideBooleanForMultiValuedProperty() throws Exception {
+ prop = cars.getProperty("booleanProperty");
prop.getBoolean();
}
@Test( expected = ValueFormatException.class )
public void shouldNotProvideDateForMultiValuedProperty() throws Exception {
+ prop = cars.getProperty("dateProperty");
prop.getDate();
}
@Test( expected = ValueFormatException.class )
public void shouldNotProvideDoubleForMultiValuedProperty() throws Exception {
+ prop = cars.getProperty("doubleProperty");
prop.getDouble();
}
@Test( expected = ValueFormatException.class )
public void shouldNotProvideLongForMultiValuedProperty() throws Exception {
+ prop = cars.getProperty("longProperty");
prop.getLong();
}
@Test( expected = ValueFormatException.class )
public void shouldNotProvideStreamForMultiValuedProperty() throws Exception {
+ prop = cars.getProperty("binaryProperty");
prop.getStream();
}
@Test( expected = ValueFormatException.class )
public void shouldNotProvideStringForMultiValuedProperty() throws Exception {
+ prop = cars.getProperty("stringProperty");
prop.getString();
}
@Test( expected = ValueFormatException.class )
public void shouldNotProvideValue() throws Exception {
+ prop = cars.getProperty("stringProperty");
prop.getValue();
}
@Test
public void shouldProvideValues() throws Exception {
+ prop = cars.getProperty("booleanProperty");
Value[] vals = prop.getValues();
assertThat(vals, notNullValue());
- assertThat(vals.length, is(1));
+ assertThat(vals.length, is(2));
assertThat(vals[0].getBoolean(), is(true));
+ assertThat(vals[1].getBoolean(), is(false));
}
@Test( expected = ValueFormatException.class )
public void shouldNotProvideLength() throws Exception {
+ prop = cars.getProperty("stringProperty");
prop.getLength();
}
- @Test
- public void shouldProvideLengths() throws Exception {
- long[] lengths = prop.getLengths();
- assertThat(lengths, notNullValue());
- assertThat(lengths.length, is(1));
- assertThat(lengths[0], is(4L));
-
- Object value = "value";
- dnaProperty = executionContext.getPropertyFactory().create(JcrLexicon.MIMETYPE, value);
- stub(propertyInfo.getProperty()).toReturn(dnaProperty);
- stub(definition.getRequiredType()).toReturn(PropertyType.STRING);
- stub(definition.isMultiple()).toReturn(true);
- prop = new JcrMultiValueProperty(cache, propertyId);
- lengths = prop.getLengths();
- assertThat(lengths, notNullValue());
- assertThat(lengths.length, is(1));
- assertThat(lengths[0], is(5L));
-
- value = new Object();
- long expectedLength = executionContext.getValueFactories().getBinaryFactory().create(value).getSize();
- dnaProperty = executionContext.getPropertyFactory().create(JcrLexicon.MIMETYPE, value);
- stub(propertyInfo.getProperty()).toReturn(dnaProperty);
- stub(definition.getRequiredType()).toReturn(PropertyType.STRING);
- stub(definition.isMultiple()).toReturn(true);
- prop = new JcrMultiValueProperty(cache, propertyId);
- lengths = prop.getLengths();
- assertThat(lengths, notNullValue());
- assertThat(lengths.length, is(1));
- assertThat(lengths[0], is(expectedLength));
-
- String[] values = new String[] {"value1", "value2", "value 3 is longer"};
- dnaProperty = executionContext.getPropertyFactory().create(JcrLexicon.MIMETYPE, (Object[])values);
- stub(propertyInfo.getProperty()).toReturn(dnaProperty);
- stub(definition.getRequiredType()).toReturn(PropertyType.STRING);
- stub(definition.isMultiple()).toReturn(true);
- prop = new JcrMultiValueProperty(cache, propertyId);
- lengths = prop.getLengths();
- assertThat(lengths, notNullValue());
- assertThat(lengths.length, is(values.length));
- assertThat(lengths[0], is((long)values[0].length()));
- assertThat(lengths[1], is((long)values[1].length()));
- assertThat(lengths[2], is((long)values[2].length()));
- }
+ // @Test
+ // public void shouldProvideLengths() throws Exception {
+ // long[] lengths = prop.getLengths();
+ // assertThat(lengths, notNullValue());
+ // assertThat(lengths.length, is(1));
+ // assertThat(lengths[0], is(4L));
+ //
+ // Object value = "value";
+ // dnaProperty = executionContext.getPropertyFactory().create(JcrLexicon.MIMETYPE, value);
+ // stub(propertyInfo.getProperty()).toReturn(dnaProperty);
+ // stub(definition.getRequiredType()).toReturn(PropertyType.STRING);
+ // stub(definition.isMultiple()).toReturn(true);
+ // prop = new JcrMultiValueProperty(cache, propertyId);
+ // lengths = prop.getLengths();
+ // assertThat(lengths, notNullValue());
+ // assertThat(lengths.length, is(1));
+ // assertThat(lengths[0], is(5L));
+ //
+ // value = new Object();
+ // long expectedLength = executionContext.getValueFactories().getBinaryFactory().create(value).getSize();
+ // dnaProperty = executionContext.getPropertyFactory().create(JcrLexicon.MIMETYPE, value);
+ // stub(propertyInfo.getProperty()).toReturn(dnaProperty);
+ // stub(definition.getRequiredType()).toReturn(PropertyType.STRING);
+ // stub(definition.isMultiple()).toReturn(true);
+ // prop = new JcrMultiValueProperty(cache, propertyId);
+ // lengths = prop.getLengths();
+ // assertThat(lengths, notNullValue());
+ // assertThat(lengths.length, is(1));
+ // assertThat(lengths[0], is(expectedLength));
+ //
+ // String[] values = new String[] {"value1", "value2", "value 3 is longer"};
+ // dnaProperty = executionContext.getPropertyFactory().create(JcrLexicon.MIMETYPE, (Object[])values);
+ // stub(propertyInfo.getProperty()).toReturn(dnaProperty);
+ // stub(definition.getRequiredType()).toReturn(PropertyType.STRING);
+ // stub(definition.isMultiple()).toReturn(true);
+ // prop = new JcrMultiValueProperty(cache, propertyId);
+ // lengths = prop.getLengths();
+ // assertThat(lengths, notNullValue());
+ // assertThat(lengths.length, is(values.length));
+ // assertThat(lengths[0], is((long)values[0].length()));
+ // assertThat(lengths[1], is((long)values[1].length()));
+ // assertThat(lengths[2], is((long)values[2].length()));
+ // }
}
Modified: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrNodeTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrNodeTest.java 2009-07-09 16:23:09 UTC (rev 1081)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrNodeTest.java 2009-07-09 16:26:04 UTC (rev 1082)
@@ -4,13 +4,13 @@
* 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.
+ * 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
@@ -24,81 +24,51 @@
package org.jboss.dna.jcr;
import static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.IsNull.notNullValue;
import static org.junit.Assert.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.stub;
-import java.util.UUID;
-import javax.jcr.ItemNotFoundException;
-import org.jboss.dna.graph.ExecutionContext;
-import org.jboss.dna.graph.property.Name;
-import org.jboss.dna.graph.property.Path;
-import org.jboss.dna.jcr.cache.NodeInfo;
import org.junit.Before;
import org.junit.Test;
-import org.mockito.MockitoAnnotations;
-import org.mockito.MockitoAnnotations.Mock;
/**
- * @author jverhaeg
+ *
*/
-public class JcrNodeTest {
+public class JcrNodeTest extends AbstractJcrTest {
- private UUID uuid;
- private JcrNode node;
- private ExecutionContext context;
- @Mock
- private SessionCache cache;
+ private AbstractJcrNode hybrid;
+ private AbstractJcrNode altima;
+ @Override
@Before
- public void before() throws Exception {
- MockitoAnnotations.initMocks(this);
-
- uuid = UUID.randomUUID();
- node = new JcrNode(cache, uuid);
-
- context = new ExecutionContext();
- stub(cache.context()).toReturn(context);
+ public void beforeEach() throws Exception {
+ super.beforeEach();
+ hybrid = cache.findJcrNode(null, path("/Cars/Hybrid"));
+ altima = cache.findJcrNode(null, path("/Cars/Hybrid/Nissan Altima"));
}
- protected Name name( String name ) {
- return context.getValueFactories().getNameFactory().create(name);
- }
+ @Test
+ public void shouldHavePath() throws Exception {
+ assertThat(altima.getPath(), is("/Cars/Hybrid/Nissan Altima"));
- protected Path path( String path ) {
- return context.getValueFactories().getPathFactory().create(path);
+ javax.jcr.Node altima2 = hybrid.addNode("Nissan Altima");
+ assertThat(altima2, is(notNullValue()));
+ assertThat(altima2.getPath(), is("/Cars/Hybrid/Nissan Altima[2]"));
}
- @Test( expected = ItemNotFoundException.class )
- public void shouldNotAllowAncestorDepthGreaterThanNodeDepth() throws Exception {
- NodeInfo info = mock(NodeInfo.class);
- stub(cache.findNodeInfo(uuid)).toReturn(info);
- stub(cache.getPathFor(info)).toReturn(path("/a/b/c/name[2]"));
- node.getAncestor(6);
- }
-
@Test
- public void shouldProvideDepth() throws Exception {
- NodeInfo info = mock(NodeInfo.class);
- stub(cache.findNodeInfo(uuid)).toReturn(info);
- stub(cache.getPathFor(info)).toReturn(path("/a/b/c/name[2]"));
- assertThat(node.getDepth(), is(4));
- }
+ public void shouldHaveSameNameSiblingIndex() throws Exception {
+ assertThat(altima.getIndex(), is(1));
- @Test
- public void shouldProvideIndex() throws Exception {
- stub(cache.getSnsIndexOf(uuid)).toReturn(1);
- assertThat(node.getIndex(), is(1));
+ javax.jcr.Node altima2 = hybrid.addNode("Nissan Altima");
+ assertThat(altima2, is(notNullValue()));
+ assertThat(altima2.getIndex(), is(2));
}
@Test
- public void shouldProvideName() throws Exception {
- stub(cache.getNameOf(uuid)).toReturn(name("name"));
- assertThat(node.getName(), is("name"));
+ public void shouldHaveNameThatExcludesSameNameSiblingIndex() throws Exception {
+ assertThat(altima.getName(), is("Nissan Altima"));
+ javax.jcr.Node altima2 = hybrid.addNode("Nissan Altima");
+ assertThat(altima2, is(notNullValue()));
+ assertThat(altima2.getPath(), is("/Cars/Hybrid/Nissan Altima[2]"));
+ assertThat(altima2.getName(), is("Nissan Altima"));
}
-
- @Test
- public void shouldProvidePath() throws Exception {
- stub(cache.getPathFor(uuid)).toReturn(path("/a/b/c/name[2]"));
- assertThat(node.getPath(), is("/a/b/c/name[2]"));
- }
}
Modified: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrRootNodeTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrRootNodeTest.java 2009-07-09 16:23:09 UTC (rev 1081)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrRootNodeTest.java 2009-07-09 16:26:04 UTC (rev 1082)
@@ -26,76 +26,53 @@
import static org.hamcrest.core.Is.is;
import static org.hamcrest.core.IsNull.notNullValue;
import static org.junit.Assert.assertThat;
-import static org.mockito.Mockito.stub;
-import java.util.UUID;
import javax.jcr.ItemNotFoundException;
-import org.jboss.dna.graph.ExecutionContext;
-import org.jboss.dna.graph.property.Name;
-import org.jboss.dna.graph.property.Path;
import org.junit.Before;
import org.junit.Test;
-import org.mockito.MockitoAnnotations;
-import org.mockito.MockitoAnnotations.Mock;
/**
* @author jverhaeg
*/
-public class JcrRootNodeTest {
+public class JcrRootNodeTest extends AbstractJcrTest {
- private UUID uuid;
- private JcrRootNode root;
- private ExecutionContext context;
- @Mock
- private SessionCache cache;
+ private AbstractJcrNode rootNode;
+ @Override
@Before
- public void before() throws Exception {
- MockitoAnnotations.initMocks(this);
-
- uuid = UUID.randomUUID();
- root = new JcrRootNode(cache, uuid);
-
- context = new ExecutionContext();
- stub(cache.context()).toReturn(context);
+ public void beforeEach() throws Exception {
+ super.beforeEach();
+ rootNode = cache.findJcrRootNode();
}
- protected Name name( String name ) {
- return context.getValueFactories().getNameFactory().create(name);
- }
-
- protected Path path( String path ) {
- return context.getValueFactories().getPathFactory().create(path);
- }
-
@Test( expected = ItemNotFoundException.class )
public void shouldNotAllowAncestorDepthGreaterThanNodeDepth() throws Exception {
- root.getAncestor(1);
+ rootNode.getAncestor(1);
}
@Test
public void shouldHaveZeroDepth() throws Exception {
- assertThat(root.getDepth(), is(0));
+ assertThat(rootNode.getDepth(), is(0));
}
@Test
public void shouldIndicateIndexIsOne() throws Exception {
- assertThat(root.getIndex(), is(1));
+ assertThat(rootNode.getIndex(), is(1));
}
@Test
public void shouldHaveEmptyName() throws Exception {
- String name = root.getName();
+ String name = rootNode.getName();
assertThat(name, notNullValue());
assertThat(name.length(), is(0));
}
@Test( expected = ItemNotFoundException.class )
public void shouldHaveNoParent() throws Exception {
- root.getParent();
+ rootNode.getParent();
}
@Test
public void shouldProvidePath() throws Exception {
- assertThat(root.getPath(), is("/"));
+ assertThat(rootNode.getPath(), is("/"));
}
}
Modified: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrSessionTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrSessionTest.java 2009-07-09 16:23:09 UTC (rev 1081)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrSessionTest.java 2009-07-09 16:26:04 UTC (rev 1082)
@@ -74,7 +74,6 @@
@Before
public void beforeEach() throws Exception {
super.beforeEach();
-
}
@Override
@@ -89,6 +88,17 @@
// Make sure the path to the namespaces exists ...
graph.create("/jcr:system").and().create("/jcr:system/dna:namespaces").and();
+ // Set up the session attributes ...
+ sessionAttributes = new HashMap<String, Object>();
+ sessionAttributes.put("attribute1", "value1");
+
+ // Now create the workspace ...
+ SecurityContext mockSecurityContext = new MockSecurityContext(null,
+ Collections.singleton(JcrSession.DNA_WRITE_PERMISSION));
+ workspace = new JcrWorkspace(repository, workspaceName, context.with(mockSecurityContext), sessionAttributes);
+
+ // Create the session and log in ...
+ session = (JcrSession)workspace.getSession();
}
@@ -126,7 +136,7 @@
@Test( expected = IllegalArgumentException.class )
public void shouldNotAllowCheckPermissionWithNoPath() throws Exception {
- session.checkPermission((String) null, "read");
+ session.checkPermission((String)null, "read");
}
@Test( expected = IllegalArgumentException.class )
@@ -224,7 +234,8 @@
Subject subject = new Subject(false, Collections.singleton(principal), Collections.EMPTY_SET, Collections.EMPTY_SET);
LoginContext loginContext = mock(LoginContext.class);
stub(loginContext.getSubject()).toReturn(subject);
- Session session = new JcrSession(repository, workspace, context.with(new JaasSecurityContext(loginContext)), sessionAttributes);
+ Session session = new JcrSession(repository, workspace, context.with(new JaasSecurityContext(loginContext)),
+ sessionAttributes);
try {
assertThat(session.getUserID(), is("name"));
} finally {
@@ -236,8 +247,6 @@
public void shouldProvideRootNode() throws Exception {
Node root = session.getRootNode();
assertThat(root, notNullValue());
- UUID uuid = ((JcrRootNode)root).internalUuid();
- assertThat(uuid, notNullValue());
}
@Test
@@ -375,7 +384,8 @@
public void rootNodeShouldBeReferenceable() throws RepositoryException {
Node rootNode = session.getRootNode();
- assertTrue(rootNode.getPrimaryNodeType().isNodeType(JcrMixLexicon.REFERENCEABLE.getString(context.getNamespaceRegistry())));
+ assertTrue(rootNode.getPrimaryNodeType()
+ .isNodeType(JcrMixLexicon.REFERENCEABLE.getString(context.getNamespaceRegistry())));
}
@Test
@@ -415,7 +425,7 @@
// The root node is referenceable in DNA
Node rootNode = session.getRootNode();
- UUID uuid = ((AbstractJcrNode)rootNode).internalUuid();
+ UUID uuid = ((AbstractJcrNode)rootNode).location.getUuid();
assertThat(rootNode.getUUID(), is(uuid.toString()));
}
Modified: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrSingleValuePropertyTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrSingleValuePropertyTest.java 2009-07-09 16:23:09 UTC (rev 1081)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrSingleValuePropertyTest.java 2009-07-09 16:26:04 UTC (rev 1082)
@@ -26,157 +26,211 @@
import static org.hamcrest.core.Is.is;
import static org.hamcrest.core.IsNull.notNullValue;
import static org.junit.Assert.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.stub;
+import static org.junit.Assert.fail;
+import java.io.ByteArrayInputStream;
import java.io.InputStream;
-import java.util.UUID;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
import javax.jcr.Node;
+import javax.jcr.Property;
import javax.jcr.PropertyType;
import javax.jcr.Value;
import javax.jcr.ValueFormatException;
import javax.jcr.nodetype.PropertyDefinition;
-import org.jboss.dna.graph.ExecutionContext;
import org.jboss.dna.graph.property.DateTime;
-import org.jboss.dna.graph.property.Name;
-import org.jboss.dna.graph.property.Path;
-import org.jboss.dna.jcr.cache.PropertyInfo;
+import org.jboss.dna.graph.property.ValueFactory;
+import org.jboss.dna.jcr.nodetype.NodeTypeDefinition;
+import org.jboss.dna.jcr.nodetype.PropertyDefinitionTemplate;
import org.junit.Before;
+import org.junit.BeforeClass;
import org.junit.Test;
-import org.mockito.MockitoAnnotations;
-import org.mockito.MockitoAnnotations.Mock;
-/**
- * @author jverhaeg
- */
-public class JcrSingleValuePropertyTest {
+public class JcrSingleValuePropertyTest extends AbstractJcrTest {
- private PropertyId propertyId;
- private JcrSingleValueProperty prop;
- private ExecutionContext executionContext;
- private org.jboss.dna.graph.property.Property dnaProperty;
- @Mock
- private SessionCache cache;
- @Mock
- private JcrSession session;
- @Mock
- private PropertyInfo propertyInfo;
- @Mock
- private JcrPropertyDefinition definition;
- @Mock
- private JcrNodeTypeManager nodeTypes;
+ private Property prop;
+ private byte[] binaryValue;
+ private DateTime dateValue;
+ private double doubleValue;
+ private long longValue;
+ private String stringValue;
+ private boolean booleanValue;
+ private String nameValue;
+ private String pathValue;
+ private ValueFactory<String> stringFactory;
+ protected AbstractJcrNode cars;
+ protected AbstractJcrNode altima;
- @Before
- public void before() throws Exception {
- MockitoAnnotations.initMocks(this);
- executionContext = new ExecutionContext();
- stub(cache.session()).toReturn(session);
- stub(cache.context()).toReturn(executionContext);
- stub(session.nodeTypeManager()).toReturn(nodeTypes);
- stub(session.getExecutionContext()).toReturn(executionContext);
+ /**
+ * Initialize the expensive activities, and in particular the RepositoryNodeTypeManager instance.
+ *
+ * @throws Exception
+ */
+ @BeforeClass
+ public static void beforeAll() throws Exception {
+ AbstractJcrTest.beforeAll();
- dnaProperty = executionContext.getPropertyFactory().create(JcrLexicon.MIMETYPE, "text/plain");
- stub(definition.getRequiredType()).toReturn(PropertyType.STRING);
- stub(definition.isMultiple()).toReturn(false);
- PropertyDefinitionId definitionId = new PropertyDefinitionId(name("nodeTypeName"), name("propDefnName"),
- PropertyType.STRING, false);
- stub(nodeTypes.getPropertyDefinition(definitionId)).toReturn(definition);
+ // Define the node definition that will have all the different kinds of properties ...
+ JcrNodeTypeTemplate nodeType = new JcrNodeTypeTemplate(context);
+ nodeType.setMixin(true);
+ nodeType.setName("mixinWithAllPropTypes");
+ List<PropertyDefinitionTemplate> propDefns = nodeType.getPropertyDefinitionTemplates();
- UUID uuid = UUID.randomUUID();
- propertyId = new PropertyId(uuid, JcrLexicon.MIMETYPE);
- prop = new JcrSingleValueProperty(cache, propertyId);
+ // Add a property for each type ...
+ JcrPropertyDefinitionTemplate binaryDefn = new JcrPropertyDefinitionTemplate(context);
+ binaryDefn.setName("binaryProperty");
+ binaryDefn.setRequiredType(PropertyType.BINARY);
+ propDefns.add(binaryDefn);
- stub(cache.findPropertyInfo(propertyId)).toReturn(propertyInfo);
- stub(propertyInfo.getDefinitionId()).toReturn(definitionId);
- stub(propertyInfo.getPropertyType()).toReturn(PropertyType.STRING);
- stub(propertyInfo.isMultiValued()).toReturn(false);
- stub(propertyInfo.getProperty()).toReturn(dnaProperty);
- stub(propertyInfo.getPropertyName()).toReturn(dnaProperty.getName());
- }
+ JcrPropertyDefinitionTemplate booleanDefn = new JcrPropertyDefinitionTemplate(context);
+ booleanDefn.setName("booleanProperty");
+ booleanDefn.setRequiredType(PropertyType.BOOLEAN);
+ propDefns.add(booleanDefn);
- protected Name name( String name ) {
- return executionContext.getValueFactories().getNameFactory().create(name);
+ JcrPropertyDefinitionTemplate dateDefn = new JcrPropertyDefinitionTemplate(context);
+ dateDefn.setName("dateProperty");
+ dateDefn.setRequiredType(PropertyType.DATE);
+ propDefns.add(dateDefn);
+
+ JcrPropertyDefinitionTemplate doubleDefn = new JcrPropertyDefinitionTemplate(context);
+ doubleDefn.setName("doubleProperty");
+ doubleDefn.setRequiredType(PropertyType.DOUBLE);
+ propDefns.add(doubleDefn);
+
+ JcrPropertyDefinitionTemplate longDefn = new JcrPropertyDefinitionTemplate(context);
+ longDefn.setName("longProperty");
+ longDefn.setRequiredType(PropertyType.LONG);
+ propDefns.add(longDefn);
+
+ JcrPropertyDefinitionTemplate nameDefn = new JcrPropertyDefinitionTemplate(context);
+ nameDefn.setName("nameProperty");
+ nameDefn.setRequiredType(PropertyType.NAME);
+ propDefns.add(nameDefn);
+
+ JcrPropertyDefinitionTemplate pathDefn = new JcrPropertyDefinitionTemplate(context);
+ pathDefn.setName("pathProperty");
+ pathDefn.setRequiredType(PropertyType.PATH);
+ propDefns.add(pathDefn);
+
+ JcrPropertyDefinitionTemplate refDefn = new JcrPropertyDefinitionTemplate(context);
+ refDefn.setName("referenceProperty");
+ refDefn.setRequiredType(PropertyType.REFERENCE);
+ propDefns.add(refDefn);
+
+ JcrPropertyDefinitionTemplate stringDefn = new JcrPropertyDefinitionTemplate(context);
+ stringDefn.setName("stringProperty");
+ stringDefn.setRequiredType(PropertyType.STRING);
+ propDefns.add(stringDefn);
+
+ JcrPropertyDefinitionTemplate undefinedDefn = new JcrPropertyDefinitionTemplate(context);
+ undefinedDefn.setName("undefinedProperty");
+ undefinedDefn.setRequiredType(PropertyType.UNDEFINED);
+ propDefns.add(undefinedDefn);
+
+ // Add the node type ...
+ Collection<NodeTypeDefinition> defns = new ArrayList<NodeTypeDefinition>();
+ defns.add(nodeType);
+ rntm.registerNodeTypes(defns, false);
}
- @Test
- public void shouldProvideBoolean() throws Exception {
- stub(propertyInfo.getPropertyType()).toReturn(PropertyType.BOOLEAN);
- dnaProperty = executionContext.getPropertyFactory().create(JcrLexicon.MIMETYPE, "true");
- stub(propertyInfo.getProperty()).toReturn(dnaProperty);
- assertThat(prop.getBoolean(), is(true));
- assertThat(prop.getType(), is(PropertyType.BOOLEAN));
+ @Override
+ @Before
+ public void beforeEach() throws Exception {
+ super.beforeEach();
+ context.getNamespaceRegistry().register("acme", "http://example.com");
+ stringFactory = context.getValueFactories().getStringFactory();
+
+ binaryValue = "This is a binary value".getBytes();
+ dateValue = context.getValueFactories().getDateFactory().create();
+ doubleValue = 3.14159d;
+ longValue = 100L;
+ booleanValue = true;
+ stringValue = "stringValue";
+ nameValue = "acme:SomeName";
+ pathValue = "/Cars/Hybrid/Toyota Highlander/acme:SomethingElse";
+
+ // Add the mixin to the 'Cars' node ...
+ cars = cache.findJcrNode(null, path("/Cars"));
+ cars.addMixin("mixinWithAllPropTypes");
+
+ altima = cache.findJcrNode(null, path("/Cars/Hybrid/Nissan Altima"));
+ altima.addMixin("mix:referenceable");
+
+ // Set each property ...
+ cars.setProperty("booleanProperty", booleanValue);
+ cars.setProperty("dateProperty", dateValue.toCalendar());
+ cars.setProperty("doubleProperty", doubleValue);
+ cars.setProperty("binaryProperty", new ByteArrayInputStream(binaryValue));
+ cars.setProperty("longProperty", longValue);
+ cars.setProperty("referenceProperty", altima);
+ cars.setProperty("stringProperty", stringValue);
+ cars.setProperty("pathProperty", pathValue);
+ cars.setProperty("nameProperty", nameValue);
+ cars.setProperty("undefinedProperty", "100");
}
@Test
public void shouldIndicateHasSingleValue() throws Exception {
+ prop = cars.getProperty("booleanProperty");
PropertyDefinition def = prop.getDefinition();
assertThat(def.isMultiple(), is(false));
}
@Test
+ public void shouldProvideBoolean() throws Exception {
+ prop = cars.getProperty("booleanProperty");
+ assertThat(prop.getBoolean(), is(booleanValue));
+ assertThat(prop.getType(), is(PropertyType.BOOLEAN));
+ assertThat(prop.getString(), is(stringFactory.create(booleanValue)));
+ assertThat(prop.getLength(), is((long)stringFactory.create(booleanValue).length()));
+ checkValue(prop);
+ }
+
+ @Test
public void shouldProvideDate() throws Exception {
- DateTime dnaDate = executionContext.getValueFactories().getDateFactory().create();
- dnaProperty = executionContext.getPropertyFactory().create(JcrLexicon.MIMETYPE, dnaDate);
- stub(propertyInfo.getProperty()).toReturn(dnaProperty);
- stub(propertyInfo.getPropertyType()).toReturn(PropertyType.DATE);
- assertThat(prop.getDate(), is(dnaDate.toCalendar()));
- assertThat(prop.getLong(), is(dnaDate.getMilliseconds()));
+ prop = cars.getProperty("dateProperty");
+ assertThat(prop.getDate(), is(dateValue.toCalendar()));
+ assertThat(prop.getLong(), is(dateValue.getMilliseconds()));
+ assertThat(prop.getString(), is(stringFactory.create(dateValue)));
assertThat(prop.getType(), is(PropertyType.DATE));
- assertThat(prop.getName(), is(dnaProperty.getName().getString(executionContext.getNamespaceRegistry())));
+ assertThat(prop.getLength(), is((long)stringFactory.create(dateValue).length()));
+ checkValue(prop);
}
@Test
public void shouldProvideNode() throws Exception {
- UUID referencedUuid = UUID.randomUUID();
- dnaProperty = executionContext.getPropertyFactory().create(JcrLexicon.MIMETYPE, referencedUuid);
- stub(propertyInfo.getProperty()).toReturn(dnaProperty);
- stub(propertyInfo.getPropertyType()).toReturn(PropertyType.REFERENCE);
- AbstractJcrNode referencedNode = mock(AbstractJcrNode.class);
- stub(cache.findJcrNode(referencedUuid)).toReturn(referencedNode);
- assertThat(prop.getNode(), is((Node)referencedNode));
+ prop = cars.getProperty("referenceProperty");
+ assertThat(prop.getNode(), is((Node)altima));
assertThat(prop.getType(), is(PropertyType.REFERENCE));
- assertThat(prop.getName(), is(dnaProperty.getName().getString(executionContext.getNamespaceRegistry())));
+ assertThat(prop.getString(), is(altima.getUUID()));
+ assertThat(prop.getLength(), is((long)altima.getUUID().length()));
+ checkValue(prop);
}
@Test
public void shouldProvideDouble() throws Exception {
- dnaProperty = executionContext.getPropertyFactory().create(JcrLexicon.MIMETYPE, 1.0);
- stub(propertyInfo.getProperty()).toReturn(dnaProperty);
- stub(propertyInfo.getPropertyType()).toReturn(PropertyType.DOUBLE);
- assertThat(prop.getDouble(), is(1.0));
+ prop = cars.getProperty("doubleProperty");
+ assertThat(prop.getDouble(), is(doubleValue));
+ assertThat(prop.getString(), is(stringFactory.create(doubleValue)));
assertThat(prop.getType(), is(PropertyType.DOUBLE));
- assertThat(prop.getName(), is(dnaProperty.getName().getString(executionContext.getNamespaceRegistry())));
- dnaProperty = executionContext.getPropertyFactory().create(JcrLexicon.MIMETYPE, 1.0F);
- stub(propertyInfo.getProperty()).toReturn(dnaProperty);
- assertThat(prop.getDouble(), is(1.0));
- assertThat(prop.getType(), is(PropertyType.DOUBLE));
- assertThat(prop.getName(), is(dnaProperty.getName().getString(executionContext.getNamespaceRegistry())));
+ assertThat(prop.getLength(), is((long)stringFactory.create(doubleValue).length()));
+ checkValue(prop);
}
@Test
public void shouldProvideLong() throws Exception {
- dnaProperty = executionContext.getPropertyFactory().create(JcrLexicon.MIMETYPE, 1);
- stub(propertyInfo.getProperty()).toReturn(dnaProperty);
- stub(propertyInfo.getPropertyType()).toReturn(PropertyType.LONG);
- assertThat(prop.getLong(), is(1L));
+ prop = cars.getProperty("longProperty");
+ assertThat(prop.getLong(), is(longValue));
+ assertThat(prop.getString(), is(stringFactory.create(longValue)));
assertThat(prop.getType(), is(PropertyType.LONG));
- assertThat(prop.getName(), is(dnaProperty.getName().getString(executionContext.getNamespaceRegistry())));
-
- dnaProperty = executionContext.getPropertyFactory().create(JcrLexicon.MIMETYPE, 1L);
- stub(propertyInfo.getProperty()).toReturn(dnaProperty);
- stub(propertyInfo.getPropertyType()).toReturn(PropertyType.LONG);
- assertThat(prop.getLong(), is(1L));
- assertThat(prop.getString(), is("1"));
- assertThat(prop.getType(), is(PropertyType.LONG));
- assertThat(prop.getName(), is(dnaProperty.getName().getString(executionContext.getNamespaceRegistry())));
+ assertThat(prop.getLength(), is((long)stringFactory.create(longValue).length()));
+ checkValue(prop);
}
@Test
public void shouldProvideStream() throws Exception {
- dnaProperty = executionContext.getPropertyFactory().create(JcrLexicon.MIMETYPE, new Object());
- stub(propertyInfo.getProperty()).toReturn(dnaProperty);
- stub(propertyInfo.getPropertyType()).toReturn(PropertyType.BINARY);
+ prop = cars.getProperty("binaryProperty");
assertThat(prop.getType(), is(PropertyType.BINARY));
- assertThat(prop.getName(), is(dnaProperty.getName().getString(executionContext.getNamespaceRegistry())));
InputStream stream = prop.getStream();
try {
assertThat(stream, notNullValue());
@@ -185,95 +239,62 @@
stream.close();
}
}
+ assertThat(prop.getString(), is(stringFactory.create(binaryValue)));
+ assertThat(prop.getLength(), is((long)binaryValue.length)); // note this value!!
+ checkValue(prop);
}
@Test
public void shouldProvideString() throws Exception {
- dnaProperty = executionContext.getPropertyFactory().create(JcrLexicon.MIMETYPE, "value");
- stub(propertyInfo.getProperty()).toReturn(dnaProperty);
- stub(propertyInfo.getPropertyType()).toReturn(PropertyType.STRING);
- assertThat(prop.getString(), is("value"));
+ prop = cars.getProperty("stringProperty");
+ assertThat(prop.getString(), is(stringValue));
assertThat(prop.getType(), is(PropertyType.STRING));
- assertThat(prop.getName(), is(dnaProperty.getName().getString(executionContext.getNamespaceRegistry())));
+ assertThat(prop.getLength(), is((long)stringValue.length()));
+ checkValue(prop);
}
@Test
- public void shouldAllowReferenceValue() throws Exception {
- UUID uuid = UUID.randomUUID();
- dnaProperty = executionContext.getPropertyFactory().create(JcrLexicon.MIMETYPE, uuid);
- stub(propertyInfo.getProperty()).toReturn(dnaProperty);
- stub(propertyInfo.getPropertyType()).toReturn(PropertyType.STRING);
- assertThat(prop.getString(), is(uuid.toString()));
- assertThat(prop.getType(), is(PropertyType.STRING));
- assertThat(prop.getName(), is(dnaProperty.getName().getString(executionContext.getNamespaceRegistry())));
- }
-
- @Test
public void shouldAllowNameValue() throws Exception {
- executionContext.getNamespaceRegistry().register("acme", "http://example.com");
- Name path = executionContext.getValueFactories().getNameFactory().create("acme:something");
- dnaProperty = executionContext.getPropertyFactory().create(JcrLexicon.MIMETYPE, path);
- stub(propertyInfo.getProperty()).toReturn(dnaProperty);
- stub(propertyInfo.getPropertyType()).toReturn(PropertyType.NAME);
- assertThat(prop.getString(), is("acme:something"));
+ prop = cars.getProperty("nameProperty");
assertThat(prop.getType(), is(PropertyType.NAME));
- assertThat(prop.getName(), is(dnaProperty.getName().getString(executionContext.getNamespaceRegistry())));
+ assertThat(prop.getString(), is(nameValue));
+ assertThat(prop.getLength(), is((long)nameValue.length()));
// Change the namespace registry ...
- executionContext.getNamespaceRegistry().register("acme2", "http://example.com");
- assertThat(prop.getString(), is("acme2:something"));
+ context.getNamespaceRegistry().register("acme2", "http://example.com");
+ assertThat(prop.getString(), is("acme2:SomeName"));
+ checkValue(prop);
}
@Test
public void shouldAllowPathValue() throws Exception {
- executionContext.getNamespaceRegistry().register("acme", "http://example.com");
- Path path = executionContext.getValueFactories().getPathFactory().create("/a/b/acme:c");
- dnaProperty = executionContext.getPropertyFactory().create(JcrLexicon.MIMETYPE, (Object)path);
- stub(propertyInfo.getProperty()).toReturn(dnaProperty);
- stub(propertyInfo.getPropertyType()).toReturn(PropertyType.PATH);
- assertThat(prop.getString(), is("/a/b/acme:c"));
+ prop = cars.getProperty("pathProperty");
assertThat(prop.getType(), is(PropertyType.PATH));
- assertThat(prop.getName(), is(dnaProperty.getName().getString(executionContext.getNamespaceRegistry())));
+ assertThat(prop.getString(), is(pathValue));
// Change the namespace registry ...
- executionContext.getNamespaceRegistry().register("acme2", "http://example.com");
- assertThat(prop.getString(), is("/a/b/acme2:c"));
+ context.getNamespaceRegistry().register("acme2", "http://example.com");
+ assertThat(prop.getString(), is("/Cars/Hybrid/Toyota Highlander/acme2:SomethingElse"));
+ checkValue(prop);
}
- @Test
- public void shouldProvideValue() throws Exception {
+ public void checkValue( Property prop ) throws Exception {
+ // Should provide a value and not multiple values ...
Value val = prop.getValue();
assertThat(val, notNullValue());
- }
+ assertThat(prop.getDefinition(), notNullValue());
- @Test( expected = ValueFormatException.class )
- public void shouldNotProvideValues() throws Exception {
- prop.getValues();
+ // Should not allow multiple-value methods ...
+ try {
+ prop.getValues();
+ fail("Should not be able to call 'getValues()' on a single-value property");
+ } catch (ValueFormatException e) {
+ // expected
+ }
+ try {
+ prop.getLengths();
+ fail("Should not be able to call 'getValues()' on a single-value property");
+ } catch (ValueFormatException e) {
+ // expected
+ }
}
- @Test
- public void shouldProvideLength() throws Exception {
- String dnaValue = executionContext.getValueFactories().getStringFactory().create(dnaProperty.getFirstValue());
- assertThat(prop.getLength(), is((long)dnaValue.length()));
-
- dnaValue = "some other value";
- dnaProperty = executionContext.getPropertyFactory().create(JcrLexicon.MIMETYPE, dnaValue);
- stub(propertyInfo.getProperty()).toReturn(dnaProperty);
- assertThat(prop.getLength(), is((long)dnaValue.length()));
-
- Object obj = new Object();
- long binaryLength = executionContext.getValueFactories().getBinaryFactory().create(obj).getSize();
- dnaProperty = executionContext.getPropertyFactory().create(JcrLexicon.MIMETYPE, obj);
- stub(propertyInfo.getProperty()).toReturn(dnaProperty);
- assertThat(prop.getLength(), is(binaryLength));
- }
-
- @Test( expected = ValueFormatException.class )
- public void shouldNotProvideLengths() throws Exception {
- prop.getLengths();
- }
-
- @Test
- public void shouldProvidePropertyDefinition() throws Exception {
- assertThat(prop.getDefinition(), notNullValue());
- }
-
}
Modified: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/SessionCacheTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/SessionCacheTest.java 2009-07-09 16:23:09 UTC (rev 1081)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/SessionCacheTest.java 2009-07-09 16:26:04 UTC (rev 1082)
@@ -23,753 +23,599 @@
*/
package org.jboss.dna.jcr;
-import static javax.jcr.PropertyType.DOUBLE;
-import static javax.jcr.PropertyType.LONG;
-import static javax.jcr.PropertyType.STRING;
-import static javax.jcr.PropertyType.UNDEFINED;
-import static org.hamcrest.core.Is.is;
-import static org.hamcrest.core.IsNull.notNullValue;
-import static org.hamcrest.core.IsNull.nullValue;
-import static org.hamcrest.core.IsSame.sameInstance;
-import static org.jboss.dna.graph.IsNodeWithChildren.hasChildren;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.fail;
-import static org.junit.matchers.JUnitMatchers.hasItems;
-import static org.mockito.Mockito.stub;
-import java.io.File;
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.UUID;
-import javax.jcr.InvalidItemStateException;
-import javax.jcr.RepositoryException;
-import javax.jcr.nodetype.ConstraintViolationException;
-import org.jboss.dna.common.statistic.Stopwatch;
-import org.jboss.dna.common.util.StringUtil;
-import org.jboss.dna.graph.ExecutionContext;
-import org.jboss.dna.graph.Graph;
-import org.jboss.dna.graph.Location;
-import org.jboss.dna.graph.Node;
-import org.jboss.dna.graph.Graph.Children;
-import org.jboss.dna.graph.connector.inmemory.InMemoryRepositorySource;
-import org.jboss.dna.graph.property.Name;
-import org.jboss.dna.graph.property.Path;
-import org.jboss.dna.graph.property.PathNotFoundException;
-import org.jboss.dna.graph.property.Property;
-import org.jboss.dna.graph.property.ValueFactory;
-import org.jboss.dna.jcr.SessionCache.NodeEditor;
-import org.jboss.dna.jcr.Vehicles.Lexicon;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.MockitoAnnotations;
-import org.mockito.MockitoAnnotations.Mock;
-import org.xml.sax.SAXException;
+public class SessionCacheTest extends AbstractJcrTest {
-/**
- *
- */
-public class SessionCacheTest {
-
- private ExecutionContext context;
- private RepositoryNodeTypeManager repoTypes;
- private JcrNodeTypeManager nodeTypes;
- private Stopwatch sw;
- private Graph store;
- private SessionCache cache;
- private Map<String, Graph> storesByName;
- private Map<String, SessionCache> cachesByName;
-
- @Mock
- private JcrSession session;
-
- @Before
- public void beforeEach() throws Exception {
- MockitoAnnotations.initMocks(this);
- sw = new Stopwatch();
- storesByName = new HashMap<String, Graph>();
- cachesByName = new HashMap<String, SessionCache>();
-
- context = new ExecutionContext();
- context.getNamespaceRegistry().register(Vehicles.Lexicon.Namespace.PREFIX, Vehicles.Lexicon.Namespace.URI);
-
- stub(session.getExecutionContext()).toReturn(context);
- stub(session.namespaces()).toReturn(context.getNamespaceRegistry());
-
- // Load up all the node types ...
- repoTypes = new RepositoryNodeTypeManager(context);
- try {
- this.repoTypes.registerNodeTypes(new CndNodeTypeSource(new String[] {"/org/jboss/dna/jcr/jsr_170_builtins.cnd",
- "/org/jboss/dna/jcr/dna_builtins.cnd"}));
- this.repoTypes.registerNodeTypes(new NodeTemplateNodeTypeSource(Vehicles.getNodeTypes(context)));
- } catch (RepositoryException re) {
- re.printStackTrace();
- throw new IllegalStateException("Could not load node type definition files", re);
- } catch (IOException ioe) {
- ioe.printStackTrace();
- throw new IllegalStateException("Could not access node type definition files", ioe);
- }
-
- nodeTypes = new JcrNodeTypeManager(this.session, repoTypes);
- stub(session.nodeTypeManager()).toReturn(nodeTypes);
-
- // Now set up the graph and session cache ...
- store = getGraph("vehicles"); // imports the "/src/test/resources/vehicles.xml" file
- cache = getCache("vehicles");
- }
-
- protected Graph createFrom( String repositoryName,
- String workspaceName,
- File file ) throws IOException, SAXException {
- InMemoryRepositorySource source = new InMemoryRepositorySource();
- source.setName(repositoryName);
- Graph graph = Graph.create(source, context);
- graph.createWorkspace().named(workspaceName);
-
- if (file != null) {
- graph.importXmlFrom(file).into("/");
- }
- return graph;
- }
-
- protected Graph getGraph( String name ) throws IOException, SAXException {
- Graph graph = storesByName.get(name);
- if (graph == null) {
- graph = createFrom(name, name + " workspace", new File("src/test/resources/" + name + ".xml"));
- storesByName.put(name, graph);
- }
- return graph;
- }
-
- protected SessionCache getCache( String name ) throws IOException, SAXException {
- SessionCache cache = cachesByName.get(name);
- if (cache == null) {
- cache = new SessionCache(session, name + " workspace", context, nodeTypes, getGraph(name));
- cachesByName.put(name, cache);
- }
- return cache;
- }
-
- protected Name name( String name ) {
- return context.getValueFactories().getNameFactory().create(name);
- }
-
- protected Path path( String path ) {
- return context.getValueFactories().getPathFactory().create(path);
- }
-
- protected Path.Segment segment( String segment ) {
- return context.getValueFactories().getPathFactory().createSegment(segment);
- }
-
- protected String pad( String name ) {
- return StringUtil.justifyLeft(name, 22, ' ');
- }
-
- protected void assertSameProperties( NodeInfo nodeInfo,
- Node dnaNode ) {
- UUID uuid = dnaNode.getLocation().getUuid();
- assertThat(nodeInfo.getUuid(), is(uuid));
- assertThat(nodeInfo.getOriginalLocation().getUuid(), is(uuid));
- Set<Name> propertyNames = nodeInfo.getPropertyNames();
- for (Name propertyName : propertyNames) {
- PropertyInfo info = nodeInfo.getProperty(propertyName);
- assertThat(info.getNodeUuid(), is(uuid));
- assertThat(info.getPropertyId().getNodeId(), is(uuid));
- assertThat(info.getPropertyId().getPropertyName(), is(propertyName));
- assertThat(info.getProperty().getName(), is(propertyName));
- Property actual = dnaNode.getProperty(propertyName);
- if (actual != null) {
- assertThat(info.getProperty().size(), is(actual.size()));
- assertThat(info.getProperty().getValuesAsArray(), is(actual.getValuesAsArray()));
- } else {
- if (propertyName.equals(JcrLexicon.UUID)) {
- // check for a DNA UUID property ...
- actual = dnaNode.getProperty(DnaLexicon.UUID);
- if (actual != null) {
- assertThat(info.getProperty().size(), is(actual.size()));
- assertThat(info.getProperty().getValuesAsArray(), is(actual.getValuesAsArray()));
- } else {
- fail("missing property \"" + propertyName + "\" on " + dnaNode);
- }
- } else if (propertyName.equals(JcrLexicon.PRIMARY_TYPE)) {
- // This is okay
- } else if (propertyName.equals(DnaIntLexicon.MULTI_VALUED_PROPERTIES)) {
- // This is okay
- } else {
- fail("missing property \"" + propertyName + "\" on " + dnaNode);
- }
- }
- }
- }
-
- protected JcrValue value( int propertyType,
- Object value ) {
- return new JcrValue(context.getValueFactories(), cache, propertyType, value);
- }
-
- protected void assertDoesExist( Graph graph,
- Location location ) {
- Node node = store.getNodeAt(location);
- assertThat(node, is(notNullValue()));
- assertThat(node.getLocation(), is(location));
- }
-
- protected void assertDoesNotExist( Graph graph,
- Location location ) {
- try {
- store.getNodeAt(location);
- fail("Shouldn't have found the node " + location);
- } catch (PathNotFoundException e) {
- // expected
- }
- }
-
- protected void assertDoesNotExist( Graph graph,
- Path path ) {
- try {
- store.getNodeAt(path);
- fail("Shouldn't have found the node " + path);
- } catch (PathNotFoundException e) {
- // expected
- }
- }
-
- protected void assertDoesNotExist( Graph graph,
- UUID uuid ) {
- try {
- store.getNodeAt(uuid);
- fail("Shouldn't have found the node " + uuid);
- } catch (PathNotFoundException e) {
- // expected
- }
- }
-
- protected void assertDoNotExist( Graph graph,
- List<Location> locations ) {
- for (Location location : locations)
- assertDoesNotExist(graph, location);
- }
-
- protected void assertDoesNotExist( SessionCache cache,
- UUID uuid ) throws InvalidItemStateException {
- assertThat(cache.findNodeInfoInCache(uuid), is(nullValue()));
- }
-
- protected void assertIsDeleted( SessionCache cache,
- UUID uuid ) {
- try {
- cache.findNodeInfoInCache(uuid);
- fail("Shouldn't have found the node " + uuid);
- } catch (InvalidItemStateException err) {
- // expected
- }
- }
-
- protected void assertDoesExist( SessionCache cache,
- UUID uuid ) throws InvalidItemStateException {
- NodeInfo info = cache.findNodeInfoInCache(uuid);
- assertThat(info, is(notNullValue()));
- assertThat(info.getUuid(), is(uuid));
- }
-
- protected void assertProperty( NodeInfo info,
- Name propertyName,
- int type,
- Name nodeTypeName,
- Name propertyDefinitionName,
- int definitionType,
- Object value ) {
- PropertyDefinitionId defnId = new PropertyDefinitionId(nodeTypeName, propertyDefinitionName, definitionType, false);
- PropertyInfo propertyInfo = info.getProperty(propertyName);
- assertThat(propertyInfo, is(notNullValue()));
- assertThat(propertyInfo.getPropertyType(), is(type));
- assertThat(propertyInfo.getDefinitionId(), is(defnId));
- org.jboss.dna.graph.property.PropertyType dnaPropertyType = PropertyTypeUtil.dnaPropertyTypeFor(type);
- // Check the value ...
- ValueFactory<?> factory = context.getValueFactories().getValueFactory(dnaPropertyType);
- Object actual = factory.create(propertyInfo.getProperty().getFirstValue());
- assertThat(actual, is(value));
- }
-
- protected void assertProperty( NodeInfo info,
- Name propertyName,
- int type,
- Name nodeTypeName,
- Name propertyDefinitionName,
- int definitionType,
- Object... values ) {
- PropertyDefinitionId defnId = new PropertyDefinitionId(nodeTypeName, propertyDefinitionName, definitionType, true);
- PropertyInfo propertyInfo = info.getProperty(propertyName);
- assertThat(propertyInfo, is(notNullValue()));
- assertThat(propertyInfo.getPropertyType(), is(type));
- assertThat(propertyInfo.getDefinitionId(), is(defnId));
- org.jboss.dna.graph.property.PropertyType dnaPropertyType = PropertyTypeUtil.dnaPropertyTypeFor(type);
- // Check the values ...
- ValueFactory<?> factory = context.getValueFactories().getValueFactory(dnaPropertyType);
- int i = 0;
- for (Object value : propertyInfo.getProperty()) {
- assertThat(factory.create(value), is(values[i++]));
- }
- }
-
- protected void assertNoProperty( NodeInfo info,
- Name propertyName ) {
- PropertyInfo propertyInfo = info.getProperty(propertyName);
- assertThat(propertyInfo, is(nullValue()));
- }
-
- @Test
- public void shouldCreateWithValidParameters() {
- assertThat(cache, is(notNullValue()));
- }
-
- @Test
- public void shouldFindNodeInfoForRootByUuid() throws Exception {
- Node root = store.getNodeAt("/");
- UUID rootUuid = root.getLocation().getUuid();
- NodeInfo rootInfo = cache.findNodeInfo(rootUuid);
- assertThat(rootInfo, is(notNullValue()));
- assertThat(rootInfo.getUuid(), is(rootUuid));
- assertThat(rootInfo.getDefinitionId().getNodeTypeName(), is(name("dna:root")));
- assertThat(rootInfo.getDefinitionId().getChildDefinitionName(), is(name("*")));
- assertThat(rootInfo.getPrimaryTypeName(), is(name("dna:root")));
- assertThat(rootInfo.getOriginalLocation().getPath().isRoot(), is(true));
- assertThat(rootInfo.getOriginalLocation().getUuid(), is(rootUuid));
- Set<Name> rootProperties = rootInfo.getPropertyNames();
- assertThat(rootProperties, hasItems(name("jcr:primaryType")));
- assertSameProperties(rootInfo, root);
-
- PropertyInfo info = rootInfo.getProperty(JcrLexicon.PRIMARY_TYPE);
- assertThat(info.getProperty().getFirstValue(), is((Object)name("dna:root")));
- }
-
- @Test
- public void shouldRepeatedlyFindRootNodeInfoByUuid() throws Exception {
- Node root = store.getNodeAt("/");
- UUID rootUuid = root.getLocation().getUuid();
- for (int i = 0; i != 20; ++i) {
- NodeInfo rootInfo = cache.findNodeInfo(rootUuid);
- assertThat(rootInfo, is(notNullValue()));
- }
- }
-
- @Test
- public void shouldRepeatedlyFindRootNodeInfoByPath() throws Exception {
- String sourceName = "cars";
- Graph store = getGraph(sourceName);
- SessionCache cache = getCache(sourceName);
- Node root = store.getNodeAt("/");
- UUID rootUuid = root.getLocation().getUuid();
- NodeInfo nodeInfo = cache.findNodeInfoForRoot();
- assertThat(nodeInfo.getUuid(), is(rootUuid));
- for (int i = 0; i != 20; ++i) {
- sw.start();
- assertThat(nodeInfo, is(sameInstance(cache.findNodeInfoForRoot())));
- sw.stop();
- assertThat(nodeInfo, is(sameInstance(cache.findNodeInfo(rootUuid))));
- }
- // System.out.println(pad(sourceName) + " ==> " + sw.getSimpleStatistics());
- }
-
- @Test
- public void shouldRepeatedlyFindRootNodeInfoByUuidFromVehiclesSource() throws Exception {
- String sourceName = "vehicles";
- Graph store = getGraph(sourceName);
- SessionCache cache = getCache(sourceName);
- sw.start();
- Node root = store.getNodeAt("/");
- sw.stop();
- UUID rootUuid = root.getLocation().getUuid();
- for (int i = 0; i != 20; ++i) {
- sw.start();
- NodeInfo rootInfo = cache.findNodeInfo(rootUuid);
- sw.stop();
- assertThat(rootInfo, is(notNullValue()));
- }
- // System.out.println(pad(sourceName) + " ==> " + sw.getSimpleStatistics());
- }
-
- @Test
- public void shouldRepeatedlyFindRootNodeInfoByUuidFromSourceWithPrimaryTypes() throws Exception {
- String sourceName = "repositoryForTckTests";
- Graph store = getGraph(sourceName);
- SessionCache cache = getCache(sourceName);
- sw.start();
- Node root = store.getNodeAt("/");
- sw.stop();
- UUID rootUuid = root.getLocation().getUuid();
- for (int i = 0; i != 20; ++i) {
- sw.start();
- NodeInfo rootInfo = cache.findNodeInfo(rootUuid);
- sw.stop();
- assertThat(rootInfo, is(notNullValue()));
- }
- // System.out.println(pad(sourceName) + " ==> " + sw.getSimpleStatistics());
- }
-
- @Test
- public void shouldFindChildrenInNodeInfoForRoot() throws Exception {
- NodeInfo root = cache.findNodeInfoForRoot();
- Children children = root.getChildren();
- assertThat(children, is(notNullValue()));
- assertThat(children.size(), is(1));
- assertThat(children.getChild(segment("vehix:Vehicles")), is(notNullValue()));
- }
-
- @Test
- public void shouldFindNodeInfoForNonRootNodeByPath() throws Exception {
- String sourceName = "vehicles";
- Graph store = getGraph(sourceName);
- SessionCache cache = getCache(sourceName);
- // Get the root ...
- NodeInfo root = cache.findNodeInfoForRoot();
-
- // Now try to load a node that is well-below the root ...
- Path lr3Path = path("/vehix:Vehicles/vehix:Cars/vehix:Utility/vehix:Land Rover LR3");
- Node lr3Node = store.getNodeAt(lr3Path);
- sw.start();
- NodeInfo lr3 = cache.findNodeInfo(root.getUuid(), lr3Path);
- sw.stop();
- assertThat(lr3.getUuid(), is(lr3Node.getLocation().getUuid()));
- assertSameProperties(lr3, lr3Node);
- // System.out.println(pad(sourceName) + " ==> " + sw.getSimpleStatistics());
-
- // Verify that this loaded all the intermediate nodes, by walking up ...
- NodeInfo info = lr3;
- while (true) {
- UUID parent = info.getParent();
- if (parent == null) {
- // then we should be at the root ...
- assertThat(info.getUuid(), is(root.getUuid()));
- break;
- }
- // Otherwise, we're not at the root, so we should find the parent ...
- info = cache.findNodeInfoInCache(parent);
- assertThat(info, is(notNullValue()));
- }
- }
-
- @Test
- public void shouldFindInfoForNodeUsingRelativePathFromRoot() throws Exception {
- String sourceName = "vehicles";
- Graph store = getGraph(sourceName);
- SessionCache cache = getCache(sourceName);
-
- // Verify that the node does exist in the source ...
- Path lr3AbsolutePath = path("/vehix:Vehicles/vehix:Cars/vehix:Utility/vehix:Land Rover LR3");
- Node lr3Node = store.getNodeAt(lr3AbsolutePath);
-
- // Get the root ...
- NodeInfo root = cache.findNodeInfoForRoot();
-
- // Now try to load a node that is well-below the root ...
- Path lr3Path = path("vehix:Vehicles/vehix:Cars/vehix:Utility/vehix:Land Rover LR3");
- assertThat(lr3Path.isAbsolute(), is(false));
- NodeInfo lr3 = cache.findNodeInfo(root.getUuid(), lr3Path);
- assertThat(lr3.getUuid(), is(lr3Node.getLocation().getUuid()));
- assertSameProperties(lr3, lr3Node);
-
- Path recoveredPath = cache.getPathFor(lr3);
- assertThat(recoveredPath, is(lr3AbsolutePath));
- }
-
- @Test
- public void shouldFindInfoForNodeUsingRelativePathFromNonRoot() throws Exception {
- // Verify that the node does exist in the source ...
- Path carsAbsolutePath = path("/vehix:Vehicles/vehix:Cars");
- Node carsNode = store.getNodeAt(carsAbsolutePath);
- Path lr3AbsolutePath = path("/vehix:Vehicles/vehix:Cars/vehix:Utility/vehix:Land Rover LR3");
- Node lr3Node = store.getNodeAt(lr3AbsolutePath);
- Path b787AbsolutePath = path("/vehix:Vehicles/vehix:Aircraft/vehix:Commercial/vehix:Boeing 787");
- Node b787Node = store.getNodeAt(b787AbsolutePath);
-
- // Get the root ...
- NodeInfo root = cache.findNodeInfoForRoot();
-
- // Now try to load the cars node ...
- Path carsPath = path("vehix:Vehicles/vehix:Cars");
- assertThat(carsPath.isAbsolute(), is(false));
- NodeInfo cars = cache.findNodeInfo(root.getUuid(), carsPath);
- assertThat(cars.getUuid(), is(carsNode.getLocation().getUuid()));
- assertSameProperties(cars, carsNode);
-
- // Now try to find the LR3 node relative to the car ...
- Path lr3Path = path("vehix:Utility/vehix:Land Rover LR3");
- assertThat(lr3Path.isAbsolute(), is(false));
- NodeInfo lr3 = cache.findNodeInfo(cars.getUuid(), lr3Path);
- assertThat(lr3.getUuid(), is(lr3Node.getLocation().getUuid()));
- assertSameProperties(lr3, lr3Node);
-
- // Now try to find the "Boeing 787" node relative to the LR3 node ...
- Path b787Path = path("../../../vehix:Aircraft/vehix:Commercial/vehix:Boeing 787");
- assertThat(b787Path.isAbsolute(), is(false));
- assertThat(b787Path.isNormalized(), is(true));
- NodeInfo b787 = cache.findNodeInfo(lr3.getUuid(), b787Path);
- assertThat(b787.getUuid(), is(b787Node.getLocation().getUuid()));
- assertSameProperties(b787, b787Node);
-
- assertThat(cache.getPathFor(cars), is(carsAbsolutePath));
- assertThat(cache.getPathFor(lr3), is(lr3AbsolutePath));
- assertThat(cache.getPathFor(b787), is(b787AbsolutePath));
- }
-
- @Test
- public void shouldFindJcrNodeUsingAbsolutePaths() throws Exception {
- // Verify that the node does exist in the source ...
- Path carsAbsolutePath = path("/vehix:Vehicles/vehix:Cars");
- Node carsNode = store.getNodeAt(carsAbsolutePath);
- Path lr3AbsolutePath = path("/vehix:Vehicles/vehix:Cars/vehix:Utility/vehix:Land Rover LR3");
- Node lr3Node = store.getNodeAt(lr3AbsolutePath);
- Path b787AbsolutePath = path("/vehix:Vehicles/vehix:Aircraft/vehix:Commercial/vehix:Boeing 787");
- Node b787Node = store.getNodeAt(b787AbsolutePath);
-
- // Get the root ...
- NodeInfo root = cache.findNodeInfoForRoot();
-
- // Now try to load the cars node ...
- Path carsPath = path("vehix:Vehicles/vehix:Cars");
- assertThat(carsPath.isAbsolute(), is(false));
- AbstractJcrNode carJcrNode = cache.findJcrNode(root.getUuid(), carsAbsolutePath);
- assertThat(carJcrNode.internalUuid(), is(carsNode.getLocation().getUuid()));
- NodeInfo cars = cache.findNodeInfo(root.getUuid(), carsPath);
- assertThat(cars.getUuid(), is(carsNode.getLocation().getUuid()));
- assertSameProperties(cars, carsNode);
-
- // Now try to find the LR3 node relative to the car ...
- Path lr3Path = path("vehix:Utility/vehix:Land Rover LR3");
- assertThat(lr3Path.isAbsolute(), is(false));
- AbstractJcrNode lr3JcrNode = cache.findJcrNode(root.getUuid(), lr3AbsolutePath);
- assertThat(lr3JcrNode.internalUuid(), is(lr3Node.getLocation().getUuid()));
- NodeInfo lr3 = cache.findNodeInfo(cars.getUuid(), lr3Path);
- assertThat(lr3.getUuid(), is(lr3Node.getLocation().getUuid()));
- assertSameProperties(lr3, lr3Node);
-
- // Now try to find the "Boeing 787" node relative to the LR3 node ...
- Path b787Path = path("../../../vehix:Aircraft/vehix:Commercial/vehix:Boeing 787");
- assertThat(b787Path.isAbsolute(), is(false));
- assertThat(b787Path.isNormalized(), is(true));
- AbstractJcrNode b787JcrNode = cache.findJcrNode(root.getUuid(), b787AbsolutePath);
- assertThat(b787JcrNode.internalUuid(), is(b787Node.getLocation().getUuid()));
- NodeInfo b787 = cache.findNodeInfo(lr3.getUuid(), b787Path);
- assertThat(b787.getUuid(), is(b787Node.getLocation().getUuid()));
- assertSameProperties(b787, b787Node);
-
- assertThat(cache.getPathFor(cars), is(carsAbsolutePath));
- assertThat(cache.getPathFor(lr3), is(lr3AbsolutePath));
- assertThat(cache.getPathFor(b787), is(b787AbsolutePath));
- }
-
- @Test
- public void shouldDeleteLeafNode() throws Exception {
- // Find the state of some Graph nodes we'll be using in the test ...
- Node utility = store.getNodeAt("/vehix:Vehicles/vehix:Cars/vehix:Utility");
- Node lr2Node = store.getNodeAt("/vehix:Vehicles/vehix:Cars/vehix:Utility/vehix:Land Rover LR2");
- Node lr3Node = store.getNodeAt("/vehix:Vehicles/vehix:Cars/vehix:Utility/vehix:Land Rover LR3");
- int numChildrenOfUtility = utility.getChildren().size();
- assertThat(numChildrenOfUtility, is(4));
- assertThat(utility.getChildren(), hasChildren(segment("vehix:Land Rover LR2"),
- segment("vehix:Land Rover LR3"),
- segment("vehix:Hummer H3"),
- segment("vehix:Ford F-150")));
-
- // Now get the editor for the 'vehix:Utility' node ...
- NodeEditor editor = cache.getEditorFor(utility.getLocation().getUuid());
- assertThat(editor, is(notNullValue()));
-
- // Destroy the LR3 node, which is a leaf ...
- editor.destroyChild(lr3Node.getLocation().getUuid());
-
- // Verify that the store has not yet been changed ...
- assertDoesExist(store, lr3Node.getLocation());
-
- // Save the session and verify that the node was deleted ...
- cache.save();
- Node utilityNode2 = store.getNodeAt(utility.getLocation());
- assertThat(utilityNode2.getChildren().size(), is(numChildrenOfUtility - 1));
- assertThat(utilityNode2.getChildren(), hasChildren(segment("vehix:Land Rover LR2"), // no LR3!
- segment("vehix:Hummer H3"),
- segment("vehix:Ford F-150")));
- // Should no longer find the LR3 node in the graph ...
- assertDoesNotExist(store, lr3Node.getLocation().getUuid());
- assertDoesExist(store, lr2Node.getLocation());
- }
-
- @Test
- public void shouldDeleteNonLeafNode() throws Exception {
- // Find the state of some Graph nodes we'll be using in the test ...
- Node carsNode = store.getNodeAt("/vehix:Vehicles/vehix:Cars");
- Node utility = store.getNodeAt("/vehix:Vehicles/vehix:Cars/vehix:Utility");
- Node hybrid = store.getNodeAt("/vehix:Vehicles/vehix:Cars/vehix:Hybrid");
- Node luxury = store.getNodeAt("/vehix:Vehicles/vehix:Cars/vehix:Luxury");
- Node sports = store.getNodeAt("/vehix:Vehicles/vehix:Cars/vehix:Sports");
- Node lr3 = store.getNodeAt("/vehix:Vehicles/vehix:Cars/vehix:Utility/vehix:Land Rover LR3");
- Node lr2 = store.getNodeAt("/vehix:Vehicles/vehix:Cars/vehix:Utility/vehix:Land Rover LR2");
- Node f150 = store.getNodeAt("/vehix:Vehicles/vehix:Cars/vehix:Utility/vehix:Ford F-150");
- int numChildrenOfCars = carsNode.getChildren().size();
- assertThat(numChildrenOfCars, is(4));
- assertThat(carsNode.getChildren(), hasChildren(segment("vehix:Hybrid"),
- segment("vehix:Sports"),
- segment("vehix:Luxury"),
- segment("vehix:Utility")));
-
- // Load the LR2 and Hummer nodes ...
- NodeInfo h3i = cache.findNodeInfo(utility.getLocation().getUuid(), path("vehix:Hummer H3"));
- NodeInfo lr2i = cache.findNodeInfo(utility.getLocation().getUuid(), path("vehix:Land Rover LR2"));
- assertThat(h3i, is(notNullValue()));
- assertThat(lr2i, is(notNullValue()));
- assertThat(lr2i.getUuid(), is(lr2.getLocation().getUuid()));
-
- // Now get the editor for the 'vehix:Cars' node ...
- NodeEditor editor = cache.getEditorFor(carsNode.getLocation().getUuid());
- assertThat(editor, is(notNullValue()));
-
- // Destroy the Utility node, which is NOT a leaf ...
- editor.destroyChild(utility.getLocation().getUuid());
-
- // Verify that the store has not yet been changed ...
- assertDoesExist(store, utility.getLocation());
-
- // ... but the utility node and its two loaded children have been marked for deletion ...
- assertIsDeleted(cache, utility.getLocation().getUuid());
- assertIsDeleted(cache, h3i.getUuid());
- assertIsDeleted(cache, lr2i.getUuid());
-
- // Save the session and verify that the Utility node and its children were deleted ...
- cache.save();
- Node carsNode2 = store.getNodeAt(carsNode.getLocation());
- assertThat(carsNode2.getChildren().size(), is(numChildrenOfCars - 1));
- assertThat(carsNode2.getChildren(),
- hasChildren(segment("vehix:Hybrid"), segment("vehix:Sports"), segment("vehix:Luxury")));
- // Should no longer find the Utility node in the graph ...
- assertDoesNotExist(store, utility.getLocation());
- assertDoesNotExist(cache, utility.getLocation().getUuid());
- assertDoesNotExist(cache, h3i.getUuid());
- assertDoesNotExist(cache, lr2i.getUuid());
- assertDoesNotExist(cache, lr3.getLocation().getUuid());
- assertDoesNotExist(cache, f150.getLocation().getUuid());
- assertDoNotExist(store, utility.getChildren());
- assertDoesExist(store, hybrid.getLocation());
- assertDoesExist(store, luxury.getLocation());
- assertDoesExist(store, sports.getLocation());
- }
-
- @Test
- public void shouldGetExistingPropertyOnExistingNode() throws Exception {
- NodeInfo root = cache.findNodeInfoForRoot();
- NodeInfo lr3 = cache.findNodeInfo(root.getUuid(), path("/vehix:Vehicles/vehix:Cars/vehix:Utility/vehix:Land Rover LR3"));
- assertProperty(lr3, Lexicon.MODEL, STRING, Lexicon.CAR, Lexicon.MODEL, STRING, "LR3");
- assertProperty(lr3, Lexicon.MAKER, STRING, Lexicon.CAR, Lexicon.MAKER, STRING, "Land Rover");
- assertProperty(lr3, Lexicon.YEAR, LONG, Lexicon.CAR, Lexicon.YEAR, LONG, 2008L);
- assertProperty(lr3, Lexicon.MSRP, STRING, Lexicon.CAR, Lexicon.MSRP, STRING, "$48,525");
-
- NodeInfo db9 = cache.findNodeInfo(root.getUuid(), path("/vehix:Vehicles/vehix:Cars/vehix:Sports/vehix:Aston Martin DB9"));
- assertProperty(db9, Lexicon.MODEL, STRING, Lexicon.CAR, Lexicon.MODEL, STRING, "DB9");
- assertProperty(db9, Lexicon.MAKER, STRING, Lexicon.CAR, Lexicon.MAKER, STRING, "Aston Martin");
- assertProperty(db9, Lexicon.LENGTH_IN_INCHES, DOUBLE, Lexicon.CAR, Lexicon.LENGTH_IN_INCHES, DOUBLE, 185.5D);
-
- NodeInfo b878 = cache.findNodeInfo(root.getUuid(),
- path("/vehix:Vehicles/vehix:Aircraft/vehix:Commercial/vehix:Boeing 787"));
- assertProperty(b878, Lexicon.MODEL, STRING, Lexicon.AIRCRAFT, Lexicon.MODEL, STRING, "787-3");
- assertProperty(b878, Lexicon.MAKER, STRING, Lexicon.AIRCRAFT, Lexicon.MAKER, STRING, "Boeing");
- assertProperty(b878, Lexicon.INTRODUCED, LONG, Lexicon.AIRCRAFT, Lexicon.INTRODUCED, LONG, 2009L);
- assertProperty(b878, Lexicon.EMPTY_WEIGHT, STRING, JcrNtLexicon.UNSTRUCTURED, name("*"), UNDEFINED, "223000lb");
-
- }
-
- @Test
- public void shouldNotFindNonExistantPropertyOnExistingNode() throws Exception {
- NodeInfo root = cache.findNodeInfoForRoot();
- NodeInfo lr3 = cache.findNodeInfo(root.getUuid(), path("/vehix:Vehicles/vehix:Cars/vehix:Utility/vehix:Land Rover LR3"));
- assertProperty(lr3, Lexicon.MODEL, STRING, Lexicon.CAR, Lexicon.MODEL, STRING, "LR3");
- assertProperty(lr3, Lexicon.MAKER, STRING, Lexicon.CAR, Lexicon.MAKER, STRING, "Land Rover");
- assertNoProperty(lr3, Lexicon.LENGTH_IN_INCHES);
- assertNoProperty(lr3, Lexicon.INTRODUCED);
- }
-
- @Test
- public void shouldSetNewValueOnExistingPropertyOnExistingNode() throws Exception {
- NodeInfo root = cache.findNodeInfoForRoot();
- NodeInfo lr3 = cache.findNodeInfo(root.getUuid(), path("/vehix:Vehicles/vehix:Cars/vehix:Utility/vehix:Land Rover LR3"));
- assertProperty(lr3, Lexicon.MODEL, STRING, Lexicon.CAR, Lexicon.MODEL, STRING, "LR3");
- assertProperty(lr3, Lexicon.MAKER, STRING, Lexicon.CAR, Lexicon.MAKER, STRING, "Land Rover");
- assertNoProperty(lr3, Lexicon.LENGTH_IN_INCHES);
-
- SessionCache.NodeEditor editor = cache.getEditorFor(lr3.getUuid());
- editor.setProperty(Lexicon.LENGTH_IN_INCHES, value(DOUBLE, 100.0D));
- }
-
- @Test
- public void shouldSetNewPropertyOnExistingNode() throws Exception {
- NodeInfo root = cache.findNodeInfoForRoot();
- NodeInfo db9 = cache.findNodeInfo(root.getUuid(), path("/vehix:Vehicles/vehix:Cars/vehix:Sports/vehix:Aston Martin DB9"));
- assertProperty(db9, Lexicon.MODEL, STRING, Lexicon.CAR, Lexicon.MODEL, STRING, "DB9");
- assertProperty(db9, Lexicon.MAKER, STRING, Lexicon.CAR, Lexicon.MAKER, STRING, "Aston Martin");
- assertProperty(db9, Lexicon.LENGTH_IN_INCHES, DOUBLE, Lexicon.CAR, Lexicon.LENGTH_IN_INCHES, DOUBLE, 185.5D);
-
- SessionCache.NodeEditor editor = cache.getEditorFor(db9.getUuid());
- editor.setProperty(Lexicon.LENGTH_IN_INCHES, value(DOUBLE, 100.0D));
- }
-
- @Test( expected = ConstraintViolationException.class )
- public void shouldFailToSetPropertyToInvalidValuesOnExistingNode() throws Exception {
- NodeInfo root = cache.findNodeInfoForRoot();
- NodeInfo db9 = cache.findNodeInfo(root.getUuid(), path("/vehix:Vehicles/vehix:Cars/vehix:Sports/vehix:Aston Martin DB9"));
- assertProperty(db9, Lexicon.MODEL, STRING, Lexicon.CAR, Lexicon.MODEL, STRING, "DB9");
- assertProperty(db9, Lexicon.MAKER, STRING, Lexicon.CAR, Lexicon.MAKER, STRING, "Aston Martin");
- assertProperty(db9, Lexicon.LENGTH_IN_INCHES, DOUBLE, Lexicon.CAR, Lexicon.LENGTH_IN_INCHES, DOUBLE, 185.5D);
-
- SessionCache.NodeEditor editor = cache.getEditorFor(db9.getUuid());
- editor.setProperty(Lexicon.LENGTH_IN_INCHES, value(STRING, "This is not a valid double"));
- }
-
- @Test
- public void shouldRemoveExistingPropertyOnExistingNode() throws Exception {
- NodeInfo root = cache.findNodeInfoForRoot();
- NodeInfo db9 = cache.findNodeInfo(root.getUuid(), path("/vehix:Vehicles/vehix:Cars/vehix:Sports/vehix:Aston Martin DB9"));
- assertProperty(db9, Lexicon.MODEL, STRING, Lexicon.CAR, Lexicon.MODEL, STRING, "DB9");
- assertProperty(db9, Lexicon.MAKER, STRING, Lexicon.CAR, Lexicon.MAKER, STRING, "Aston Martin");
- assertProperty(db9, Lexicon.LENGTH_IN_INCHES, DOUBLE, Lexicon.CAR, Lexicon.LENGTH_IN_INCHES, DOUBLE, 185.5D);
-
- UUID db9uuid = db9.getUuid();
- SessionCache.NodeEditor editor = cache.getEditorFor(db9uuid);
- editor.removeProperty(Lexicon.LENGTH_IN_INCHES);
-
- db9 = cache.findNodeInfo(db9uuid);
- assertNoProperty(db9, Lexicon.LENGTH_IN_INCHES);
-
- db9 = cache.findNodeInfo(root.getUuid(), path("/vehix:Vehicles/vehix:Cars/vehix:Sports/vehix:Aston Martin DB9"));
- assertNoProperty(db9, Lexicon.LENGTH_IN_INCHES);
- }
-
- protected void walkInfosForNodesUnder( NodeInfo parentInfo,
- Stopwatch sw ) throws Exception {
- for (ChildNode child : parentInfo.getChildren()) {
- sw.start();
- NodeInfo childInfo = cache.findNodeInfo(child.getUuid());
- cache.getPathFor(childInfo);
- sw.stop();
-
- // Walk the infos for nodes under the child (this is recursive) ...
- walkInfosForNodesUnder(childInfo, sw);
- }
- }
-
- @Test
- public void shouldFindInfoForAllNodesInGraph() throws Exception {
- for (int i = 0; i != 3; ++i) {
- Stopwatch sw = new Stopwatch();
-
- // Get the root ...
- sw.start();
- NodeInfo root = cache.findNodeInfoForRoot();
- cache.getPathFor(root);
- sw.stop();
-
- // Walk the infos for nodes under the root (this is recursive) ...
- walkInfosForNodesUnder(root, sw);
- System.out.println("Statistics for walking nodes using SessionCache: " + sw.getSimpleStatistics());
- }
- }
+ // @Override
+ // @Before
+ // public void beforeEach() throws Exception {
+ // super.beforeEach();
+ // }
+ //
+ // protected Graph createFrom( String repositoryName,
+ // String workspaceName,
+ // File file ) throws IOException, SAXException {
+ // InMemoryRepositorySource source = new InMemoryRepositorySource();
+ // source.setName(repositoryName);
+ // Graph graph = Graph.create(source, context);
+ // graph.createWorkspace().named(workspaceName);
+ //
+ // if (file != null) {
+ // graph.importXmlFrom(file).into("/");
+ // }
+ // return graph;
+ // }
+ //
+ // protected Graph getGraph( String name ) throws IOException, SAXException {
+ // Graph graph = storesByName.get(name);
+ // if (graph == null) {
+ // graph = createFrom(name, name + " workspace", new File("src/test/resources/" + name + ".xml"));
+ // storesByName.put(name, graph);
+ // }
+ // return graph;
+ // }
+ //
+ // protected SessionCache getCache( String name ) throws IOException, SAXException {
+ // SessionCache cache = cachesByName.get(name);
+ // if (cache == null) {
+ // cache = new SessionCache(session, name + " workspace", context, nodeTypes, getGraph(name));
+ // cachesByName.put(name, cache);
+ // }
+ // return cache;
+ // }
+ //
+ // protected Name name( String name ) {
+ // return context.getValueFactories().getNameFactory().create(name);
+ // }
+ //
+ // protected Path path( String path ) {
+ // return context.getValueFactories().getPathFactory().create(path);
+ // }
+ //
+ // protected Path.Segment segment( String segment ) {
+ // return context.getValueFactories().getPathFactory().createSegment(segment);
+ // }
+ //
+ // protected String pad( String name ) {
+ // return StringUtil.justifyLeft(name, 22, ' ');
+ // }
+ //
+ // protected void assertSameProperties( Node<JcrNodePayload, JcrPropertyPayload> nodeInfo,
+ // org.jboss.dna.graph.Node dnaNode ) {
+ // assertThat(nodeInfo.getLocation(), is(dnaNode.getLocation()));
+ // Set<Name> propertyNames = nodeInfo.getPropertyNames();
+ // for (Name propertyName : propertyNames) {
+ // PropertyInfo<JcrPropertyPayload> info = nodeInfo.getProperty(propertyName);
+ // assertThat(info.getName(), is(propertyName));
+ // assertThat(info.getProperty().getName(), is(propertyName));
+ // Property actual = dnaNode.getProperty(propertyName);
+ // if (actual != null) {
+ // assertThat(info.getProperty().size(), is(actual.size()));
+ // assertThat(info.getProperty().getValuesAsArray(), is(actual.getValuesAsArray()));
+ // } else {
+ // if (propertyName.equals(JcrLexicon.UUID)) {
+ // // check for a DNA UUID property ...
+ // actual = dnaNode.getProperty(DnaLexicon.UUID);
+ // if (actual != null) {
+ // assertThat(info.getProperty().size(), is(actual.size()));
+ // assertThat(info.getProperty().getValuesAsArray(), is(actual.getValuesAsArray()));
+ // } else {
+ // fail("missing property \"" + propertyName + "\" on " + dnaNode);
+ // }
+ // } else if (propertyName.equals(JcrLexicon.PRIMARY_TYPE)) {
+ // // This is okay
+ // } else if (propertyName.equals(DnaIntLexicon.MULTI_VALUED_PROPERTIES)) {
+ // // This is okay
+ // } else {
+ // fail("missing property \"" + propertyName + "\" on " + dnaNode);
+ // }
+ // }
+ // }
+ // }
+ //
+ // protected JcrValue value( int propertyType,
+ // Object value ) {
+ // return new JcrValue(context.getValueFactories(), cache, propertyType, value);
+ // }
+ //
+ // protected void assertDoesExist( Graph graph,
+ // Location location ) {
+ // org.jboss.dna.graph.Node node = store.getNodeAt(location);
+ // assertThat(node, is(notNullValue()));
+ // assertThat(node.getLocation(), is(location));
+ // }
+ //
+ // protected void assertDoesNotExist( Graph graph,
+ // Location location ) {
+ // try {
+ // store.getNodeAt(location);
+ // fail("Shouldn't have found the node " + location);
+ // } catch (PathNotFoundException e) {
+ // // expected
+ // }
+ // }
+ //
+ // protected void assertDoesNotExist( Graph graph,
+ // Path path ) {
+ // try {
+ // store.getNodeAt(path);
+ // fail("Shouldn't have found the node " + path);
+ // } catch (PathNotFoundException e) {
+ // // expected
+ // }
+ // }
+ //
+ // protected void assertDoNotExist( Graph graph,
+ // List<Location> locations ) {
+ // for (Location location : locations)
+ // assertDoesNotExist(graph, location);
+ // }
+ //
+ // protected void assertProperty( org.jboss.dna.graph.session.GraphSession.Node<JcrNodePayload, JcrPropertyPayload> info,
+ // Name propertyName,
+ // int type,
+ // Name nodeTypeName,
+ // Name propertyDefinitionName,
+ // int definitionType,
+ // Object value ) {
+ // PropertyDefinitionId defnId = new PropertyDefinitionId(nodeTypeName, propertyDefinitionName, definitionType, false);
+ // PropertyInfo<JcrPropertyPayload> propertyInfo = info.getProperty(propertyName);
+ // assertThat(propertyInfo, is(notNullValue()));
+ // assertThat(propertyInfo.getPayload().getPropertyType(), is(type));
+ // assertThat(propertyInfo.getPayload().getPropertyDefinitionId(), is(defnId));
+ // org.jboss.dna.graph.property.PropertyType dnaPropertyType = PropertyTypeUtil.dnaPropertyTypeFor(type);
+ // // Check the value ...
+ // ValueFactory<?> factory = context.getValueFactories().getValueFactory(dnaPropertyType);
+ // Object actual = factory.create(propertyInfo.getProperty().getFirstValue());
+ // assertThat(actual, is(value));
+ // }
+ //
+ // protected void assertProperty( org.jboss.dna.graph.session.GraphSession.Node<JcrNodePayload, JcrPropertyPayload> info,
+ // Name propertyName,
+ // int type,
+ // Name nodeTypeName,
+ // Name propertyDefinitionName,
+ // int definitionType,
+ // Object... values ) {
+ // PropertyDefinitionId defnId = new PropertyDefinitionId(nodeTypeName, propertyDefinitionName, definitionType, true);
+ // PropertyInfo<JcrPropertyPayload> propertyInfo = info.getProperty(propertyName);
+ // assertThat(propertyInfo, is(notNullValue()));
+ // assertThat(propertyInfo.getPayload().getPropertyType(), is(type));
+ // assertThat(propertyInfo.getPayload().getPropertyDefinitionId(), is(defnId));
+ // org.jboss.dna.graph.property.PropertyType dnaPropertyType = PropertyTypeUtil.dnaPropertyTypeFor(type);
+ // // Check the values ...
+ // ValueFactory<?> factory = context.getValueFactories().getValueFactory(dnaPropertyType);
+ // int i = 0;
+ // for (Object value : propertyInfo.getProperty()) {
+ // assertThat(factory.create(value), is(values[i++]));
+ // }
+ // }
+ //
+ // protected void assertNoProperty( org.jboss.dna.graph.session.GraphSession.Node<JcrNodePayload, JcrPropertyPayload> info,
+ // Name propertyName ) {
+ // assertThat(info.getProperty(propertyName), is(nullValue()));
+ // }
+ //
+ // @Test
+ // public void shouldCreateWithValidParameters() {
+ // assertThat(cache, is(notNullValue()));
+ // }
+ //
+ // @Test
+ // public void shouldRepeatedlyFindRootNodeInfoByPath() throws Exception {
+ // String sourceName = "cars";
+ // Graph store = getGraph(sourceName);
+ // SessionCache cache = getCache(sourceName);
+ // org.jboss.dna.graph.Node root = store.getNodeAt("/");
+ // UUID rootUuid = root.getLocation().getUuid();
+ // AbstractJcrNode nodeInfo = cache.findJcrRootNode();
+ // assertSameProperties(nod, root)
+ // assertThat(nodeInfo.getUuid(), is(rootUuid));
+ // for (int i = 0; i != 20; ++i) {
+ // sw.start();
+ // assertThat(nodeInfo, is(sameInstance(cache.findNodeInfoForRoot())));
+ // sw.stop();
+ // assertThat(nodeInfo, is(sameInstance(cache.findNodeInfo(rootUuid))));
+ // }
+ // // System.out.println(pad(sourceName) + " ==> " + sw.getSimpleStatistics());
+ // }
+ //
+ // @Test
+ // public void shouldRepeatedlyFindRootNodeInfoByUuidFromVehiclesSource() throws Exception {
+ // String sourceName = "vehicles";
+ // Graph store = getGraph(sourceName);
+ // SessionCache cache = getCache(sourceName);
+ // sw.start();
+ // Node root = store.getNodeAt("/");
+ // sw.stop();
+ // UUID rootUuid = root.getLocation().getUuid();
+ // for (int i = 0; i != 20; ++i) {
+ // sw.start();
+ // NodeInfo rootInfo = cache.findNodeInfo(rootUuid);
+ // sw.stop();
+ // assertThat(rootInfo, is(notNullValue()));
+ // }
+ // // System.out.println(pad(sourceName) + " ==> " + sw.getSimpleStatistics());
+ // }
+ //
+ // @Test
+ // public void shouldRepeatedlyFindRootNodeInfoByUuidFromSourceWithPrimaryTypes() throws Exception {
+ // String sourceName = "repositoryForTckTests";
+ // Graph store = getGraph(sourceName);
+ // SessionCache cache = getCache(sourceName);
+ // sw.start();
+ // Node root = store.getNodeAt("/");
+ // sw.stop();
+ // UUID rootUuid = root.getLocation().getUuid();
+ // for (int i = 0; i != 20; ++i) {
+ // sw.start();
+ // NodeInfo rootInfo = cache.findNodeInfo(rootUuid);
+ // sw.stop();
+ // assertThat(rootInfo, is(notNullValue()));
+ // }
+ // // System.out.println(pad(sourceName) + " ==> " + sw.getSimpleStatistics());
+ // }
+ //
+ // @Test
+ // public void shouldFindChildrenInNodeInfoForRoot() throws Exception {
+ // NodeInfo root = cache.findNodeInfoForRoot();
+ // Children children = root.getChildren();
+ // assertThat(children, is(notNullValue()));
+ // assertThat(children.size(), is(1));
+ // assertThat(children.getChild(segment("vehix:Vehicles")), is(notNullValue()));
+ // }
+ //
+ // @Test
+ // public void shouldFindNodeInfoForNonRootNodeByPath() throws Exception {
+ // String sourceName = "vehicles";
+ // Graph store = getGraph(sourceName);
+ // SessionCache cache = getCache(sourceName);
+ // // Get the root ...
+ // NodeInfo root = cache.findNodeInfoForRoot();
+ //
+ // // Now try to load a node that is well-below the root ...
+ // Path lr3Path = path("/vehix:Vehicles/vehix:Cars/vehix:Utility/vehix:Land Rover LR3");
+ // Node lr3Node = store.getNodeAt(lr3Path);
+ // sw.start();
+ // NodeInfo lr3 = cache.findNodeInfo(root.getUuid(), lr3Path);
+ // sw.stop();
+ // assertThat(lr3.getUuid(), is(lr3Node.getLocation().getUuid()));
+ // assertSameProperties(lr3, lr3Node);
+ // // System.out.println(pad(sourceName) + " ==> " + sw.getSimpleStatistics());
+ //
+ // // Verify that this loaded all the intermediate nodes, by walking up ...
+ // NodeInfo info = lr3;
+ // while (true) {
+ // UUID parent = info.getParent();
+ // if (parent == null) {
+ // // then we should be at the root ...
+ // assertThat(info.getUuid(), is(root.getUuid()));
+ // break;
+ // }
+ // // Otherwise, we're not at the root, so we should find the parent ...
+ // info = cache.findNodeInfoInCache(parent);
+ // assertThat(info, is(notNullValue()));
+ // }
+ // }
+ //
+ // @Test
+ // public void shouldFindInfoForNodeUsingRelativePathFromRoot() throws Exception {
+ // String sourceName = "vehicles";
+ // Graph store = getGraph(sourceName);
+ // SessionCache cache = getCache(sourceName);
+ //
+ // // Verify that the node does exist in the source ...
+ // Path lr3AbsolutePath = path("/vehix:Vehicles/vehix:Cars/vehix:Utility/vehix:Land Rover LR3");
+ // Node lr3Node = store.getNodeAt(lr3AbsolutePath);
+ //
+ // // Get the root ...
+ // NodeInfo root = cache.findNodeInfoForRoot();
+ //
+ // // Now try to load a node that is well-below the root ...
+ // Path lr3Path = path("vehix:Vehicles/vehix:Cars/vehix:Utility/vehix:Land Rover LR3");
+ // assertThat(lr3Path.isAbsolute(), is(false));
+ // NodeInfo lr3 = cache.findNodeInfo(root.getUuid(), lr3Path);
+ // assertThat(lr3.getUuid(), is(lr3Node.getLocation().getUuid()));
+ // assertSameProperties(lr3, lr3Node);
+ //
+ // Path recoveredPath = cache.getPathFor(lr3);
+ // assertThat(recoveredPath, is(lr3AbsolutePath));
+ // }
+ //
+ // @Test
+ // public void shouldFindInfoForNodeUsingRelativePathFromNonRoot() throws Exception {
+ // // Verify that the node does exist in the source ...
+ // Path carsAbsolutePath = path("/vehix:Vehicles/vehix:Cars");
+ // Node carsNode = store.getNodeAt(carsAbsolutePath);
+ // Path lr3AbsolutePath = path("/vehix:Vehicles/vehix:Cars/vehix:Utility/vehix:Land Rover LR3");
+ // Node lr3Node = store.getNodeAt(lr3AbsolutePath);
+ // Path b787AbsolutePath = path("/vehix:Vehicles/vehix:Aircraft/vehix:Commercial/vehix:Boeing 787");
+ // Node b787Node = store.getNodeAt(b787AbsolutePath);
+ //
+ // // Get the root ...
+ // NodeInfo root = cache.findNodeInfoForRoot();
+ //
+ // // Now try to load the cars node ...
+ // Path carsPath = path("vehix:Vehicles/vehix:Cars");
+ // assertThat(carsPath.isAbsolute(), is(false));
+ // NodeInfo cars = cache.findNodeInfo(root.getUuid(), carsPath);
+ // assertThat(cars.getUuid(), is(carsNode.getLocation().getUuid()));
+ // assertSameProperties(cars, carsNode);
+ //
+ // // Now try to find the LR3 node relative to the car ...
+ // Path lr3Path = path("vehix:Utility/vehix:Land Rover LR3");
+ // assertThat(lr3Path.isAbsolute(), is(false));
+ // NodeInfo lr3 = cache.findNodeInfo(cars.getUuid(), lr3Path);
+ // assertThat(lr3.getUuid(), is(lr3Node.getLocation().getUuid()));
+ // assertSameProperties(lr3, lr3Node);
+ //
+ // // Now try to find the "Boeing 787" node relative to the LR3 node ...
+ // Path b787Path = path("../../../vehix:Aircraft/vehix:Commercial/vehix:Boeing 787");
+ // assertThat(b787Path.isAbsolute(), is(false));
+ // assertThat(b787Path.isNormalized(), is(true));
+ // NodeInfo b787 = cache.findNodeInfo(lr3.getUuid(), b787Path);
+ // assertThat(b787.getUuid(), is(b787Node.getLocation().getUuid()));
+ // assertSameProperties(b787, b787Node);
+ //
+ // assertThat(cache.getPathFor(cars), is(carsAbsolutePath));
+ // assertThat(cache.getPathFor(lr3), is(lr3AbsolutePath));
+ // assertThat(cache.getPathFor(b787), is(b787AbsolutePath));
+ // }
+ //
+ // @Test
+ // public void shouldFindJcrNodeUsingAbsolutePaths() throws Exception {
+ // // Verify that the node does exist in the source ...
+ // Path carsAbsolutePath = path("/vehix:Vehicles/vehix:Cars");
+ // Node carsNode = store.getNodeAt(carsAbsolutePath);
+ // Path lr3AbsolutePath = path("/vehix:Vehicles/vehix:Cars/vehix:Utility/vehix:Land Rover LR3");
+ // Node lr3Node = store.getNodeAt(lr3AbsolutePath);
+ // Path b787AbsolutePath = path("/vehix:Vehicles/vehix:Aircraft/vehix:Commercial/vehix:Boeing 787");
+ // Node b787Node = store.getNodeAt(b787AbsolutePath);
+ //
+ // // Get the root ...
+ // NodeInfo root = cache.findNodeInfoForRoot();
+ //
+ // // Now try to load the cars node ...
+ // Path carsPath = path("vehix:Vehicles/vehix:Cars");
+ // assertThat(carsPath.isAbsolute(), is(false));
+ // AbstractJcrNode carJcrNode = cache.findJcrNode(root.getUuid(), carsAbsolutePath);
+ // assertThat(carJcrNode.internalUuid(), is(carsNode.getLocation().getUuid()));
+ // NodeInfo cars = cache.findNodeInfo(root.getUuid(), carsPath);
+ // assertThat(cars.getUuid(), is(carsNode.getLocation().getUuid()));
+ // assertSameProperties(cars, carsNode);
+ //
+ // // Now try to find the LR3 node relative to the car ...
+ // Path lr3Path = path("vehix:Utility/vehix:Land Rover LR3");
+ // assertThat(lr3Path.isAbsolute(), is(false));
+ // AbstractJcrNode lr3JcrNode = cache.findJcrNode(root.getUuid(), lr3AbsolutePath);
+ // assertThat(lr3JcrNode.internalUuid(), is(lr3Node.getLocation().getUuid()));
+ // NodeInfo lr3 = cache.findNodeInfo(cars.getUuid(), lr3Path);
+ // assertThat(lr3.getUuid(), is(lr3Node.getLocation().getUuid()));
+ // assertSameProperties(lr3, lr3Node);
+ //
+ // // Now try to find the "Boeing 787" node relative to the LR3 node ...
+ // Path b787Path = path("../../../vehix:Aircraft/vehix:Commercial/vehix:Boeing 787");
+ // assertThat(b787Path.isAbsolute(), is(false));
+ // assertThat(b787Path.isNormalized(), is(true));
+ // AbstractJcrNode b787JcrNode = cache.findJcrNode(root.getUuid(), b787AbsolutePath);
+ // assertThat(b787JcrNode.internalUuid(), is(b787Node.getLocation().getUuid()));
+ // NodeInfo b787 = cache.findNodeInfo(lr3.getUuid(), b787Path);
+ // assertThat(b787.getUuid(), is(b787Node.getLocation().getUuid()));
+ // assertSameProperties(b787, b787Node);
+ //
+ // assertThat(cache.getPathFor(cars), is(carsAbsolutePath));
+ // assertThat(cache.getPathFor(lr3), is(lr3AbsolutePath));
+ // assertThat(cache.getPathFor(b787), is(b787AbsolutePath));
+ // }
+ //
+ // @Test
+ // public void shouldDeleteLeafNode() throws Exception {
+ // // Find the state of some Graph nodes we'll be using in the test ...
+ // Node utility = store.getNodeAt("/vehix:Vehicles/vehix:Cars/vehix:Utility");
+ // Node lr2Node = store.getNodeAt("/vehix:Vehicles/vehix:Cars/vehix:Utility/vehix:Land Rover LR2");
+ // Node lr3Node = store.getNodeAt("/vehix:Vehicles/vehix:Cars/vehix:Utility/vehix:Land Rover LR3");
+ // int numChildrenOfUtility = utility.getChildren().size();
+ // assertThat(numChildrenOfUtility, is(4));
+ // assertThat(utility.getChildren(), hasChildren(segment("vehix:Land Rover LR2"),
+ // segment("vehix:Land Rover LR3"),
+ // segment("vehix:Hummer H3"),
+ // segment("vehix:Ford F-150")));
+ //
+ // // Now get the editor for the 'vehix:Utility' node ...
+ // NodeEditor editor = cache.getEditorFor(utility.getLocation().getUuid());
+ // assertThat(editor, is(notNullValue()));
+ //
+ // // Destroy the LR3 node, which is a leaf ...
+ // editor.destroyChild(lr3Node.getLocation().getUuid());
+ //
+ // // Verify that the store has not yet been changed ...
+ // assertDoesExist(store, lr3Node.getLocation());
+ //
+ // // Save the session and verify that the node was deleted ...
+ // cache.save();
+ // Node utilityNode2 = store.getNodeAt(utility.getLocation());
+ // assertThat(utilityNode2.getChildren().size(), is(numChildrenOfUtility - 1));
+ // assertThat(utilityNode2.getChildren(), hasChildren(segment("vehix:Land Rover LR2"), // no LR3!
+ // segment("vehix:Hummer H3"),
+ // segment("vehix:Ford F-150")));
+ // // Should no longer find the LR3 node in the graph ...
+ // assertDoesNotExist(store, lr3Node.getLocation().getUuid());
+ // assertDoesExist(store, lr2Node.getLocation());
+ // }
+ //
+ // @Test
+ // public void shouldDeleteNonLeafNode() throws Exception {
+ // // Find the state of some Graph nodes we'll be using in the test ...
+ // Node carsNode = store.getNodeAt("/vehix:Vehicles/vehix:Cars");
+ // Node utility = store.getNodeAt("/vehix:Vehicles/vehix:Cars/vehix:Utility");
+ // Node hybrid = store.getNodeAt("/vehix:Vehicles/vehix:Cars/vehix:Hybrid");
+ // Node luxury = store.getNodeAt("/vehix:Vehicles/vehix:Cars/vehix:Luxury");
+ // Node sports = store.getNodeAt("/vehix:Vehicles/vehix:Cars/vehix:Sports");
+ // Node lr3 = store.getNodeAt("/vehix:Vehicles/vehix:Cars/vehix:Utility/vehix:Land Rover LR3");
+ // Node lr2 = store.getNodeAt("/vehix:Vehicles/vehix:Cars/vehix:Utility/vehix:Land Rover LR2");
+ // Node f150 = store.getNodeAt("/vehix:Vehicles/vehix:Cars/vehix:Utility/vehix:Ford F-150");
+ // int numChildrenOfCars = carsNode.getChildren().size();
+ // assertThat(numChildrenOfCars, is(4));
+ // assertThat(carsNode.getChildren(), hasChildren(segment("vehix:Hybrid"),
+ // segment("vehix:Sports"),
+ // segment("vehix:Luxury"),
+ // segment("vehix:Utility")));
+ //
+ // // Load the LR2 and Hummer nodes ...
+ // NodeInfo h3i = cache.findNodeInfo(utility.getLocation().getUuid(), path("vehix:Hummer H3"));
+ // NodeInfo lr2i = cache.findNodeInfo(utility.getLocation().getUuid(), path("vehix:Land Rover LR2"));
+ // assertThat(h3i, is(notNullValue()));
+ // assertThat(lr2i, is(notNullValue()));
+ // assertThat(lr2i.getUuid(), is(lr2.getLocation().getUuid()));
+ //
+ // // Now get the editor for the 'vehix:Cars' node ...
+ // NodeEditor editor = cache.getEditorFor(carsNode.getLocation().getUuid());
+ // assertThat(editor, is(notNullValue()));
+ //
+ // // Destroy the Utility node, which is NOT a leaf ...
+ // editor.destroyChild(utility.getLocation().getUuid());
+ //
+ // // Verify that the store has not yet been changed ...
+ // assertDoesExist(store, utility.getLocation());
+ //
+ // // ... but the utility node and its two loaded children have been marked for deletion ...
+ // assertIsDeleted(cache, utility.getLocation().getUuid());
+ // assertIsDeleted(cache, h3i.getUuid());
+ // assertIsDeleted(cache, lr2i.getUuid());
+ //
+ // // Save the session and verify that the Utility node and its children were deleted ...
+ // cache.save();
+ // Node carsNode2 = store.getNodeAt(carsNode.getLocation());
+ // assertThat(carsNode2.getChildren().size(), is(numChildrenOfCars - 1));
+ // assertThat(carsNode2.getChildren(),
+ // hasChildren(segment("vehix:Hybrid"), segment("vehix:Sports"), segment("vehix:Luxury")));
+ // // Should no longer find the Utility node in the graph ...
+ // assertDoesNotExist(store, utility.getLocation());
+ // assertDoesNotExist(cache, utility.getLocation().getUuid());
+ // assertDoesNotExist(cache, h3i.getUuid());
+ // assertDoesNotExist(cache, lr2i.getUuid());
+ // assertDoesNotExist(cache, lr3.getLocation().getUuid());
+ // assertDoesNotExist(cache, f150.getLocation().getUuid());
+ // assertDoNotExist(store, utility.getChildren());
+ // assertDoesExist(store, hybrid.getLocation());
+ // assertDoesExist(store, luxury.getLocation());
+ // assertDoesExist(store, sports.getLocation());
+ // }
+ //
+ // @Test
+ // public void shouldGetExistingPropertyOnExistingNode() throws Exception {
+ // NodeInfo root = cache.findNodeInfoForRoot();
+ // NodeInfo lr3 = cache.findNodeInfo(root.getUuid(), path("/vehix:Vehicles/vehix:Cars/vehix:Utility/vehix:Land Rover LR3"));
+ // assertProperty(lr3, Lexicon.MODEL, STRING, Lexicon.CAR, Lexicon.MODEL, STRING, "LR3");
+ // assertProperty(lr3, Lexicon.MAKER, STRING, Lexicon.CAR, Lexicon.MAKER, STRING, "Land Rover");
+ // assertProperty(lr3, Lexicon.YEAR, LONG, Lexicon.CAR, Lexicon.YEAR, LONG, 2008L);
+ // assertProperty(lr3, Lexicon.MSRP, STRING, Lexicon.CAR, Lexicon.MSRP, STRING, "$48,525");
+ //
+ // NodeInfo db9 = cache.findNodeInfo(root.getUuid(), path("/vehix:Vehicles/vehix:Cars/vehix:Sports/vehix:Aston Martin DB9"));
+ // assertProperty(db9, Lexicon.MODEL, STRING, Lexicon.CAR, Lexicon.MODEL, STRING, "DB9");
+ // assertProperty(db9, Lexicon.MAKER, STRING, Lexicon.CAR, Lexicon.MAKER, STRING, "Aston Martin");
+ // assertProperty(db9, Lexicon.LENGTH_IN_INCHES, DOUBLE, Lexicon.CAR, Lexicon.LENGTH_IN_INCHES, DOUBLE, 185.5D);
+ //
+ // NodeInfo b878 = cache.findNodeInfo(root.getUuid(),
+ // path("/vehix:Vehicles/vehix:Aircraft/vehix:Commercial/vehix:Boeing 787"));
+ // assertProperty(b878, Lexicon.MODEL, STRING, Lexicon.AIRCRAFT, Lexicon.MODEL, STRING, "787-3");
+ // assertProperty(b878, Lexicon.MAKER, STRING, Lexicon.AIRCRAFT, Lexicon.MAKER, STRING, "Boeing");
+ // assertProperty(b878, Lexicon.INTRODUCED, LONG, Lexicon.AIRCRAFT, Lexicon.INTRODUCED, LONG, 2009L);
+ // assertProperty(b878, Lexicon.EMPTY_WEIGHT, STRING, JcrNtLexicon.UNSTRUCTURED, name("*"), UNDEFINED, "223000lb");
+ //
+ // }
+ //
+ // @Test
+ // public void shouldNotFindNonExistantPropertyOnExistingNode() throws Exception {
+ // NodeInfo root = cache.findNodeInfoForRoot();
+ // NodeInfo lr3 = cache.findNodeInfo(root.getUuid(), path("/vehix:Vehicles/vehix:Cars/vehix:Utility/vehix:Land Rover LR3"));
+ // assertProperty(lr3, Lexicon.MODEL, STRING, Lexicon.CAR, Lexicon.MODEL, STRING, "LR3");
+ // assertProperty(lr3, Lexicon.MAKER, STRING, Lexicon.CAR, Lexicon.MAKER, STRING, "Land Rover");
+ // assertNoProperty(lr3, Lexicon.LENGTH_IN_INCHES);
+ // assertNoProperty(lr3, Lexicon.INTRODUCED);
+ // }
+ //
+ // @Test
+ // public void shouldSetNewValueOnExistingPropertyOnExistingNode() throws Exception {
+ // NodeInfo root = cache.findNodeInfoForRoot();
+ // NodeInfo lr3 = cache.findNodeInfo(root.getUuid(), path("/vehix:Vehicles/vehix:Cars/vehix:Utility/vehix:Land Rover LR3"));
+ // assertProperty(lr3, Lexicon.MODEL, STRING, Lexicon.CAR, Lexicon.MODEL, STRING, "LR3");
+ // assertProperty(lr3, Lexicon.MAKER, STRING, Lexicon.CAR, Lexicon.MAKER, STRING, "Land Rover");
+ // assertNoProperty(lr3, Lexicon.LENGTH_IN_INCHES);
+ //
+ // SessionCache.NodeEditor editor = cache.getEditorFor(lr3.getUuid());
+ // editor.setProperty(Lexicon.LENGTH_IN_INCHES, value(DOUBLE, 100.0D));
+ // }
+ //
+ // @Test
+ // public void shouldSetNewPropertyOnExistingNode() throws Exception {
+ // NodeInfo root = cache.findNodeInfoForRoot();
+ // NodeInfo db9 = cache.findNodeInfo(root.getUuid(), path("/vehix:Vehicles/vehix:Cars/vehix:Sports/vehix:Aston Martin DB9"));
+ // assertProperty(db9, Lexicon.MODEL, STRING, Lexicon.CAR, Lexicon.MODEL, STRING, "DB9");
+ // assertProperty(db9, Lexicon.MAKER, STRING, Lexicon.CAR, Lexicon.MAKER, STRING, "Aston Martin");
+ // assertProperty(db9, Lexicon.LENGTH_IN_INCHES, DOUBLE, Lexicon.CAR, Lexicon.LENGTH_IN_INCHES, DOUBLE, 185.5D);
+ //
+ // SessionCache.NodeEditor editor = cache.getEditorFor(db9.getUuid());
+ // editor.setProperty(Lexicon.LENGTH_IN_INCHES, value(DOUBLE, 100.0D));
+ // }
+ //
+ // @Test( expected = ConstraintViolationException.class )
+ // public void shouldFailToSetPropertyToInvalidValuesOnExistingNode() throws Exception {
+ // NodeInfo root = cache.findNodeInfoForRoot();
+ // NodeInfo db9 = cache.findNodeInfo(root.getUuid(), path("/vehix:Vehicles/vehix:Cars/vehix:Sports/vehix:Aston Martin DB9"));
+ // assertProperty(db9, Lexicon.MODEL, STRING, Lexicon.CAR, Lexicon.MODEL, STRING, "DB9");
+ // assertProperty(db9, Lexicon.MAKER, STRING, Lexicon.CAR, Lexicon.MAKER, STRING, "Aston Martin");
+ // assertProperty(db9, Lexicon.LENGTH_IN_INCHES, DOUBLE, Lexicon.CAR, Lexicon.LENGTH_IN_INCHES, DOUBLE, 185.5D);
+ //
+ // SessionCache.NodeEditor editor = cache.getEditorFor(db9.getUuid());
+ // editor.setProperty(Lexicon.LENGTH_IN_INCHES, value(STRING, "This is not a valid double"));
+ // }
+ //
+ // @Test
+ // public void shouldRemoveExistingPropertyOnExistingNode() throws Exception {
+ // NodeInfo root = cache.findNodeInfoForRoot();
+ // NodeInfo db9 = cache.findNodeInfo(root.getUuid(), path("/vehix:Vehicles/vehix:Cars/vehix:Sports/vehix:Aston Martin DB9"));
+ // assertProperty(db9, Lexicon.MODEL, STRING, Lexicon.CAR, Lexicon.MODEL, STRING, "DB9");
+ // assertProperty(db9, Lexicon.MAKER, STRING, Lexicon.CAR, Lexicon.MAKER, STRING, "Aston Martin");
+ // assertProperty(db9, Lexicon.LENGTH_IN_INCHES, DOUBLE, Lexicon.CAR, Lexicon.LENGTH_IN_INCHES, DOUBLE, 185.5D);
+ //
+ // UUID db9uuid = db9.getUuid();
+ // SessionCache.NodeEditor editor = cache.getEditorFor(db9uuid);
+ // editor.removeProperty(Lexicon.LENGTH_IN_INCHES);
+ //
+ // db9 = cache.findNodeInfo(db9uuid);
+ // assertNoProperty(db9, Lexicon.LENGTH_IN_INCHES);
+ //
+ // db9 = cache.findNodeInfo(root.getUuid(), path("/vehix:Vehicles/vehix:Cars/vehix:Sports/vehix:Aston Martin DB9"));
+ // assertNoProperty(db9, Lexicon.LENGTH_IN_INCHES);
+ // }
+ //
+ // protected void walkInfosForNodesUnder( NodeInfo parentInfo,
+ // Stopwatch sw ) throws Exception {
+ // for (ChildNode child : parentInfo.getChildren()) {
+ // sw.start();
+ // NodeInfo childInfo = cache.findNodeInfo(child.getUuid());
+ // cache.getPathFor(childInfo);
+ // sw.stop();
+ //
+ // // Walk the infos for nodes under the child (this is recursive) ...
+ // walkInfosForNodesUnder(childInfo, sw);
+ // }
+ // }
+ //
+ // @Test
+ // public void shouldFindInfoForAllNodesInGraph() throws Exception {
+ // for (int i = 0; i != 3; ++i) {
+ // Stopwatch sw = new Stopwatch();
+ //
+ // // Get the root ...
+ // sw.start();
+ // NodeInfo root = cache.findNodeInfoForRoot();
+ // cache.getPathFor(root);
+ // sw.stop();
+ //
+ // // Walk the infos for nodes under the root (this is recursive) ...
+ // walkInfosForNodesUnder(root, sw);
+ // System.out.println("Statistics for walking nodes using SessionCache: " + sw.getSimpleStatistics());
+ // }
+ // }
}
Added: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/SessionCacheTest2.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/SessionCacheTest2.java (rev 0)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/SessionCacheTest2.java 2009-07-09 16:26:04 UTC (rev 1082)
@@ -0,0 +1,382 @@
+/*
+ * 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.jcr;
+
+import static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.IsNot.not;
+import static org.hamcrest.core.IsNull.notNullValue;
+import static org.hamcrest.core.IsSame.sameInstance;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.fail;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import java.util.UUID;
+import javax.jcr.PropertyType;
+import javax.jcr.RepositoryException;
+import javax.jcr.Value;
+import javax.jcr.ValueFormatException;
+import org.jboss.dna.graph.Location;
+import org.jboss.dna.graph.property.Name;
+import org.jboss.dna.graph.property.Property;
+import org.jboss.dna.graph.session.GraphSession.Node;
+import org.jboss.dna.graph.session.GraphSession.PropertyInfo;
+import org.jboss.dna.jcr.SessionCache.JcrNodePayload;
+import org.jboss.dna.jcr.SessionCache.JcrPropertyPayload;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ *
+ */
+public class SessionCacheTest2 extends AbstractJcrTest {
+
+ @Override
+ @Before
+ public void beforeEach() throws Exception {
+ super.beforeEach();
+ }
+
+ @Test
+ public void shouldRepeatedlyFindRootNode() throws Exception {
+ AbstractJcrNode root = cache.findJcrRootNode();
+ for (int i = 0; i != 10; ++i) {
+ AbstractJcrNode node = cache.findJcrRootNode();
+ assertThat(node, is(sameInstance(root)));
+ // Look up the graph node ...
+ assertMatchesStore(node);
+ }
+ }
+
+ @Test
+ public void shouldRepeatedlyFindRootNodeByPath() throws Exception {
+ AbstractJcrNode root = cache.findJcrNode(null, path("/"));
+ for (int i = 0; i != 10; ++i) {
+ AbstractJcrNode node = cache.findJcrRootNode();
+ assertThat(node, is(sameInstance(root)));
+ // Look up the graph node ...
+ assertMatchesStore(node);
+ }
+ }
+
+ @Test
+ public void shouldRepeatedlyFindRootNodeByLocationWithoutPath() throws Exception {
+ AbstractJcrNode root = cache.findJcrRootNode();
+ AbstractJcrNode root2 = cache.findJcrNode(Location.create(root.location.getIdProperties()));
+ assertThat(root2, is(sameInstance(root)));
+ }
+
+ @Test
+ public void shouldRepeatedlyFindNodeByPath() throws Exception {
+ AbstractJcrNode hybrid = cache.findJcrNode(null, path("/Cars/Hybrid"));
+ for (int i = 0; i != 10; ++i) {
+ AbstractJcrNode hybrid2 = cache.findJcrNode(null, hybrid.path());
+ assertThat(hybrid, is(sameInstance(hybrid2)));
+ // Look up the graph node ...
+ assertMatchesStore(hybrid2);
+ }
+ }
+
+ @Test
+ public void shouldRepeatedlyFindNodeByNodeId() throws Exception {
+ AbstractJcrNode hybrid = cache.findJcrNode(null, path("/Cars/Hybrid"));
+ for (int i = 0; i != 10; ++i) {
+ AbstractJcrNode hybrid2 = cache.findJcrNode(hybrid.nodeId, null);
+ assertThat(hybrid, is(sameInstance(hybrid2)));
+ // Look up the graph node ...
+ assertMatchesStore(hybrid2);
+ }
+ }
+
+ @Test
+ public void shouldRepeatedlyFindNodeByLocationWithoutPath() throws Exception {
+ AbstractJcrNode hybrid = cache.findJcrNode(null, path("/Cars/Hybrid"));
+ AbstractJcrNode hybrid2 = cache.findJcrNode(Location.create(hybrid.location.getIdProperties()));
+ assertThat(hybrid2, is(sameInstance(hybrid)));
+ }
+
+ @Test
+ public void shouldFindNodeUsingStartingNodeAndRelativePath() throws Exception {
+ AbstractJcrNode hybrid = cache.findJcrNode(null, path("/Cars/Hybrid"));
+ AbstractJcrNode highlander = cache.findJcrNode(hybrid.nodeId, hybrid.path(), path("../Hybrid/Toyota Highlander"));
+ // Make sure this is the same as if we find it directly ...
+ AbstractJcrNode highlander2 = cache.findJcrNode(null, path("/Cars/Hybrid/Toyota Highlander"));
+ assertThat(highlander, is(sameInstance(highlander2)));
+ assertMatchesStore(highlander);
+ }
+
+ @Test
+ public void shouldFindNodeItemUsingStartingNodeAndRelativePath() throws Exception {
+ AbstractJcrNode hybrid = cache.findJcrNode(null, path("/Cars/Hybrid"));
+ AbstractJcrItem highlander = cache.findJcrItem(hybrid.nodeId, hybrid.path(), path("../Hybrid/Toyota Highlander"));
+ assertThat(highlander.isNode(), is(true));
+ // Make sure this is the same as if we find it directly ...
+ AbstractJcrNode highlander2 = cache.findJcrNode(null, path("/Cars/Hybrid/Toyota Highlander"));
+ assertThat((AbstractJcrNode)highlander, is(sameInstance(highlander2)));
+ }
+
+ @Test
+ public void shouldFindPropertyItemUsingStartingNodeAndRelativePath() throws Exception {
+ AbstractJcrNode hybrid = cache.findJcrNode(null, path("/Cars/Hybrid"));
+ AbstractJcrItem altimaModel = cache.findJcrItem(hybrid.nodeId, hybrid.path(), path("../Hybrid/Nissan Altima/vehix:model"));
+ assertThat(altimaModel.isNode(), is(false));
+ javax.jcr.Node altimaModelParent = altimaModel.getParent();
+ javax.jcr.Node altima = cache.findJcrNode(null, path("/Cars/Hybrid/Nissan Altima"));
+ assertThat(altima, is(sameInstance(altimaModelParent)));
+ }
+
+ @Test
+ public void shouldFindPropertyForNodeUsingPropertyName() throws Exception {
+ AbstractJcrNode altima = cache.findJcrNode(null, path("/Cars/Hybrid/Nissan Altima"));
+ AbstractJcrItem altimaModel = cache.findJcrProperty(altima.nodeId, altima.path(), name("vehix:model"));
+ assertThat(altimaModel.isNode(), is(false));
+ javax.jcr.Node altimaModelParent = altimaModel.getParent();
+ assertThat(altima, is(sameInstance(altimaModelParent)));
+ }
+
+ @Test
+ public void shouldFindPropertiesForNode() throws Exception {
+ AbstractJcrNode altima = cache.findJcrNode(null, path("/Cars/Hybrid/Nissan Altima"));
+ Collection<AbstractJcrProperty> properties = cache.findJcrPropertiesFor(altima.nodeId, altima.path());
+ assertThat(properties.size(), is(7));
+ List<AbstractJcrProperty> properties2 = new ArrayList<AbstractJcrProperty>(properties);
+ Collections.sort(properties2);
+ Iterator<AbstractJcrProperty> iter = properties2.iterator();
+ assertProperty(iter.next(), altima, "jcr:primaryType", PropertyType.NAME, "vehix:car");
+ assertProperty(iter.next(), altima, "vehix:maker", PropertyType.STRING, "Nissan");
+ assertProperty(iter.next(), altima, "vehix:model", PropertyType.STRING, "Altima");
+ assertProperty(iter.next(), altima, "vehix:mpgCity", PropertyType.LONG, "23");
+ assertProperty(iter.next(), altima, "vehix:mpgHighway", PropertyType.LONG, "32");
+ assertProperty(iter.next(), altima, "vehix:msrp", PropertyType.STRING, "$18,260");
+ assertProperty(iter.next(), altima, "vehix:year", PropertyType.LONG, "2008");
+ }
+
+ @Test
+ public void shouldRefreshWithoutKeepingChanges() throws Exception {
+ AbstractJcrNode altima1 = cache.findJcrNode(null, path("/Cars/Hybrid/Nissan Altima"));
+ assertMatchesStore(altima1);
+ assertThat(altima1.isNew(), is(false));
+
+ // Add the child ...
+ AbstractJcrNode hybrid = cache.findJcrNode(null, path("/Cars/Hybrid"));
+ javax.jcr.Node child = hybrid.addNode("child");
+ assertThat(hybrid.isModified(), is(true));
+ assertThat(child.isNew(), is(true));
+ assertThat(hybrid.hasNode("child"), is(true));
+
+ cache.refresh(false);
+ AbstractJcrNode altima2 = cache.findJcrNode(null, path("/Cars/Hybrid/Nissan Altima"));
+ assertMatchesStore(altima2);
+
+ // The objects should no longer be the same ...
+ assertThat(altima1, is(altima2));
+ assertThat(altima1, is(not(sameInstance(altima2))));
+ assertThat(altima2.isNew(), is(false));
+
+ // The new child should no longer exist ...
+ assertThat(hybrid.hasNode("child"), is(false));
+ }
+
+ @Test
+ public void shouldRefreshAndKeepChanges() throws Exception {
+ AbstractJcrNode altima1 = cache.findJcrNode(null, path("/Cars/Hybrid/Nissan Altima"));
+ assertMatchesStore(altima1);
+ assertThat(altima1.isNew(), is(false));
+
+ // Add the child ...
+ AbstractJcrNode hybrid = cache.findJcrNode(null, path("/Cars/Hybrid"));
+ javax.jcr.Node child = hybrid.addNode("child");
+ assertThat(hybrid.isModified(), is(true));
+ assertThat(child.isNew(), is(true));
+ assertThat(hybrid.hasNode("child"), is(true));
+
+ cache.refresh(true);
+ AbstractJcrNode altima2 = cache.findJcrNode(null, path("/Cars/Hybrid/Nissan Altima"));
+ assertMatchesStore(altima2);
+
+ // The objects should still be the same ...
+ assertThat(altima1, is(altima2));
+ assertThat(altima1, is(sameInstance(altima2)));
+ assertThat(altima2.isNew(), is(false));
+
+ // The new child should still exist ...
+ assertThat(hybrid.hasNode("child"), is(true));
+ }
+
+ @Test
+ public void shouldSaveChanges() throws Exception {
+ AbstractJcrNode altima1 = cache.findJcrNode(null, path("/Cars/Hybrid/Nissan Altima"));
+ assertMatchesStore(altima1);
+ assertThat(altima1.isNew(), is(false));
+
+ // Add the child ...
+ AbstractJcrNode hybrid = cache.findJcrNode(null, path("/Cars/Hybrid"));
+ javax.jcr.Node child = hybrid.addNode("child");
+ assertThat(hybrid.isModified(), is(true));
+ assertThat(child.isNew(), is(true));
+ assertThat(hybrid.hasNode("child"), is(true));
+
+ cache.save();
+ AbstractJcrNode altima2 = cache.findJcrNode(null, path("/Cars/Hybrid/Nissan Altima"));
+ assertMatchesStore(altima2);
+
+ // The objects should no longer be the same ...
+ assertThat(altima1, is(altima2));
+ assertThat(altima1, is(not(sameInstance(altima2))));
+ assertThat(altima2.isNew(), is(false));
+
+ // The new child should still exist ...
+ assertThat(hybrid.hasNode("child"), is(true));
+ }
+
+ protected void assertProperty( AbstractJcrProperty property,
+ javax.jcr.Node node,
+ String name,
+ int propertyType,
+ Object... values ) throws Exception {
+ assertThat(property.getName(), is(name));
+ assertThat(property.getType(), is(propertyType));
+ assertThat(property.getParent(), is(node));
+ if (values.length > 1) {
+ int i = 0;
+ for (Value actual : property.getValues()) {
+ String actualString = actual.getString();
+ String expectedString = context.getValueFactories().getStringFactory().create(values[i]);
+ assertThat(actualString, is(expectedString));
+ assertCanObtainValue(actual, propertyType);
+ ++i;
+ }
+ // Getting the single value should result in an error ...
+ try {
+ property.getValue();
+ fail("Should not be able to call Property.getValue() on multi-valued properties");
+ } catch (ValueFormatException e) {
+ // expected ...
+ }
+ } else {
+ String actualString = property.getValue().getString();
+ String expectedString = context.getValueFactories().getStringFactory().create(values[0]);
+ assertThat(actualString, is(expectedString));
+ assertThat(actualString, is(property.getString()));
+ assertCanObtainValue(property.getValue(), propertyType);
+ // Getting the multiple values should result in an error ...
+ try {
+ property.getValues();
+ fail("Should not be able to call Property.getValues() on single-valued properties");
+ } catch (ValueFormatException e) {
+ // expected ...
+ }
+ // Check resolving the reference ...
+ if (propertyType == PropertyType.REFERENCE) {
+ javax.jcr.Node referenced = property.getNode();
+ assertThat(referenced, is(notNullValue()));
+ }
+ }
+ }
+
+ protected void assertCanObtainValue( Value value,
+ int expectedType ) throws Exception {
+ switch (expectedType) {
+ case PropertyType.BINARY:
+ InputStream stream = value.getStream();
+ assertThat(stream, is(notNullValue()));
+ try {
+ stream.read();
+ } finally {
+ stream.close();
+ }
+ break;
+ case PropertyType.BOOLEAN:
+ assertThat(value.getBoolean() || !value.getBoolean(), is(true));
+ break;
+ case PropertyType.DATE:
+ Calendar cal = value.getDate();
+ assertThat(cal, is(notNullValue()));
+ break;
+ case PropertyType.DOUBLE:
+ double doubleValue = value.getDouble();
+ assertThat(doubleValue < 0.0d || doubleValue >= -1.0d, is(true));
+ break;
+ case PropertyType.LONG:
+ long longValue = value.getLong();
+ assertThat(longValue < 0L || longValue >= 0L, is(true));
+ break;
+ case PropertyType.NAME:
+ context.getValueFactories().getNameFactory().create(value.getString());
+ break;
+ case PropertyType.PATH:
+ context.getValueFactories().getPathFactory().create(value.getString());
+ break;
+ case PropertyType.REFERENCE:
+ UUID uuid = context.getValueFactories().getUuidFactory().create(value.getString());
+ assertThat(uuid, is(notNullValue()));
+ break;
+ case PropertyType.STRING:
+ value.getString();
+ break;
+ }
+ }
+
+ protected void assertMatchesStore( AbstractJcrNode jcrNode ) throws RepositoryException {
+ // Find the corresponding session node ...
+ Node<JcrNodePayload, JcrPropertyPayload> nodeInfo = cache.findNode(jcrNode.nodeId, jcrNode.path());
+ // And the graph node ...
+ org.jboss.dna.graph.Node dnaNode = store.getNodeAt(jcrNode.location);
+
+ assertThat(nodeInfo.getLocation(), is(dnaNode.getLocation()));
+ Set<Name> propertyNames = nodeInfo.getPropertyNames();
+ for (Name propertyName : propertyNames) {
+ PropertyInfo<JcrPropertyPayload> info = nodeInfo.getProperty(propertyName);
+ assertThat(info.getName(), is(propertyName));
+ assertThat(info.getProperty().getName(), is(propertyName));
+ Property actual = dnaNode.getProperty(propertyName);
+ if (actual != null) {
+ assertThat(info.getProperty().size(), is(actual.size()));
+ assertThat(info.getProperty().getValuesAsArray(), is(actual.getValuesAsArray()));
+ } else {
+ if (propertyName.equals(JcrLexicon.UUID)) {
+ // check for a DNA UUID property ...
+ actual = dnaNode.getProperty(DnaLexicon.UUID);
+ if (actual != null) {
+ assertThat(info.getProperty().size(), is(actual.size()));
+ assertThat(info.getProperty().getValuesAsArray(), is(actual.getValuesAsArray()));
+ } else {
+ fail("missing property \"" + propertyName + "\" on " + dnaNode);
+ }
+ } else if (propertyName.equals(JcrLexicon.PRIMARY_TYPE)) {
+ // This is okay
+ } else if (propertyName.equals(DnaIntLexicon.MULTI_VALUED_PROPERTIES)) {
+ // This is okay
+ } else {
+ fail("missing property \"" + propertyName + "\" on " + dnaNode);
+ }
+ }
+ }
+ }
+}
Property changes on: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/SessionCacheTest2.java
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Modified: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/Vehicles.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/Vehicles.java 2009-07-09 16:23:09 UTC (rev 1081)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/Vehicles.java 2009-07-09 16:26:04 UTC (rev 1082)
@@ -69,6 +69,7 @@
NodeTypeTemplate car = new JcrNodeTypeTemplate(context);
car.setName("vehix:car");
car.setOrderableChildNodes(true);
+ car.setPrimaryItemName("vehix:model");
property = new JcrPropertyDefinitionTemplate(context);
property.setName("vehix:maker");
Deleted: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/cache/AbstractChildrenTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/cache/AbstractChildrenTest.java 2009-07-09 16:23:09 UTC (rev 1081)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/cache/AbstractChildrenTest.java 2009-07-09 16:26:04 UTC (rev 1082)
@@ -1,168 +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.
- *
- * 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.jcr.cache;
-
-import static org.hamcrest.core.Is.is;
-import static org.hamcrest.core.IsNull.notNullValue;
-import static org.hamcrest.core.IsSame.sameInstance;
-import static org.junit.Assert.assertThat;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.UUID;
-import java.util.concurrent.atomic.AtomicInteger;
-import org.jboss.dna.graph.ExecutionContext;
-import org.jboss.dna.graph.property.Name;
-import org.jboss.dna.graph.property.NameFactory;
-import org.jboss.dna.graph.property.PathFactory;
-import org.jboss.dna.graph.property.Path.Segment;
-import org.junit.Before;
-import org.junit.Test;
-
-/**
- * @param <ChildrenType> the type for the {@link #children} variable
- */
-public abstract class AbstractChildrenTest<ChildrenType extends Children> {
-
- protected ChildrenType children;
- protected ExecutionContext context;
- protected PathFactory pathFactory;
- protected NameFactory nameFactory;
- protected UUID parentUuid;
- protected UUID firstChildUuid;
- protected Name firstChildName;
- protected ChildNode firstChild;
-
- @Before
- public void beforeEach() {
- context = new ExecutionContext();
- pathFactory = context.getValueFactories().getPathFactory();
- nameFactory = context.getValueFactories().getNameFactory();
-
- parentUuid = UUID.randomUUID();
- firstChildUuid = UUID.randomUUID();
- firstChildName = nameFactory.create("childA");
- }
-
- protected Name name( String name ) {
- return nameFactory.create(name);
- }
-
- protected void assertChildNodesWithName( Children children,
- String childName,
- Object... childNodes ) {
- Name name = name(childName);
- Iterator<ChildNode> iter = children.getChildren(name);
- int expectedSnsIndex = 1;
- for (Object expectedChild : childNodes) {
- assertThat(iter.hasNext(), is(true));
- ChildNode next = iter.next();
- assertThat(next.getName(), is(name));
- assertThat(next.getSnsIndex(), is(expectedSnsIndex++));
- if (expectedChild instanceof ChildNode) {
- assertThat(next, is(sameInstance(expectedChild)));
- } else if (expectedChild instanceof Name) {
- Name expectedName = (Name)expectedChild;
- assertThat(next.getName(), is(expectedName));
- } else if (expectedChild instanceof String) {
- Name expectedName = name((String)expectedChild);
- assertThat(next.getName(), is(expectedName));
- }
- }
- assertThat(iter.hasNext(), is(false));
- }
-
- protected void assertChildNodes( Children children,
- Object... childNodes ) {
- Iterator<ChildNode> iter = children.iterator();
- Map<Name, AtomicInteger> expectedSnsIndexes = new HashMap<Name, AtomicInteger>();
- for (Object expectedChild : childNodes) {
- assertThat(iter.hasNext(), is(true));
- ChildNode next = iter.next();
- Name actualName = next.getName();
- // Check the name ...
- if (expectedChild instanceof ChildNode) {
- assertThat(next, is(sameInstance(expectedChild)));
- } else if (expectedChild instanceof Name) {
- Name expectedName = (Name)expectedChild;
- assertThat(actualName, is(expectedName));
- } else if (expectedChild instanceof String) {
- Name expectedName = name((String)expectedChild);
- assertThat(actualName, is(expectedName));
- }
- // Check the SNS ...
- AtomicInteger expectedSns = expectedSnsIndexes.get(actualName);
- if (expectedSns == null) {
- expectedSns = new AtomicInteger(1);
- expectedSnsIndexes.put(actualName, expectedSns);
- }
- assertThat(next.getSnsIndex(), is(expectedSns.getAndIncrement()));
- }
- assertThat(iter.hasNext(), is(false));
- }
-
- protected void assertSameContent( Children children,
- Children other ) {
- Iterator<ChildNode> iter = children.iterator();
- Iterator<ChildNode> otherIter = other.iterator();
- while (iter.hasNext()) {
- assertThat(otherIter.hasNext(), is(true));
- ChildNode next = iter.next();
- ChildNode otherNext = otherIter.next();
- assertThat(next, is(otherNext));
- }
- assertThat(iter.hasNext(), is(false));
- assertThat(otherIter.hasNext(), is(false));
- }
-
- @Test
- public void shouldFindFirstChildByUuid() {
- ChildNode firstChild = children.getChild(firstChildUuid);
- assertThat(firstChild, is(notNullValue()));
- assertThat(firstChild, is(sameInstance(this.firstChild)));
- assertThat(firstChild.getUuid(), is(firstChildUuid));
- assertThat(firstChild.getName(), is(firstChildName));
- assertThat(firstChild.getSnsIndex(), is(1));
- assertThat(firstChild.getSegment().getIndex(), is(1));
- assertThat(firstChild.getSegment().getName(), is(firstChildName));
- }
-
- @Test
- public void shouldFindFirstChildByName() {
- Segment segment = pathFactory.createSegment(firstChildName, 1);
- ChildNode firstChild = children.getChild(segment);
- assertThat(firstChild, is(notNullValue()));
- assertThat(firstChild, is(sameInstance(this.firstChild)));
- assertThat(firstChild.getUuid(), is(firstChildUuid));
- assertThat(firstChild.getName(), is(firstChildName));
- assertThat(firstChild.getSnsIndex(), is(1));
- assertThat(firstChild.getSegment().getIndex(), is(1));
- assertThat(firstChild.getSegment().getName(), is(firstChildName));
- }
-
- @Test
- public void shouldImplementToString() {
- children.toString();
- }
-}
Deleted: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/cache/ChangedChildrenTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/cache/ChangedChildrenTest.java 2009-07-09 16:23:09 UTC (rev 1081)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/cache/ChangedChildrenTest.java 2009-07-09 16:26:04 UTC (rev 1082)
@@ -1,150 +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.
- *
- * 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.jcr.cache;
-
-import static org.hamcrest.core.Is.is;
-import static org.hamcrest.core.IsSame.sameInstance;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.fail;
-import java.util.Iterator;
-import java.util.NoSuchElementException;
-import java.util.UUID;
-import org.junit.Before;
-import org.junit.Test;
-
-/**
- *
- */
-public class ChangedChildrenTest extends AbstractChildrenTest<ChangedChildren> {
-
- private ImmutableChildren original;
-
- @Override
- @Before
- public void beforeEach() {
- super.beforeEach();
-
- original = new ImmutableChildren(parentUuid);
- firstChild = original.add(firstChildName, firstChildUuid, pathFactory);
-
- children = new ChangedChildren(original);
- }
-
- @Test
- public void shouldHaveCorrectSize() {
- assertThat(children.size(), is(1));
- }
-
- @Test
- public void shouldHaveSameContentsAsOriginal() {
- assertSameContent(children, original);
- }
-
- @Test
- public void shouldFindChildrenByName() {
- Iterator<ChildNode> iter = children.getChildren(firstChildName);
- assertThat(iter.hasNext(), is(true));
- assertThat(iter.next(), is(sameInstance(firstChild)));
- assertThat(iter.hasNext(), is(false));
- try {
- iter.next();
- fail("Failed to throw exception");
- } catch (NoSuchElementException e) {
- // expected
- }
- }
-
- @Test
- public void shouldReturnSameInstanceFromWithoutIfSuppliedChildIsNotFound() {
- ChildNode nonExistant = new ChildNode(UUID.randomUUID(), pathFactory.createSegment("some segment"));
- assertThat(children.without(nonExistant.getUuid(), pathFactory), is(sameInstance((Children)children)));
- }
-
- @Test
- public void shouldReturnEmptyChildrenFromWithoutIfOnlyChildIsRemoved() {
- Children newChildren = children.without(firstChild.getUuid(), pathFactory);
- assertThat(newChildren.size(), is(0));
- }
-
- @Test
- public void shouldReturnSameInstanceFromWithIfSuppliedChildThatIsFoundInContainer() {
- assertThat(children.with(firstChildName, firstChildUuid, pathFactory), is(sameInstance((Children)children)));
- }
-
- @Test( expected = UnsupportedOperationException.class )
- public void shouldReturnIteratorThatDoesNotSupportRemoving() {
- Iterator<ChildNode> iter = children.getChildren(firstChildName);
- assertThat(iter.hasNext(), is(true));
- assertThat(iter.next(), is(sameInstance(firstChild)));
- iter.remove();
- }
-
- @Test
- public void shouldReturnChangedChildrenFromWithoutIfSuppliedChildIsFound() {
- ChildNode child2 = children.add(name("childB"), UUID.randomUUID(), pathFactory);
- ChildNode child3 = children.add(name("childC"), UUID.randomUUID(), pathFactory);
- ChildNode child4 = children.add(name("childA"), UUID.randomUUID(), pathFactory);
- ChildNode child5 = children.add(name("childA"), UUID.randomUUID(), pathFactory);
- ChildNode child6 = children.add(name("childD"), UUID.randomUUID(), pathFactory);
-
- // Check that the children contains what we expect ...
- assertChildNodes(children, firstChild, child2, child3, child4, child5, child6);
- assertChildNodesWithName(children, "childA", firstChild, child4, child5);
-
- // Remove 'child4' ...
- Children result = children.without(child4.getUuid(), pathFactory);
-
- // but the result should not have child4 ...
- assertChildNodesWithName(result, "childA", firstChild, "childA");
-
- // Now check that all the child nodes are in the result, in the expected order ...
- assertChildNodes(result, firstChild, child2, child3, "childA", child6);
- }
-
- @Test
- public void shouldReturnChangedChildrenFromWithIfSuppliedChildIsNotFound() {
- // Make sure that children contains what we expect ...
- assertChildNodes(children, firstChild);
- assertChildNodesWithName(children, "childA", firstChild);
-
- // Add a node ...
- Children result = children.with(name("childB"), UUID.randomUUID(), pathFactory);
- assertThat(result, is(sameInstance((Children)children)));
- assertChildNodes(children, firstChild, "childB");
- assertChildNodesWithName(children, "childA", firstChild);
-
- // Add another node ...
- result = children.with(name("childC"), UUID.randomUUID(), pathFactory);
- assertThat(result, is(sameInstance((Children)children)));
- assertChildNodes(children, firstChild, "childB", "childC");
- assertChildNodesWithName(children, "childA", firstChild);
-
- // Add another node ...
- result = children.with(name("childA"), UUID.randomUUID(), pathFactory);
- assertThat(result, is(sameInstance((Children)children)));
- assertChildNodes(children, firstChild, "childB", "childC", "childA");
- assertChildNodesWithName(children, "childA", firstChild, "childA");
- }
-
-}
Deleted: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/cache/ChangedNodeInfoTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/cache/ChangedNodeInfoTest.java 2009-07-09 16:23:09 UTC (rev 1081)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/cache/ChangedNodeInfoTest.java 2009-07-09 16:26:04 UTC (rev 1082)
@@ -1,671 +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.
- *
- * 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.jcr.cache;
-
-import static org.hamcrest.core.Is.is;
-import static org.hamcrest.core.IsNot.not;
-import static org.hamcrest.core.IsNull.notNullValue;
-import static org.hamcrest.core.IsNull.nullValue;
-import static org.hamcrest.core.IsSame.sameInstance;
-import static org.jboss.dna.jcr.cache.IsNodeInfoWithChildrenHavingNames.hasChild;
-import static org.jboss.dna.jcr.cache.IsNodeInfoWithChildrenHavingNames.hasChildren;
-import static org.jboss.dna.jcr.cache.IsNodeInfoWithChildrenHavingUuids.hasChild;
-import static org.jboss.dna.jcr.cache.IsNodeInfoWithChildrenHavingUuids.hasChildren;
-import static org.junit.Assert.assertThat;
-import static org.junit.matchers.JUnitMatchers.hasItems;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.stub;
-import java.util.HashMap;
-import java.util.LinkedList;
-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.JcrLexicon;
-import org.jboss.dna.graph.Location;
-import org.jboss.dna.graph.property.Name;
-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.jcr.NodeDefinitionId;
-import org.junit.Before;
-import org.junit.Test;
-
-/**
- *
- */
-public class ChangedNodeInfoTest {
-
- private ExecutionContext context;
- private PathFactory pathFactory;
- private NodeInfo original;
- private UUID uuid;
- private Name primaryTypeName;
- private Name[] requiredPrimaryTypes;
- private Location location;
- private NodeDefinitionId definitionId;
- private ChangedChildren children;
- private Map<Name, PropertyInfo> properties;
- private List<Name> mixinTypeNames;
- private ChangedNodeInfo changes;
-
- @Before
- public void beforeEach() {
- context = new ExecutionContext();
- context.getNamespaceRegistry().register("acme", "http://example.com/acme");
- pathFactory = context.getValueFactories().getPathFactory();
-
- // Set up the original ...
- uuid = UUID.randomUUID();
- location = Location.create(uuid);
- primaryTypeName = name("acme:geniusType");
- requiredPrimaryTypes = new Name[] {name("acme:requiredTypeA"), name("acme:requiredTypeB")};
- definitionId = new NodeDefinitionId(name("acme:geniusContainerType"), name("acme:geniuses"), requiredPrimaryTypes);
- children = new ChangedChildren(uuid);
- properties = new HashMap<Name, PropertyInfo>();
- mixinTypeNames = new LinkedList<Name>();
- original = new ImmutableNodeInfo(location, primaryTypeName, mixinTypeNames, definitionId, uuid, children, properties);
-
- // Create the changed node representation ...
- changes = new ChangedNodeInfo(original);
- }
-
- protected Name name( String name ) {
- return context.getValueFactories().getNameFactory().create(name);
- }
-
- protected Segment segment( String segment ) {
- return pathFactory.createSegment(segment);
- }
-
- /**
- * Utility to set a property to the original node representation. This will replace any existing property with the same name.
- *
- * @param name the name of the property; may not be null
- * @return the new property representation; never null
- */
- protected PropertyInfo makePropertyInOriginal( String name ) {
- Name propName = name(name);
- PropertyInfo propertyInfo = mock(PropertyInfo.class);
- stub(propertyInfo.getPropertyName()).toReturn(propName);
- properties.put(propName, propertyInfo);
- return propertyInfo;
- }
-
- /**
- * Utility to change a property in the changed representation.
- *
- * @param name the name of the property to change; may not be null
- * @return the new property; never null
- */
- protected PropertyInfo setPropertyInChanged( String name ) {
- Name propName = name(name);
- PropertyInfo propertyInfo = mock(PropertyInfo.class);
- stub(propertyInfo.getPropertyName()).toReturn(propName);
- changes.setProperty(propertyInfo, context.getValueFactories());
- return propertyInfo;
- }
-
- protected ChildNode makeChildInOriginal( String childName ) {
- ChildNode newChild = children.add(name(childName), UUID.randomUUID(), pathFactory);
- return newChild;
- }
-
- protected ChildNode addChildInChanged( String childName ) {
- ChildNode newChild = changes.addChild(name(childName), UUID.randomUUID(), pathFactory);
- // Make sure that the 'changes' object no longer returns the original object's children object
- assertThat(changes.getChildren(), is(not(sameInstance(original.getChildren()))));
- return newChild;
- }
-
- protected void removeChildFromChanged( ChildNode child ) {
- // Verify that a child node with the supplied UUID is contained.
- // Note that it may not be the same ChildNode instance if another SNS node with smaller index was removed
- assertThat(changes.getChildren().getChild(child.getUuid()), is(notNullValue()));
- // Now remove the child, making sure the result is the same as the next 'getChildren()' call ...
- assertThat(changes.removeChild(child.getUuid(), pathFactory), is(notNullValue()));
- // Verify it no longer exists ...
- assertThat(changes.getChildren().getChild(child.getUuid()), is(nullValue()));
- }
-
- @Test
- public void shouldNotBeNew() {
- assertThat(changes.isNew(), is(false));
- }
-
- @Test
- public void shouldBeModified() {
- assertThat(changes.isModified(), is(true));
- }
-
- @Test
- public void shouldHaveLocationFromOriginal() {
- assertThat(changes.getOriginalLocation(), is(sameInstance(location)));
- }
-
- @Test
- public void shouldHaveParentUuidFromOriginal() {
- assertThat(changes.getParent(), is(sameInstance(uuid)));
- }
-
- @Test
- public void shouldHavePrimaryTypeNameFromOriginal() {
- assertThat(changes.getPrimaryTypeName(), is(sameInstance(primaryTypeName)));
- }
-
- @Test
- public void shouldHaveMixinTypeNamesFromOriginal() {
- assertThat(changes.getMixinTypeNames(), is(sameInstance(mixinTypeNames)));
- }
-
- @Test
- public void shouldUpdateMixinTypeNamesWhenSettingJcrMixinTypeProperty() {
- // Create the DNA property ...
- Property mixinTypes = context.getPropertyFactory().create(JcrLexicon.MIXIN_TYPES, "dna:type1", "dna:type2");
-
- // Modify the property ...
- PropertyInfo newPropertyInfo = mock(PropertyInfo.class);
- stub(newPropertyInfo.getPropertyName()).toReturn(mixinTypes.getName());
- stub(newPropertyInfo.getProperty()).toReturn(mixinTypes);
- PropertyInfo previous = changes.setProperty(newPropertyInfo, context.getValueFactories());
- assertThat(previous, is(nullValue()));
-
- // Verify that the mixin types were updated ...
- assertThat(changes.getProperty(name("jcr:mixinTypes")), is(sameInstance(newPropertyInfo)));
- assertThat(changes.getMixinTypeNames(), hasItems(name("dna:type2"), name("dna:type1")));
- }
-
- @Test
- public void shouldHaveNodeDefinitionIdFromOriginal() {
- assertThat(changes.getDefinitionId(), is(sameInstance(definitionId)));
- }
-
- @Test
- public void shouldHaveChildrenFromOriginal() {
- assertThat(changes.getChildren(), is(sameInstance((Children)children)));
-
- ChildNode childA = makeChildInOriginal("childA");
- assertThat(changes.getChildren().size(), is(1));
- assertThat(changes.getChildren().getChild(childA.getUuid()), is(sameInstance(childA)));
- assertThat(changes.getChildren(), hasChild(segment("childA[1]")));
- assertThat(changes.getChildren(), hasChild(childA.getUuid()));
- }
-
- @Test
- public void shouldHaveChildrenAfterAddingChild() {
- // Set up the original ...
- ChildNode childA1 = makeChildInOriginal("childA");
- ChildNode childB1 = makeChildInOriginal("childB");
- ChildNode childA2 = makeChildInOriginal("childA");
- assertThat(changes.getChildren().size(), is(3));
-
- // Add child ...
- ChildNode childA3 = addChildInChanged("childA");
-
- // Verify that all children are there in the proper order ...
- assertThat(changes.getChildren().size(), is(4));
- assertThat(changes.getChildren(), hasChildren(segment("childA[1]"),
- segment("childB[1]"),
- segment("childA[2]"),
- segment("childA[3]")));
- assertThat(changes.getChildren(), hasChildren(childA1.getUuid(), childB1.getUuid(), childA2.getUuid(), childA3.getUuid()));
- assertThat(changes.getChildren(), hasItems(childA1, childB1, childA2, childA3));
- }
-
- @Test
- public void shouldHaveChildrenAfterAddingMultipleChildren() {
- // Set up the original ...
- ChildNode childA1 = makeChildInOriginal("childA");
- ChildNode childB1 = makeChildInOriginal("childB");
- ChildNode childA2 = makeChildInOriginal("childA");
- assertThat(changes.getChildren().size(), is(3));
-
- // Add some children in the changed representation ...
- ChildNode childA3 = addChildInChanged("childA");
- ChildNode childC1 = addChildInChanged("childC");
- ChildNode childC2 = addChildInChanged("childC");
-
- // Verify that all children are there in the proper order ...
- assertThat(changes.getChildren().size(), is(6));
- assertThat(changes.getChildren(), hasChildren(segment("childA[1]"),
- segment("childB[1]"),
- segment("childA[2]"),
- segment("childA[3]"),
- segment("childC[1]"),
- segment("childC[2]")));
- assertThat(changes.getChildren(), hasChildren(childA1.getUuid(),
- childB1.getUuid(),
- childA2.getUuid(),
- childA3.getUuid(),
- childC1.getUuid(),
- childC2.getUuid()));
- assertThat(changes.getChildren(), hasItems(childA1, childB1, childA2, childA3, childC1, childC2));
- }
-
- @Test
- public void shouldHaveChildrenAfterAddingMultipleChildrenAndRemovingOthers() {
- // Set up the original ...
- ChildNode childA1 = makeChildInOriginal("childA");
- ChildNode childB1 = makeChildInOriginal("childB");
- ChildNode childA2 = makeChildInOriginal("childA");
- assertThat(changes.getChildren().size(), is(3));
-
- // Add some children in the changed representation ...
- ChildNode childA3 = addChildInChanged("childA");
- ChildNode childC1 = addChildInChanged("childC");
- ChildNode childC2 = addChildInChanged("childC");
-
- // Delete a child that was added and another that was an original ...
- removeChildFromChanged(childC1);
- removeChildFromChanged(childA2);
-
- // Verify that all children are there in the proper order ...
- assertThat(changes.getChildren().size(), is(4));
- assertThat(changes.getChildren(), hasChildren(segment("childA[1]"),
- segment("childB[1]"),
- segment("childA[2]"),
- segment("childC[1]")));
- assertThat(changes.getChildren(), hasChildren(childA1.getUuid(), childB1.getUuid(), childA3.getUuid(), childC2.getUuid()));
- }
-
- @Test
- public void shouldHaveChildrenAfterAddingMultipleChildrenAndThenRemovingThoseJustAdded() {
- // Set up the original ...
- ChildNode childA1 = makeChildInOriginal("childA");
- ChildNode childB1 = makeChildInOriginal("childB");
- ChildNode childA2 = makeChildInOriginal("childA");
- assertThat(changes.getChildren().size(), is(3));
-
- // Add some children in the changed representation ...
- ChildNode childA3 = addChildInChanged("childA");
- ChildNode childC1 = addChildInChanged("childC");
- ChildNode childC2 = addChildInChanged("childC");
-
- // Delete a child that was added and another that was an original...
- removeChildFromChanged(childA3);
- removeChildFromChanged(childC1); // causes replacement of 'childC2' with lower SNS index
- removeChildFromChanged(childC2);
-
- // Verify that all children are there in the proper order ...
- assertThat(changes.getChildren().size(), is(3));
- assertThat(changes.getChildren(), hasChildren(segment("childA[1]"), segment("childB[1]"), segment("childA[2]")));
- assertThat(changes.getChildren(), hasChildren(childA1.getUuid(), childB1.getUuid(), childA2.getUuid()));
-
- // Do it again, but change the order of delete to delete from the back ...
-
- // Add some children in the changed representation ...
- childA3 = addChildInChanged("childA");
- childC1 = addChildInChanged("childC");
- childC2 = addChildInChanged("childC");
-
- // Delete a child that was added and another that was an original ...
- removeChildFromChanged(childC2);
- removeChildFromChanged(childC1);
- removeChildFromChanged(childA3);
-
- // Verify that all children are there in the proper order ...
- assertThat(changes.getChildren().size(), is(3));
- assertThat(changes.getChildren(), hasChildren(segment("childA[1]"), segment("childB[1]"), segment("childA[2]")));
- assertThat(changes.getChildren(), hasChildren(childA1.getUuid(), childB1.getUuid(), childA2.getUuid()));
-
- }
-
- @Test
- public void shouldHaveChildrenAfterDeletingChild() {
- // Set up the original ...
- ChildNode childA1 = makeChildInOriginal("childA");
- ChildNode childB1 = makeChildInOriginal("childB");
- ChildNode childA2 = makeChildInOriginal("childA");
- assertThat(changes.getChildren().size(), is(3));
-
- // Delete a child that was added and another that was an original ...
- removeChildFromChanged(childA1);
-
- // Verify that all children are there in the proper order ...
- assertThat(changes.getChildren().size(), is(2));
- assertThat(changes.getChildren(), hasChildren(segment("childB[1]"), segment("childA[1]")));
- assertThat(changes.getChildren(), hasChildren(childB1.getUuid(), childA2.getUuid()));
- }
-
- @Test
- public void shouldHaveChildrenAfterDeletingMultipleChildren() {
- // Set up the original ...
- ChildNode childA1 = makeChildInOriginal("childA");
- ChildNode childB1 = makeChildInOriginal("childB");
- ChildNode childA2 = makeChildInOriginal("childA");
- assertThat(changes.getChildren().size(), is(3));
-
- // Delete a child that was added and another that was an original ...
- removeChildFromChanged(childA1);
- removeChildFromChanged(childA2);
-
- // Verify that all children are there in the proper order ...
- assertThat(changes.getChildren().size(), is(1));
- assertThat(changes.getChildren(), hasChildren(segment("childB[1]")));
- assertThat(changes.getChildren(), hasChildren(childB1.getUuid()));
- }
-
- @Test
- public void shouldHaveChildrenAfterDeletingAllChildrenFromTheFirsttChildToTheLast() {
- // Set up the original ...
- ChildNode childA1 = makeChildInOriginal("childA");
- ChildNode childB1 = makeChildInOriginal("childB");
- ChildNode childA2 = makeChildInOriginal("childA");
- assertThat(changes.getChildren().size(), is(3));
-
- // Delete all children, from the front to the back ...
- removeChildFromChanged(childA1); // causes replacement of 'childA2' with lower SNS index
- removeChildFromChanged(childA2);
- removeChildFromChanged(childB1);
-
- // Verify that all children have been removed ...
- assertThat(changes.getChildren().size(), is(0));
- }
-
- @Test
- public void shouldHaveChildrenAfterDeletingAllChildrenFromTheLastChildToTheFirst() {
- // Set up the original ...
- ChildNode childA1 = makeChildInOriginal("childA");
- ChildNode childB1 = makeChildInOriginal("childB");
- ChildNode childA2 = makeChildInOriginal("childA");
- assertThat(changes.getChildren().size(), is(3));
-
- // Delete all children, from the back to the front ...
- removeChildFromChanged(childA2);
- removeChildFromChanged(childB1);
- removeChildFromChanged(childA1);
-
- // Verify that all children have been removed ...
- assertThat(changes.getChildren().size(), is(0));
- }
-
- @Test
- public void shouldHaveChildrenAfterAddingSomeChildrenThenDeletingAllChildrenFromTheFirstChildToTheLast() {
- // Set up the original ...
- ChildNode childA1 = makeChildInOriginal("childA");
- ChildNode childB1 = makeChildInOriginal("childB");
- ChildNode childA2 = makeChildInOriginal("childA");
- assertThat(changes.getChildren().size(), is(3));
-
- // Add some children in the changed representation ...
- ChildNode childA3 = addChildInChanged("childA");
- ChildNode childC1 = addChildInChanged("childC");
- ChildNode childC2 = addChildInChanged("childC");
-
- // Delete all children, from the front to the back ...
- removeChildFromChanged(childA3);
- removeChildFromChanged(childC1); // causes replacement of 'childC2' with lower SNS index
- removeChildFromChanged(childC2);
- removeChildFromChanged(childA1); // causes replacement of 'childA2' with lower SNS index
- removeChildFromChanged(childB1);
- removeChildFromChanged(childA2);
-
- // Verify that all children have been removed ...
- assertThat(changes.getChildren().size(), is(0));
- }
-
- @Test
- public void shouldHaveChildrenAfterAddingSomeChildrenThenDeletingAllChildrenFromTheLastChildToTheFirst() {
- // Set up the original ...
- ChildNode childA1 = makeChildInOriginal("childA");
- ChildNode childB1 = makeChildInOriginal("childB");
- ChildNode childA2 = makeChildInOriginal("childA");
- assertThat(changes.getChildren().size(), is(3));
-
- // Add some children in the changed representation ...
- ChildNode childA3 = addChildInChanged("childA");
- ChildNode childC1 = addChildInChanged("childC");
- ChildNode childC2 = addChildInChanged("childC");
-
- // Delete all children, from the back to the front ...
- removeChildFromChanged(childC2);
- removeChildFromChanged(childC1);
- removeChildFromChanged(childA3);
- removeChildFromChanged(childA2);
- removeChildFromChanged(childB1);
- removeChildFromChanged(childA1);
-
- // Verify that all children have been removed ...
- assertThat(changes.getChildren().size(), is(0));
- }
-
- @Test
- public void shouldHaveChildrenAfterReorderingChildren() {
-
- }
-
- @Test
- @SuppressWarnings( "unused" )
- public void shouldNotRemoveFromNodeInfoWithNoChildChangesAChildThatMatchesSegmentButNotUuid() {
- // Set up the original ...
- ChildNode childA1 = makeChildInOriginal("childA");
- ChildNode childB1 = makeChildInOriginal("childB");
- ChildNode childA2 = makeChildInOriginal("childA");
- assertThat(changes.getChildren().size(), is(3));
-
- // Create a bogus node that has a new UUID but with the same segment as 'childA3' ...
- Children before = changes.getChildren();
- int beforeSize = before.size();
- assertThat(changes.removeChild(UUID.randomUUID(), pathFactory), is(nullValue()));
- Children after = changes.getChildren();
- assertThat(after.size(), is(beforeSize));
- assertThat(after, is(sameInstance(before)));
- assertThat(after, is(sameInstance(changes.getChildren())));
- }
-
- @Test
- @SuppressWarnings( "unused" )
- public void shouldNotRemoveFromNodeInfoWithSomeChildChangesAChildThatMatchesSegmentButNotUuid() {
- // Set up the original ...
- ChildNode childA1 = makeChildInOriginal("childA");
- ChildNode childB1 = makeChildInOriginal("childB");
- ChildNode childA2 = makeChildInOriginal("childA");
- assertThat(changes.getChildren().size(), is(3));
-
- // Add some children in the changed representation ...
- ChildNode childA3 = addChildInChanged("childA");
- ChildNode childC1 = addChildInChanged("childC");
- ChildNode childC2 = addChildInChanged("childC");
-
- // Create a bogus node that has a new UUID but with the same segment as 'childA3' ...
- Children before = changes.getChildren();
- int beforeSize = before.size();
- assertThat(changes.removeChild(UUID.randomUUID(), pathFactory), is(nullValue()));
- Children after = changes.getChildren();
- assertThat(after.size(), is(beforeSize));
- assertThat(after, is(sameInstance(before)));
- assertThat(after, is(sameInstance(changes.getChildren())));
- }
-
- @Test
- public void shouldFindPropertyThatHasNotBeenModifiedButIsInOriginal() {
- PropertyInfo propertyInfo = makePropertyInOriginal("test");
- assertThat(changes.getProperty(name("test")), is(sameInstance(propertyInfo)));
- }
-
- @Test
- public void shouldFindPropertyThatHasBeenModifiedFromOriginal() {
- PropertyInfo propertyInfo = makePropertyInOriginal("test");
- assertThat(changes.getProperty(name("test")), is(sameInstance(propertyInfo)));
-
- // Modify the property ...
- PropertyInfo newPropertyInfo = mock(PropertyInfo.class);
- stub(newPropertyInfo.getPropertyName()).toReturn(name("test"));
- PropertyInfo previous = changes.setProperty(newPropertyInfo, context.getValueFactories());
- assertThat(previous, is(sameInstance(propertyInfo)));
-
- // Verify we can find the new property ...
- assertThat(changes.getProperty(name("test")), is(sameInstance(newPropertyInfo)));
- }
-
- @Test
- public void shouldNotFindPropertyThatHasBeenDeletedFromOriginal() {
- PropertyInfo propertyInfo = makePropertyInOriginal("test");
- assertThat(changes.getProperty(name("test")), is(sameInstance(propertyInfo)));
-
- // Delete the property ...
- PropertyInfo previous = changes.removeProperty(name("test"));
- assertThat(previous, is(sameInstance(propertyInfo)));
-
- // Verify we can not find the new property ...
- assertThat(changes.getProperty(name("test")), is(nullValue()));
- }
-
- @Test
- public void shouldNotFindPropertyThatIsNotInOriginal() {
- assertThat(changes.getProperty(name("test")), is(nullValue()));
-
- makePropertyInOriginal("test");
- assertThat(changes.getProperty(name("nonExistant")), is(nullValue()));
- }
-
- @Test
- public void shouldFindAllPropertyNamesWhenChangedNodeHasNoChangedProperties() {
- PropertyInfo propA = makePropertyInOriginal("propA");
- PropertyInfo propB = makePropertyInOriginal("propB");
- PropertyInfo propC = makePropertyInOriginal("propC");
- PropertyInfo propD = makePropertyInOriginal("propD");
- Set<Name> names = changes.getPropertyNames();
- assertThat(names.size(), is(4));
- assertThat(names, hasItems(propA.getPropertyName(),
- propB.getPropertyName(),
- propC.getPropertyName(),
- propD.getPropertyName()));
- }
-
- @Test
- public void shouldFindAllPropertyNamesWhenChangedNodeHasDeletedAllProperties() {
- PropertyInfo propA = makePropertyInOriginal("propA");
- PropertyInfo propB = makePropertyInOriginal("propB");
- PropertyInfo propC = makePropertyInOriginal("propC");
- PropertyInfo propD = makePropertyInOriginal("propD");
- // Remove all properties ...
- assertThat(changes.removeProperty(propA.getPropertyName()), is(sameInstance(propA)));
- assertThat(changes.removeProperty(propB.getPropertyName()), is(sameInstance(propB)));
- assertThat(changes.removeProperty(propC.getPropertyName()), is(sameInstance(propC)));
- assertThat(changes.removeProperty(propD.getPropertyName()), is(sameInstance(propD)));
- // Now ask for names
- Set<Name> names = changes.getPropertyNames();
- assertThat(names.size(), is(0));
- }
-
- @Test
- public void shouldFindAllPropertyNamesWhenChangedNodeHasDeletedSomeProperties() {
- PropertyInfo propA = makePropertyInOriginal("propA");
- PropertyInfo propB = makePropertyInOriginal("propB");
- PropertyInfo propC = makePropertyInOriginal("propC");
- PropertyInfo propD = makePropertyInOriginal("propD");
- // Remove some properties ...
- assertThat(changes.removeProperty(propB.getPropertyName()), is(sameInstance(propB)));
- assertThat(changes.removeProperty(propD.getPropertyName()), is(sameInstance(propD)));
- // Now ask for names
- Set<Name> names = changes.getPropertyNames();
- assertThat(names.size(), is(2));
- assertThat(names, hasItems(propA.getPropertyName(), propC.getPropertyName()));
- }
-
- @Test
- @SuppressWarnings( "unused" )
- public void shouldFindAllPropertyNamesWhenChangedNodeHasChangedSomeProperties() {
- PropertyInfo propA = makePropertyInOriginal("propA");
- PropertyInfo propB = makePropertyInOriginal("propB");
- PropertyInfo propC = makePropertyInOriginal("propC");
- PropertyInfo propD = makePropertyInOriginal("propD");
- // Change some properties ...
- PropertyInfo propB2 = setPropertyInChanged("propB");
- PropertyInfo propC2 = setPropertyInChanged("propC");
- // Now ask for names
- Set<Name> names = changes.getPropertyNames();
- assertThat(names.size(), is(4));
- assertThat(names, hasItems(propA.getPropertyName(),
- propB2.getPropertyName(),
- propC2.getPropertyName(),
- propD.getPropertyName()));
- }
-
- @Test
- @SuppressWarnings( "unused" )
- public void shouldFindAllPropertyNamesWhenChangedNodeHasAddedSomeProperties() {
- PropertyInfo propA = makePropertyInOriginal("propA");
- PropertyInfo propB = makePropertyInOriginal("propB");
- PropertyInfo propC = makePropertyInOriginal("propC");
- PropertyInfo propD = makePropertyInOriginal("propD");
- // Add some properties ...
- PropertyInfo propE = setPropertyInChanged("propE");
- PropertyInfo propF = setPropertyInChanged("propF");
- PropertyInfo propG = setPropertyInChanged("propG");
- // Now ask for names
- Set<Name> names = changes.getPropertyNames();
- assertThat(names.size(), is(7));
- assertThat(names, hasItems(propA.getPropertyName(),
- propB.getPropertyName(),
- propC.getPropertyName(),
- propD.getPropertyName(),
- propE.getPropertyName(),
- propF.getPropertyName()));
- }
-
- @Test
- @SuppressWarnings( "unused" )
- public void shouldFindAllPropertyNamesWhenChangedNodeHasChangedAndDeletedAndAddedSomeProperties() {
- PropertyInfo propA = makePropertyInOriginal("propA");
- PropertyInfo propB = makePropertyInOriginal("propB");
- PropertyInfo propC = makePropertyInOriginal("propC");
- PropertyInfo propD = makePropertyInOriginal("propD");
- // Change some properties ...
- PropertyInfo propB2 = setPropertyInChanged("propB");
- PropertyInfo propC2 = setPropertyInChanged("propC");
- // Add some properties ...
- PropertyInfo propE = setPropertyInChanged("propE");
- // Remove some properties ...
- assertThat(changes.removeProperty(propB2.getPropertyName()), is(sameInstance(propB2)));
- assertThat(changes.removeProperty(propD.getPropertyName()), is(sameInstance(propD)));
- // Now ask for names
- Set<Name> names = changes.getPropertyNames();
- assertThat(names.size(), is(3));
- assertThat(names, hasItems(propA.getPropertyName(), propC2.getPropertyName(), propE.getPropertyName()));
- }
-
- @Test
- @SuppressWarnings( "unused" )
- public void shouldFindAllPropertyNamesWhenChangedNodeHasChangedAndDeletedAllProperties() {
- PropertyInfo propA = makePropertyInOriginal("propA");
- PropertyInfo propB = makePropertyInOriginal("propB");
- PropertyInfo propC = makePropertyInOriginal("propC");
- PropertyInfo propD = makePropertyInOriginal("propD");
- // Change some properties ...
- PropertyInfo propB2 = setPropertyInChanged("propB");
- PropertyInfo propC2 = setPropertyInChanged("propC");
- // Remove all properties ...
- assertThat(changes.removeProperty(propA.getPropertyName()), is(sameInstance(propA)));
- assertThat(changes.removeProperty(propB2.getPropertyName()), is(sameInstance(propB2)));
- assertThat(changes.removeProperty(propC2.getPropertyName()), is(sameInstance(propC2)));
- assertThat(changes.removeProperty(propD.getPropertyName()), is(sameInstance(propD)));
- // Now ask for names
- Set<Name> names = changes.getPropertyNames();
- assertThat(names.size(), is(0));
- }
-
-}
Deleted: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/cache/ImmutableChildrenTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/cache/ImmutableChildrenTest.java 2009-07-09 16:23:09 UTC (rev 1081)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/cache/ImmutableChildrenTest.java 2009-07-09 16:26:04 UTC (rev 1082)
@@ -1,141 +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.
- *
- * 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.jcr.cache;
-
-import static org.hamcrest.core.Is.is;
-import static org.hamcrest.core.IsSame.sameInstance;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.fail;
-import java.util.Iterator;
-import java.util.NoSuchElementException;
-import java.util.UUID;
-import org.junit.Before;
-import org.junit.Test;
-
-/**
- *
- */
-public class ImmutableChildrenTest extends AbstractChildrenTest<ImmutableChildren> {
-
- @Override
- @Before
- public void beforeEach() {
- super.beforeEach();
-
- children = new ImmutableChildren(parentUuid);
- firstChild = children.add(firstChildName, firstChildUuid, pathFactory);
- }
-
- @Test
- public void shouldHaveCorrectSize() {
- assertThat(children.size(), is(1));
- }
-
- @Test
- public void shouldFindChildrenByName() {
- Iterator<ChildNode> iter = children.getChildren(firstChildName);
- assertThat(iter.hasNext(), is(true));
- assertThat(iter.next(), is(sameInstance(firstChild)));
- assertThat(iter.hasNext(), is(false));
- try {
- iter.next();
- fail("Failed to throw exception");
- } catch (NoSuchElementException e) {
- // expected
- }
- }
-
- @Test( expected = UnsupportedOperationException.class )
- public void shouldReturnIteratorThatDoesNotSupportRemoving() {
- Iterator<ChildNode> iter = children.getChildren(firstChildName);
- assertThat(iter.hasNext(), is(true));
- assertThat(iter.next(), is(sameInstance(firstChild)));
- iter.remove();
- }
-
- @Test
- public void shouldReturnEmptyChildrenFromWithoutIfOnlyChildIsRemoved() {
- Children newChildren = children.without(firstChild.getUuid(), pathFactory);
- assertThat(newChildren.size(), is(0));
- }
-
- @Test
- public void shouldReturnChangedChildrenFromWithoutIfSuppliedChildIsFound() {
- ChildNode child2 = children.add(name("childB"), UUID.randomUUID(), pathFactory);
- ChildNode child3 = children.add(name("childC"), UUID.randomUUID(), pathFactory);
- ChildNode child4 = children.add(name("childA"), UUID.randomUUID(), pathFactory);
- ChildNode child5 = children.add(name("childA"), UUID.randomUUID(), pathFactory);
- ChildNode child6 = children.add(name("childD"), UUID.randomUUID(), pathFactory);
-
- // Check that the children contains what we expect ...
- assertChildNodes(children, firstChild, child2, child3, child4, child5, child6);
- assertChildNodesWithName(children, "childA", firstChild, child4, child5);
-
- // Remove 'child4' ...
- Children result = children.without(child4.getUuid(), pathFactory);
-
- // the original should not have been changed ...
- assertChildNodesWithName(children, "childA", firstChild, child4, child5);
- // but the result should not have child4 ...
- assertChildNodesWithName(result, "childA", firstChild, "childA");
-
- // Now check that all the child nodes are still in the original, in the same order ...
- assertChildNodes(children, firstChild, child2, child3, child4, child5, child6);
-
- // Now check that all the child nodes are in the result, in the expected order ...
- assertChildNodes(result, firstChild, child2, child3, "childA", child6);
- }
-
- @Test
- public void shouldReturnChangedChildrenFromWithIfSuppliedChildIsNotFound() {
- // Make sure that children contains what we expect ...
- assertChildNodes(children, firstChild);
- assertChildNodesWithName(children, "childA", firstChild);
-
- // Add a node ...
- ChangedChildren newChildren = children.with(name("childB"), UUID.randomUUID(), pathFactory);
- assertChildNodes(newChildren, firstChild, "childB");
- assertChildNodesWithName(newChildren, "childA", firstChild);
- // And make sure 'children' hasn't changed ...
- assertChildNodes(children, firstChild);
- assertChildNodesWithName(children, "childA", firstChild);
-
- // Add another node ...
- newChildren = newChildren.with(name("childC"), UUID.randomUUID(), pathFactory);
- assertChildNodes(newChildren, firstChild, "childB", "childC");
- assertChildNodesWithName(newChildren, "childA", firstChild);
- // And make sure 'children' hasn't changed ...
- assertChildNodes(children, firstChild);
- assertChildNodesWithName(children, "childA", firstChild);
-
- // Add another node ...
- newChildren = newChildren.with(name("childA"), UUID.randomUUID(), pathFactory);
- assertChildNodes(newChildren, firstChild, "childB", "childC", "childA");
- assertChildNodesWithName(newChildren, "childA", firstChild, "childA");
- // And make sure 'children' hasn't changed ...
- assertChildNodes(children, firstChild);
- assertChildNodesWithName(children, "childA", firstChild);
- }
-
-}
Deleted: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/cache/IsNodeInfoWithChildrenHavingNames.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/cache/IsNodeInfoWithChildrenHavingNames.java 2009-07-09 16:23:09 UTC (rev 1081)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/cache/IsNodeInfoWithChildrenHavingNames.java 2009-07-09 16:26:04 UTC (rev 1082)
@@ -1,84 +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.jcr.cache;
-
-import java.util.ArrayList;
-import java.util.List;
-import org.hamcrest.Description;
-import org.hamcrest.Factory;
-import org.hamcrest.Matcher;
-import org.jboss.dna.graph.property.Name;
-import org.jboss.dna.graph.property.Path;
-import org.jboss.dna.graph.property.basic.BasicPathSegment;
-import org.junit.matchers.IsCollectionContaining;
-import org.junit.matchers.TypeSafeMatcher;
-
-/**
- * A JUnit {@link TypeSafeMatcher matcher} that can be used to assert that a NodeInfo (or other
- * <code>Iterable<ChildNode></code>) has {@link ChildNode} instances with specific {@link ChildNode#getSegment() names}.
- */
-public class IsNodeInfoWithChildrenHavingNames extends TypeSafeMatcher<Children> {
- private final Matcher<Iterable<Path.Segment>> childMatcher;
-
- public IsNodeInfoWithChildrenHavingNames( Matcher<Iterable<Path.Segment>> childMatcher ) {
- this.childMatcher = childMatcher;
- }
-
- @Override
- public boolean matchesSafely( Children children ) {
- List<Path.Segment> childSegments = new ArrayList<Path.Segment>(children.size());
- for (ChildNode child : children) {
- childSegments.add(child.getSegment());
- }
- return childMatcher.matches(childSegments);
- }
-
- public void describeTo( Description description ) {
- description.appendText("children").appendDescriptionOf(childMatcher);
- }
-
- @Factory
- public static IsNodeInfoWithChildrenHavingNames hasChild( Name name,
- int sameNameSiblingIndex ) {
- Path.Segment segment = new BasicPathSegment(name, sameNameSiblingIndex);
- return new IsNodeInfoWithChildrenHavingNames(IsCollectionContaining.hasItem(segment));
- }
-
- @Factory
- public static IsNodeInfoWithChildrenHavingNames hasChild( Path.Segment child ) {
- return new IsNodeInfoWithChildrenHavingNames(IsCollectionContaining.hasItem(child));
- }
-
- @Factory
- public static IsNodeInfoWithChildrenHavingNames hasChildren( Path.Segment... childSegments ) {
- return new IsNodeInfoWithChildrenHavingNames(IsCollectionContaining.hasItems(childSegments));
- }
-
- @Factory
- public static IsNodeInfoWithChildrenHavingNames isEmpty() {
- Path.Segment[] childSegments = new Path.Segment[] {};
- return new IsNodeInfoWithChildrenHavingNames(IsCollectionContaining.hasItems(childSegments));
- }
-
-}
Deleted: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/cache/IsNodeInfoWithChildrenHavingUuids.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/cache/IsNodeInfoWithChildrenHavingUuids.java 2009-07-09 16:23:09 UTC (rev 1081)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/cache/IsNodeInfoWithChildrenHavingUuids.java 2009-07-09 16:26:04 UTC (rev 1082)
@@ -1,75 +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.jcr.cache;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.UUID;
-import org.hamcrest.Description;
-import org.hamcrest.Factory;
-import org.hamcrest.Matcher;
-import org.junit.matchers.IsCollectionContaining;
-import org.junit.matchers.TypeSafeMatcher;
-
-/**
- * A JUnit {@link TypeSafeMatcher matcher} that can be used to assert that a NodeInfo (or other
- * <code>Iterable<ChildNode></code>) has {@link ChildNode} instances with specific {@link ChildNode#getUuid() UUIDs}.
- */
-public class IsNodeInfoWithChildrenHavingUuids extends TypeSafeMatcher<Children> {
- private final Matcher<Iterable<UUID>> childMatcher;
-
- public IsNodeInfoWithChildrenHavingUuids( Matcher<Iterable<UUID>> childMatcher ) {
- this.childMatcher = childMatcher;
- }
-
- @Override
- public boolean matchesSafely( Children children ) {
- List<UUID> childSegments = new ArrayList<UUID>(children.size());
- for (ChildNode child : children) {
- childSegments.add(child.getUuid());
- }
- return childMatcher.matches(childSegments);
- }
-
- public void describeTo( Description description ) {
- description.appendText("children with UUIDs").appendDescriptionOf(childMatcher);
- }
-
- @Factory
- public static IsNodeInfoWithChildrenHavingUuids hasChild( UUID uuid ) {
- return new IsNodeInfoWithChildrenHavingUuids(IsCollectionContaining.hasItem(uuid));
- }
-
- @Factory
- public static IsNodeInfoWithChildrenHavingUuids hasChildren( UUID... uuids ) {
- return new IsNodeInfoWithChildrenHavingUuids(IsCollectionContaining.hasItems(uuids));
- }
-
- @Factory
- public static IsNodeInfoWithChildrenHavingUuids isEmpty() {
- UUID[] uuids = new UUID[] {};
- return new IsNodeInfoWithChildrenHavingUuids(IsCollectionContaining.hasItems(uuids));
- }
-
-}
Deleted: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/cache/NewNodeInfoTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/cache/NewNodeInfoTest.java 2009-07-09 16:23:09 UTC (rev 1081)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/cache/NewNodeInfoTest.java 2009-07-09 16:26:04 UTC (rev 1082)
@@ -1,672 +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.
- *
- * 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.jcr.cache;
-
-import static org.hamcrest.core.Is.is;
-import static org.hamcrest.core.IsNull.notNullValue;
-import static org.hamcrest.core.IsNull.nullValue;
-import static org.hamcrest.core.IsSame.sameInstance;
-import static org.jboss.dna.jcr.cache.IsNodeInfoWithChildrenHavingNames.hasChildren;
-import static org.jboss.dna.jcr.cache.IsNodeInfoWithChildrenHavingUuids.hasChildren;
-import static org.junit.Assert.assertThat;
-import static org.junit.matchers.JUnitMatchers.hasItems;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.stub;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-import java.util.UUID;
-import org.jboss.dna.graph.ExecutionContext;
-import org.jboss.dna.graph.JcrLexicon;
-import org.jboss.dna.graph.Location;
-import org.jboss.dna.graph.property.Name;
-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.jcr.NodeDefinitionId;
-import org.junit.Before;
-import org.junit.Test;
-
-/**
- *
- */
-public class NewNodeInfoTest {
-
- private ExecutionContext context;
- private PathFactory pathFactory;
- private UUID uuid;
- private Name primaryTypeName;
- private Name[] requiredPrimaryTypes;
- private Location location;
- private NodeDefinitionId definitionId;
- private Map<Name, PropertyInfo> properties;
- private ChangedNodeInfo changes;
-
- @Before
- public void beforeEach() {
- context = new ExecutionContext();
- context.getNamespaceRegistry().register("acme", "http://example.com/acme");
- pathFactory = context.getValueFactories().getPathFactory();
-
- // Set up the original ...
- uuid = UUID.randomUUID();
- location = Location.create(uuid);
- primaryTypeName = name("acme:geniusType");
- requiredPrimaryTypes = new Name[] {name("acme:requiredTypeA"), name("acme:requiredTypeB")};
- definitionId = new NodeDefinitionId(name("acme:geniusContainerType"), name("acme:geniuses"), requiredPrimaryTypes);
- properties = new HashMap<Name, PropertyInfo>();
-
- // Create the changed node representation ...
- changes = new NewNodeInfo(location, primaryTypeName, definitionId, uuid, properties);
- }
-
- protected Name name( String name ) {
- return context.getValueFactories().getNameFactory().create(name);
- }
-
- protected Segment segment( String segment ) {
- return pathFactory.createSegment(segment);
- }
-
- /**
- * Utility to set a property to the original node representation. This will replace any existing property with the same name.
- *
- * @param name the name of the property; may not be null
- * @return the new property representation; never null
- */
- protected PropertyInfo makePropertyInOriginal( String name ) {
- Name propName = name(name);
- PropertyInfo propertyInfo = mock(PropertyInfo.class);
- stub(propertyInfo.getPropertyName()).toReturn(propName);
- properties.put(propName, propertyInfo);
- return propertyInfo;
- }
-
- /**
- * Utility to change a property in the changed representation.
- *
- * @param name the name of the property to change; may not be null
- * @return the new property; never null
- */
- protected PropertyInfo setPropertyInChanged( String name ) {
- Name propName = name(name);
- PropertyInfo propertyInfo = mock(PropertyInfo.class);
- stub(propertyInfo.getPropertyName()).toReturn(propName);
- changes.setProperty(propertyInfo, context.getValueFactories());
- return propertyInfo;
- }
-
- protected ChildNode addChildInChanged( String childName ) {
- ChildNode newChild = changes.addChild(name(childName), UUID.randomUUID(), pathFactory);
- return newChild;
- }
-
- protected void removeChildFromChanged( ChildNode child ) {
- // Verify that a child node with the supplied UUID is contained.
- // Note that it may not be the same ChildNode instance if another SNS node with smaller index was removed
- assertThat(changes.getChildren().getChild(child.getUuid()), is(notNullValue()));
- // Now remove the child, making sure the result is the same as the next 'getChildren()' call ...
- assertThat(changes.removeChild(child.getUuid(), pathFactory), is(notNullValue()));
- // Verify it no longer exists ...
- assertThat(changes.getChildren().getChild(child.getUuid()), is(nullValue()));
- }
-
- @Test
- public void shouldBeNew() {
- assertThat(changes.isNew(), is(true));
- }
-
- @Test
- public void shouldNotBeModified() {
- assertThat(changes.isModified(), is(false));
- }
-
- @Test
- public void shouldInitiallyHaveLocation() {
- assertThat(changes.getOriginalLocation(), is(sameInstance(location)));
- }
-
- @Test
- public void shouldInitiallyHaveParentUuid() {
- assertThat(changes.getParent(), is(sameInstance(uuid)));
- }
-
- @Test
- public void shouldInitiallyHavePrimaryTypeName() {
- assertThat(changes.getPrimaryTypeName(), is(sameInstance(primaryTypeName)));
- }
-
- @Test
- public void shouldInitiallyHaveMixinNoTypeNames() {
- assertThat(changes.getMixinTypeNames().size(), is(0));
- }
-
- @Test
- public void shouldUpdateMixinTypeNamesWhenSettingJcrMixinTypeProperty() {
- // Create the DNA property ...
- Property mixinTypes = context.getPropertyFactory().create(JcrLexicon.MIXIN_TYPES, "dna:type1", "dna:type2");
-
- // Modify the property ...
- PropertyInfo newPropertyInfo = mock(PropertyInfo.class);
- stub(newPropertyInfo.getPropertyName()).toReturn(mixinTypes.getName());
- stub(newPropertyInfo.getProperty()).toReturn(mixinTypes);
- PropertyInfo previous = changes.setProperty(newPropertyInfo, context.getValueFactories());
- assertThat(previous, is(nullValue()));
-
- // Verify that the mixin types were updated ...
- assertThat(changes.getProperty(name("jcr:mixinTypes")), is(sameInstance(newPropertyInfo)));
- assertThat(changes.getMixinTypeNames(), hasItems(name("dna:type2"), name("dna:type1")));
- }
-
- @Test
- public void shouldHaveNodeDefinitionId() {
- assertThat(changes.getDefinitionId(), is(sameInstance(definitionId)));
- }
-
- @Test
- public void shouldHaveNoChildren() {
- assertThat(changes.getChildren().size(), is(0));
- }
-
- @Test
- public void shouldHaveChildrenAfterAddingChild() {
- assertThat(changes.getChildren().size(), is(0));
-
- // Add child ...
- ChildNode childA1 = addChildInChanged("childA");
- assertThat(changes.getChildren().size(), is(1));
- assertThat(changes.getChildren(), hasChildren(segment("childA")));
-
- // Add more children ...
- ChildNode childB1 = addChildInChanged("childB");
- ChildNode childA2 = addChildInChanged("childA");
- ChildNode childA3 = addChildInChanged("childA");
-
- // Verify that all children are there in the proper order ...
- assertThat(changes.getChildren().size(), is(4));
- assertThat(changes.getChildren(), hasChildren(segment("childA[1]"),
- segment("childB[1]"),
- segment("childA[2]"),
- segment("childA[3]")));
- assertThat(changes.getChildren(), hasChildren(childA1.getUuid(), childB1.getUuid(), childA2.getUuid(), childA3.getUuid()));
- assertThat(changes.getChildren(), hasItems(childA1, childB1, childA2, childA3));
- }
-
- @Test
- public void shouldHaveChildrenAfterAddingMultipleChildren() {
- assertThat(changes.getChildren().size(), is(0));
-
- // Add some children ...
- ChildNode childA1 = addChildInChanged("childA");
- ChildNode childB1 = addChildInChanged("childB");
- ChildNode childA2 = addChildInChanged("childA");
- assertThat(changes.getChildren().size(), is(3));
-
- // Add some children in the changed representation ...
- ChildNode childA3 = addChildInChanged("childA");
- ChildNode childC1 = addChildInChanged("childC");
- ChildNode childC2 = addChildInChanged("childC");
-
- // Verify that all children are there in the proper order ...
- assertThat(changes.getChildren().size(), is(6));
- assertThat(changes.getChildren(), hasChildren(segment("childA[1]"),
- segment("childB[1]"),
- segment("childA[2]"),
- segment("childA[3]"),
- segment("childC[1]"),
- segment("childC[2]")));
- assertThat(changes.getChildren(), hasChildren(childA1.getUuid(),
- childB1.getUuid(),
- childA2.getUuid(),
- childA3.getUuid(),
- childC1.getUuid(),
- childC2.getUuid()));
- assertThat(changes.getChildren(), hasItems(childA1, childB1, childA2, childA3, childC1, childC2));
- }
-
- @Test
- public void shouldHaveChildrenAfterAddingMultipleChildrenAndRemovingOthers() {
- assertThat(changes.getChildren().size(), is(0));
-
- // Add some children ...
- ChildNode childA1 = addChildInChanged("childA");
- ChildNode childB1 = addChildInChanged("childB");
- ChildNode childA2 = addChildInChanged("childA");
- assertThat(changes.getChildren().size(), is(3));
-
- // Add some children in the changed representation ...
- ChildNode childA3 = addChildInChanged("childA");
- ChildNode childC1 = addChildInChanged("childC");
- ChildNode childC2 = addChildInChanged("childC");
-
- // Delete a child that was added and another that was an original ...
- removeChildFromChanged(childC1);
- removeChildFromChanged(childA2);
-
- // Verify that all children are there in the proper order ...
- assertThat(changes.getChildren().size(), is(4));
- assertThat(changes.getChildren(), hasChildren(segment("childA[1]"),
- segment("childB[1]"),
- segment("childA[2]"),
- segment("childC[1]")));
- assertThat(changes.getChildren(), hasChildren(childA1.getUuid(), childB1.getUuid(), childA3.getUuid(), childC2.getUuid()));
- }
-
- @Test
- public void shouldHaveChildrenAfterAddingMultipleChildrenAndThenRemovingThoseJustAdded() {
- assertThat(changes.getChildren().size(), is(0));
-
- // Add some children ...
- ChildNode childA1 = addChildInChanged("childA");
- ChildNode childB1 = addChildInChanged("childB");
- ChildNode childA2 = addChildInChanged("childA");
- assertThat(changes.getChildren().size(), is(3));
-
- // Add some children in the changed representation ...
- ChildNode childA3 = addChildInChanged("childA");
- ChildNode childC1 = addChildInChanged("childC");
- ChildNode childC2 = addChildInChanged("childC");
-
- // Delete a child that was added and another that was an original...
- removeChildFromChanged(childA3);
- removeChildFromChanged(childC1); // causes replacement of 'childC2' with lower SNS index
- removeChildFromChanged(childC2);
-
- // Verify that all children are there in the proper order ...
- assertThat(changes.getChildren().size(), is(3));
- assertThat(changes.getChildren(), hasChildren(segment("childA[1]"), segment("childB[1]"), segment("childA[2]")));
- assertThat(changes.getChildren(), hasChildren(childA1.getUuid(), childB1.getUuid(), childA2.getUuid()));
-
- // Do it again, but change the order of delete to delete from the back ...
-
- // Add some children in the changed representation ...
- childA3 = addChildInChanged("childA");
- childC1 = addChildInChanged("childC");
- childC2 = addChildInChanged("childC");
-
- // Delete a child that was added and another that was an original ...
- removeChildFromChanged(childC2);
- removeChildFromChanged(childC1);
- removeChildFromChanged(childA3);
-
- // Verify that all children are there in the proper order ...
- assertThat(changes.getChildren().size(), is(3));
- assertThat(changes.getChildren(), hasChildren(segment("childA[1]"), segment("childB[1]"), segment("childA[2]")));
- assertThat(changes.getChildren(), hasChildren(childA1.getUuid(), childB1.getUuid(), childA2.getUuid()));
-
- }
-
- @Test
- public void shouldHaveChildrenAfterDeletingChild() {
- assertThat(changes.getChildren().size(), is(0));
-
- // Add some children ...
- ChildNode childA1 = addChildInChanged("childA");
- ChildNode childB1 = addChildInChanged("childB");
- ChildNode childA2 = addChildInChanged("childA");
- assertThat(changes.getChildren().size(), is(3));
-
- // Delete a child that was added and another that was an original ...
- removeChildFromChanged(childA1);
-
- // Verify that all children are there in the proper order ...
- assertThat(changes.getChildren().size(), is(2));
- assertThat(changes.getChildren(), hasChildren(segment("childB[1]"), segment("childA[1]")));
- assertThat(changes.getChildren(), hasChildren(childB1.getUuid(), childA2.getUuid()));
- }
-
- @Test
- public void shouldHaveChildrenAfterDeletingMultipleChildren() {
- assertThat(changes.getChildren().size(), is(0));
-
- // Add some children ...
- ChildNode childA1 = addChildInChanged("childA");
- ChildNode childB1 = addChildInChanged("childB");
- ChildNode childA2 = addChildInChanged("childA");
- assertThat(changes.getChildren().size(), is(3));
-
- // Delete a child that was added and another that was an original ...
- removeChildFromChanged(childA1);
- removeChildFromChanged(childA2);
-
- // Verify that all children are there in the proper order ...
- assertThat(changes.getChildren().size(), is(1));
- assertThat(changes.getChildren(), hasChildren(segment("childB[1]")));
- assertThat(changes.getChildren(), hasChildren(childB1.getUuid()));
- }
-
- @Test
- public void shouldHaveChildrenAfterDeletingAllChildrenFromTheFirsttChildToTheLast() {
- assertThat(changes.getChildren().size(), is(0));
-
- // Add some children ...
- ChildNode childA1 = addChildInChanged("childA");
- ChildNode childB1 = addChildInChanged("childB");
- ChildNode childA2 = addChildInChanged("childA");
- assertThat(changes.getChildren().size(), is(3));
-
- // Delete all children, from the front to the back ...
- removeChildFromChanged(childA1); // causes replacement of 'childA2' with lower SNS index
- removeChildFromChanged(childA2);
- removeChildFromChanged(childB1);
-
- // Verify that all children have been removed ...
- assertThat(changes.getChildren().size(), is(0));
- }
-
- @Test
- public void shouldHaveChildrenAfterDeletingAllChildrenFromTheLastChildToTheFirst() {
- assertThat(changes.getChildren().size(), is(0));
-
- // Add some children ...
- ChildNode childA1 = addChildInChanged("childA");
- ChildNode childB1 = addChildInChanged("childB");
- ChildNode childA2 = addChildInChanged("childA");
- assertThat(changes.getChildren().size(), is(3));
-
- // Delete all children, from the back to the front ...
- removeChildFromChanged(childA2);
- removeChildFromChanged(childB1);
- removeChildFromChanged(childA1);
-
- // Verify that all children have been removed ...
- assertThat(changes.getChildren().size(), is(0));
- }
-
- @Test
- public void shouldHaveChildrenAfterAddingSomeChildrenThenDeletingAllChildrenFromTheFirstChildToTheLast() {
- assertThat(changes.getChildren().size(), is(0));
-
- // Add some children ...
- ChildNode childA1 = addChildInChanged("childA");
- ChildNode childB1 = addChildInChanged("childB");
- ChildNode childA2 = addChildInChanged("childA");
- assertThat(changes.getChildren().size(), is(3));
-
- // Add some children in the changed representation ...
- ChildNode childA3 = addChildInChanged("childA");
- ChildNode childC1 = addChildInChanged("childC");
- ChildNode childC2 = addChildInChanged("childC");
-
- // Delete all children, from the front to the back ...
- removeChildFromChanged(childA3);
- removeChildFromChanged(childC1); // causes replacement of 'childC2' with lower SNS index
- removeChildFromChanged(childC2);
- removeChildFromChanged(childA1); // causes replacement of 'childA2' with lower SNS index
- removeChildFromChanged(childB1);
- removeChildFromChanged(childA2);
-
- // Verify that all children have been removed ...
- assertThat(changes.getChildren().size(), is(0));
- }
-
- @Test
- public void shouldHaveChildrenAfterAddingSomeChildrenThenDeletingAllChildrenFromTheLastChildToTheFirst() {
- assertThat(changes.getChildren().size(), is(0));
-
- // Add some children ...
- ChildNode childA1 = addChildInChanged("childA");
- ChildNode childB1 = addChildInChanged("childB");
- ChildNode childA2 = addChildInChanged("childA");
- assertThat(changes.getChildren().size(), is(3));
-
- // Add some children in the changed representation ...
- ChildNode childA3 = addChildInChanged("childA");
- ChildNode childC1 = addChildInChanged("childC");
- ChildNode childC2 = addChildInChanged("childC");
-
- // Delete all children, from the back to the front ...
- removeChildFromChanged(childC2);
- removeChildFromChanged(childC1);
- removeChildFromChanged(childA3);
- removeChildFromChanged(childA2);
- removeChildFromChanged(childB1);
- removeChildFromChanged(childA1);
-
- // Verify that all children have been removed ...
- assertThat(changes.getChildren().size(), is(0));
- }
-
- @Test
- public void shouldHaveChildrenAfterReorderingChildren() {
-
- }
-
- @Test
- @SuppressWarnings( "unused" )
- public void shouldNotRemoveFromNodeInfoWithNoChildChangesAChildThatMatchesSegmentButNotUuid() {
- assertThat(changes.getChildren().size(), is(0));
-
- // Add some children ...
- ChildNode childA1 = addChildInChanged("childA");
- ChildNode childB1 = addChildInChanged("childB");
- ChildNode childA2 = addChildInChanged("childA");
- assertThat(changes.getChildren().size(), is(3));
-
- // Create a bogus node that has a new UUID but with the same segment as 'childA3' ...
- Children before = changes.getChildren();
- int beforeSize = before.size();
- assertThat(changes.removeChild(UUID.randomUUID(), pathFactory), is(nullValue()));
- Children after = changes.getChildren();
- assertThat(after.size(), is(beforeSize));
- assertThat(after, is(sameInstance(before)));
- assertThat(after, is(sameInstance(changes.getChildren())));
- }
-
- @Test
- @SuppressWarnings( "unused" )
- public void shouldNotRemoveFromNodeInfoWithSomeChildChangesAChildThatMatchesSegmentButNotUuid() {
- assertThat(changes.getChildren().size(), is(0));
-
- // Add some children ...
- ChildNode childA1 = addChildInChanged("childA");
- ChildNode childB1 = addChildInChanged("childB");
- ChildNode childA2 = addChildInChanged("childA");
- assertThat(changes.getChildren().size(), is(3));
-
- // Add some children in the changed representation ...
- ChildNode childA3 = addChildInChanged("childA");
- ChildNode childC1 = addChildInChanged("childC");
- ChildNode childC2 = addChildInChanged("childC");
-
- // Create a bogus node that has a new UUID but with the same segment as 'childA3' ...
- Children before = changes.getChildren();
- int beforeSize = before.size();
- assertThat(changes.removeChild(UUID.randomUUID(), pathFactory), is(nullValue()));
- Children after = changes.getChildren();
- assertThat(after.size(), is(beforeSize));
- assertThat(after, is(sameInstance(before)));
- assertThat(after, is(sameInstance(changes.getChildren())));
- }
-
- @Test
- public void shouldFindPropertyThatHasNotBeenModifiedButIsInOriginal() {
- PropertyInfo propertyInfo = makePropertyInOriginal("test");
- assertThat(changes.getProperty(name("test")), is(sameInstance(propertyInfo)));
- }
-
- @Test
- public void shouldFindPropertyThatHasBeenModifiedFromOriginal() {
- PropertyInfo propertyInfo = makePropertyInOriginal("test");
- assertThat(changes.getProperty(name("test")), is(sameInstance(propertyInfo)));
-
- // Modify the property ...
- PropertyInfo newPropertyInfo = mock(PropertyInfo.class);
- stub(newPropertyInfo.getPropertyName()).toReturn(name("test"));
- PropertyInfo previous = changes.setProperty(newPropertyInfo, context.getValueFactories());
- assertThat(previous, is(sameInstance(propertyInfo)));
-
- // Verify we can find the new property ...
- assertThat(changes.getProperty(name("test")), is(sameInstance(newPropertyInfo)));
- }
-
- @Test
- public void shouldNotFindPropertyThatHasBeenDeletedFromOriginal() {
- PropertyInfo propertyInfo = makePropertyInOriginal("test");
- assertThat(changes.getProperty(name("test")), is(sameInstance(propertyInfo)));
-
- // Delete the property ...
- PropertyInfo previous = changes.removeProperty(name("test"));
- assertThat(previous, is(sameInstance(propertyInfo)));
-
- // Verify we can not find the new property ...
- assertThat(changes.getProperty(name("test")), is(nullValue()));
- }
-
- @Test
- public void shouldNotFindPropertyThatIsNotInOriginal() {
- assertThat(changes.getProperty(name("test")), is(nullValue()));
-
- makePropertyInOriginal("test");
- assertThat(changes.getProperty(name("nonExistant")), is(nullValue()));
- }
-
- @Test
- public void shouldFindAllPropertyNamesWhenChangedNodeHasNoChangedProperties() {
- PropertyInfo propA = makePropertyInOriginal("propA");
- PropertyInfo propB = makePropertyInOriginal("propB");
- PropertyInfo propC = makePropertyInOriginal("propC");
- PropertyInfo propD = makePropertyInOriginal("propD");
- Set<Name> names = changes.getPropertyNames();
- assertThat(names.size(), is(4));
- assertThat(names, hasItems(propA.getPropertyName(),
- propB.getPropertyName(),
- propC.getPropertyName(),
- propD.getPropertyName()));
- }
-
- @Test
- public void shouldFindAllPropertyNamesWhenChangedNodeHasDeletedAllProperties() {
- PropertyInfo propA = makePropertyInOriginal("propA");
- PropertyInfo propB = makePropertyInOriginal("propB");
- PropertyInfo propC = makePropertyInOriginal("propC");
- PropertyInfo propD = makePropertyInOriginal("propD");
- // Remove all properties ...
- assertThat(changes.removeProperty(propA.getPropertyName()), is(sameInstance(propA)));
- assertThat(changes.removeProperty(propB.getPropertyName()), is(sameInstance(propB)));
- assertThat(changes.removeProperty(propC.getPropertyName()), is(sameInstance(propC)));
- assertThat(changes.removeProperty(propD.getPropertyName()), is(sameInstance(propD)));
- // Now ask for names
- Set<Name> names = changes.getPropertyNames();
- assertThat(names.size(), is(0));
- }
-
- @Test
- public void shouldFindAllPropertyNamesWhenChangedNodeHasDeletedSomeProperties() {
- PropertyInfo propA = makePropertyInOriginal("propA");
- PropertyInfo propB = makePropertyInOriginal("propB");
- PropertyInfo propC = makePropertyInOriginal("propC");
- PropertyInfo propD = makePropertyInOriginal("propD");
- // Remove some properties ...
- assertThat(changes.removeProperty(propB.getPropertyName()), is(sameInstance(propB)));
- assertThat(changes.removeProperty(propD.getPropertyName()), is(sameInstance(propD)));
- // Now ask for names
- Set<Name> names = changes.getPropertyNames();
- assertThat(names.size(), is(2));
- assertThat(names, hasItems(propA.getPropertyName(), propC.getPropertyName()));
- }
-
- @Test
- @SuppressWarnings( "unused" )
- public void shouldFindAllPropertyNamesWhenChangedNodeHasChangedSomeProperties() {
- PropertyInfo propA = makePropertyInOriginal("propA");
- PropertyInfo propB = makePropertyInOriginal("propB");
- PropertyInfo propC = makePropertyInOriginal("propC");
- PropertyInfo propD = makePropertyInOriginal("propD");
- // Change some properties ...
- PropertyInfo propB2 = setPropertyInChanged("propB");
- PropertyInfo propC2 = setPropertyInChanged("propC");
- // Now ask for names
- Set<Name> names = changes.getPropertyNames();
- assertThat(names.size(), is(4));
- assertThat(names, hasItems(propA.getPropertyName(),
- propB2.getPropertyName(),
- propC2.getPropertyName(),
- propD.getPropertyName()));
- }
-
- @Test
- @SuppressWarnings( "unused" )
- public void shouldFindAllPropertyNamesWhenChangedNodeHasAddedSomeProperties() {
- PropertyInfo propA = makePropertyInOriginal("propA");
- PropertyInfo propB = makePropertyInOriginal("propB");
- PropertyInfo propC = makePropertyInOriginal("propC");
- PropertyInfo propD = makePropertyInOriginal("propD");
- // Add some properties ...
- PropertyInfo propE = setPropertyInChanged("propE");
- PropertyInfo propF = setPropertyInChanged("propF");
- PropertyInfo propG = setPropertyInChanged("propG");
- // Now ask for names
- Set<Name> names = changes.getPropertyNames();
- assertThat(names.size(), is(7));
- assertThat(names, hasItems(propA.getPropertyName(),
- propB.getPropertyName(),
- propC.getPropertyName(),
- propD.getPropertyName(),
- propE.getPropertyName(),
- propF.getPropertyName()));
- }
-
- @Test
- @SuppressWarnings( "unused" )
- public void shouldFindAllPropertyNamesWhenChangedNodeHasChangedAndDeletedAndAddedSomeProperties() {
- PropertyInfo propA = makePropertyInOriginal("propA");
- PropertyInfo propB = makePropertyInOriginal("propB");
- PropertyInfo propC = makePropertyInOriginal("propC");
- PropertyInfo propD = makePropertyInOriginal("propD");
- // Change some properties ...
- PropertyInfo propB2 = setPropertyInChanged("propB");
- PropertyInfo propC2 = setPropertyInChanged("propC");
- // Add some properties ...
- PropertyInfo propE = setPropertyInChanged("propE");
- // Remove some properties ...
- assertThat(changes.removeProperty(propB2.getPropertyName()), is(sameInstance(propB2)));
- assertThat(changes.removeProperty(propD.getPropertyName()), is(sameInstance(propD)));
- // Now ask for names
- Set<Name> names = changes.getPropertyNames();
- assertThat(names.size(), is(3));
- assertThat(names, hasItems(propA.getPropertyName(), propC2.getPropertyName(), propE.getPropertyName()));
- }
-
- @Test
- @SuppressWarnings( "unused" )
- public void shouldFindAllPropertyNamesWhenChangedNodeHasChangedAndDeletedAllProperties() {
- PropertyInfo propA = makePropertyInOriginal("propA");
- PropertyInfo propB = makePropertyInOriginal("propB");
- PropertyInfo propC = makePropertyInOriginal("propC");
- PropertyInfo propD = makePropertyInOriginal("propD");
- // Change some properties ...
- PropertyInfo propB2 = setPropertyInChanged("propB");
- PropertyInfo propC2 = setPropertyInChanged("propC");
- // Remove all properties ...
- assertThat(changes.removeProperty(propA.getPropertyName()), is(sameInstance(propA)));
- assertThat(changes.removeProperty(propB2.getPropertyName()), is(sameInstance(propB2)));
- assertThat(changes.removeProperty(propC2.getPropertyName()), is(sameInstance(propC2)));
- assertThat(changes.removeProperty(propD.getPropertyName()), is(sameInstance(propD)));
- // Now ask for names
- Set<Name> names = changes.getPropertyNames();
- assertThat(names.size(), is(0));
- }
-
-}
Modified: trunk/dna-jcr/src/test/resources/cars.xml
===================================================================
--- trunk/dna-jcr/src/test/resources/cars.xml 2009-07-09 16:23:09 UTC (rev 1081)
+++ trunk/dna-jcr/src/test/resources/cars.xml 2009-07-09 16:26:04 UTC (rev 1082)
@@ -24,25 +24,25 @@
~ 51 Franklin Street, Fifth Floor
~ Boston, MA 02110-1301 USA
-->
-<Cars xmlns:jcr="http://www.jcp.org/jcr/1.0">
+<Cars xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:vehix="http://example.com/vehicles">
<Hybrid>
- <car jcr:name="Toyota Prius" maker="Toyota" model="Prius" year="2008" msrp="$21,500" userRating="4.2" valueRating="5" mpgCity="48" mpgHighway="45"/>
- <car jcr:name="Toyota Highlander" maker="Toyota" model="Highlander" year="2008" msrp="$34,200" userRating="4" valueRating="5" mpgCity="27" mpgHighway="25"/>
- <car jcr:name="Nissan Altima" maker="Nissan" model="Altima" year="2008" msrp="$18,260" mpgCity="23" mpgHighway="32"/>
+ <car jcr:primaryType="vehix:car" jcr:name="Toyota Prius" vehix:maker="Toyota" vehix:model="Prius" vehix:year="2008" vehix:msrp="$21,500" vehix:userRating="4.2" vehix:valueRating="5" vehix:mpgCity="48" vehix:mpgHighway="45" jcr:uuid="3b9e4a2f-040e-4d65-9778-abe70ae48324"/>
+ <car jcr:primaryType="vehix:car" jcr:name="Toyota Highlander" vehix:maker="Toyota" vehix:model="Highlander" year="2008" vehix:msrp="$34,200" vehix:userRating="4" vehix:valueRating="5" vehix:mpgCity="27" vehix:mpgHighway="25"/>
+ <car jcr:primaryType="vehix:car" jcr:name="Nissan Altima" vehix:maker="Nissan" vehix:model="Altima" vehix:year="2008" vehix:msrp="$18,260" vehix:mpgCity="23" vehix:mpgHighway="32"/>
</Hybrid>
<Sports>
- <car jcr:name="Aston Martin DB9" maker="Aston Martin" model="DB9" year="2008" msrp="$171,600" userRating="5" mpgCity="12" mpgHighway="19" lengthInInches="185.5" wheelbaseInInches="108.0" engine="5,935 cc 5.9 liters V 12"/>
- <car jcr:name="Infiniti G37" maker="Infiniti" model="G37" year="2008" msrp="$34,900" userRating="3.5" valueRating="4" mpgCity="18" mpgHighway="24" />
+ <car jcr:primaryType="vehix:car" jcr:name="Aston Martin DB9" vehix:maker="Aston Martin" vehix:model="DB9" vehix:year="2008" vehix:msrp="$171,600" vehix:userRating="5" vehix:mpgCity="12" vehix:mpgHighway="19" vehix:lengthInInches="185.5" vehix:wheelbaseInInches="108.0" vehix:engine="5,935 cc 5.9 liters V 12"/>
+ <car jcr:primaryType="vehix:car" jcr:name="Infiniti G37" vehix:maker="Infiniti" vehix:model="G37" vehix:year="2008" vehix:msrp="$34,900" vehix:userRating="3.5" vehix:valueRating="4" vehix:mpgCity="18" vehix:mpgHighway="24" />
</Sports>
<Luxury>
- <car jcr:name="Cadillac DTS" maker="Cadillac" model="DTS" year="2008" engine="3.6-liter V6" userRating="0"/>
- <car jcr:name="Bentley Continental" maker="Bentley" model="Continental" year="2008" msrp="$170,990" mpgCity="10" mpgHighway="17" />
- <car jcr:name="Lexus IS350" maker="Lexus" model="IS350" year="2008" msrp="$36,305" mpgCity="18" mpgHighway="25" userRating="4" valueRating="5" />
+ <car jcr:primaryType="vehix:car" jcr:name="Cadillac DTS" vehix:maker="Cadillac" vehix:model="DTS" vehix:year="2008" vehix:engine="3.6-liter V6" vehix:userRating="0"/>
+ <car jcr:primaryType="vehix:car" jcr:name="Bentley Continental" vehix:maker="Bentley" vehix:model="Continental" vehix:year="2008" vehix:msrp="$170,990" vehix:mpgCity="10" vehix:mpgHighway="17" />
+ <car jcr:primaryType="vehix:car" jcr:name="Lexus IS350" vehix:maker="Lexus" vehix:model="IS350" vehix:year="2008" vehix:msrp="$36,305" vehix:mpgCity="18" vehix:mpgHighway="25" vehix:userRating="4" vehix:valueRating="5" />
</Luxury>
<Utility>
- <car jcr:name="Land Rover LR2" maker="Land Rover" model="LR2" year="2008" msrp="$33,985" userRating="4.5" valueRating="5" mpgCity="16" mpgHighway="23" />
- <car jcr:name="Land Rover LR3" maker="Land Rover" model="LR3" year="2008" msrp="$48,525" userRating="5" valueRating="2" mpgCity="12" mpgHighway="17" />
- <car jcr:name="Hummer H3" maker="Hummer" model="H3" year="2008" msrp="$30,595" userRating="3.5" valueRating="4" mpgCity="13" mpgHighway="16" />
- <car jcr:name="Ford F-150" maker="Ford" model="F-150" year="2008" msrp="$23,910" userRating="4" valueRating="1" mpgCity="14" mpgHighway="20" />
+ <car jcr:primaryType="vehix:car" jcr:name="Land Rover LR2" vehix:maker="Land Rover" vehix:model="LR2" vehix:year="2008" vehix:msrp="$33,985" vehix:userRating="4.5" vehix:valueRating="5" vehix:mpgCity="16" vehix:mpgHighway="23" />
+ <car jcr:primaryType="vehix:car" jcr:name="Land Rover LR3" vehix:maker="Land Rover" vehix:model="LR3" vehix:year="2008" vehix:msrp="$48,525" vehix:userRating="5" vehix:valueRating="2" vehix:mpgCity="12" vehix:mpgHighway="17" />
+ <car jcr:primaryType="vehix:car" jcr:name="Hummer H3" vehix:maker="Hummer" vehix:model="H3" vehix:year="2008" vehix:msrp="$30,595" vehix:userRating="3.5" vehix:valueRating="4" vehix:mpgCity="13" vehix:mpgHighway="16" />
+ <car jcr:primaryType="vehix:car" jcr:name="Ford F-150" vehix:maker="Ford" vehix:model="F-150" vehix:year="2008" vehix:msrp="$23,910" vehix:userRating="4" vehix:valueRating="1" vehix:mpgCity="14" vehix:mpgHighway="20" />
</Utility>
</Cars>
\ No newline at end of file
16 years, 6 months
DNA SVN: r1081 - in trunk/dna-graph/src: main/java/org/jboss/dna/graph/property and 4 other directories.
by dna-commits@lists.jboss.org
Author: rhauch
Date: 2009-07-09 12:23:09 -0400 (Thu, 09 Jul 2009)
New Revision: 1081
Added:
trunk/dna-graph/src/main/java/org/jboss/dna/graph/session/
trunk/dna-graph/src/main/java/org/jboss/dna/graph/session/GraphSession.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/session/InvalidStateException.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/session/ValidationException.java
trunk/dna-graph/src/test/java/org/jboss/dna/graph/session/
trunk/dna-graph/src/test/java/org/jboss/dna/graph/session/GraphCacheTest.java
Modified:
trunk/dna-graph/src/main/java/org/jboss/dna/graph/Graph.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/GraphI18n.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/Node.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/property/PathNotFoundException.java
trunk/dna-graph/src/main/resources/org/jboss/dna/graph/GraphI18n.properties
Log:
DNA-466 Added new session-based system to the Graph API.
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/Graph.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/Graph.java 2009-07-09 16:22:06 UTC (rev 1080)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/Graph.java 2009-07-09 16:23:09 UTC (rev 1081)
@@ -41,6 +41,7 @@
import java.util.Map;
import java.util.Set;
import java.util.UUID;
+import java.util.concurrent.TimeUnit;
import net.jcip.annotations.Immutable;
import net.jcip.annotations.NotThreadSafe;
import org.jboss.dna.common.collection.EmptyIterator;
@@ -63,6 +64,7 @@
import org.jboss.dna.graph.property.ValueFormatException;
import org.jboss.dna.graph.property.Path.Segment;
import org.jboss.dna.graph.request.BatchRequestBuilder;
+import org.jboss.dna.graph.request.CacheableRequest;
import org.jboss.dna.graph.request.CloneWorkspaceRequest;
import org.jboss.dna.graph.request.CompositeRequest;
import org.jboss.dna.graph.request.CreateNodeRequest;
@@ -1819,13 +1821,15 @@
}
public List<Location> under( Location at ) {
- return requests.readBlockOfChildren(at, getCurrentWorkspaceName(), startingIndex, blockSize).getChildren();
+ return requests.readBlockOfChildren(at, getCurrentWorkspaceName(), startingIndex, blockSize)
+ .getChildren();
}
};
}
public List<Location> startingAfter( final Location previousSibling ) {
- return requests.readNextBlockOfChildren(previousSibling, getCurrentWorkspaceName(), blockSize).getChildren();
+ return requests.readNextBlockOfChildren(previousSibling, getCurrentWorkspaceName(), blockSize)
+ .getChildren();
}
public List<Location> startingAfter( String pathOfPreviousSibling ) {
@@ -3726,7 +3730,7 @@
assertNotExecuted();
return new At<BatchConjunction>() {
public BatchConjunction at( Location location ) {
- requestQueue.readBranch(location, getCurrentWorkspaceName());
+ requestQueue.readBranch(location, getCurrentWorkspaceName(), depth);
return Batch.this.nextRequests;
}
@@ -3833,6 +3837,11 @@
return value;
}
+ protected static DateTime computeExpirationTime( CacheableRequest request ) {
+ CachePolicy policy = request.getCachePolicy();
+ return policy == null ? null : request.getTimeLoaded().plus(policy.getTimeToLive(), TimeUnit.MILLISECONDS);
+ }
+
/**
* The interface used to specify the name of a new workspace.
*/
@@ -5363,6 +5372,11 @@
return request.getActualLocationOfNode();
}
+ public DateTime getExpirationTime() {
+ CachePolicy policy = request.getCachePolicy();
+ return policy == null ? null : request.getTimeLoaded().plus(policy.getTimeToLive(), TimeUnit.MILLISECONDS);
+ }
+
public Graph getGraph() {
return Graph.this;
}
@@ -5431,24 +5445,29 @@
for (Request request : requests) {
if (request instanceof ReadAllPropertiesRequest) {
ReadAllPropertiesRequest read = (ReadAllPropertiesRequest)request;
- getOrCreateNode(read.getActualLocationOfNode()).setProperties(read.getPropertiesByName());
+ DateTime expires = computeExpirationTime(read);
+ getOrCreateNode(read.getActualLocationOfNode(), expires).setProperties(read.getPropertiesByName());
} else if (request instanceof ReadPropertyRequest) {
ReadPropertyRequest read = (ReadPropertyRequest)request;
- getOrCreateNode(read.getActualLocationOfNode()).addProperty(read.getProperty());
+ DateTime expires = computeExpirationTime(read);
+ getOrCreateNode(read.getActualLocationOfNode(), expires).addProperty(read.getProperty());
} else if (request instanceof ReadNodeRequest) {
ReadNodeRequest read = (ReadNodeRequest)request;
- BatchResultsNode node = getOrCreateNode(read.getActualLocationOfNode());
+ DateTime expires = computeExpirationTime(read);
+ BatchResultsNode node = getOrCreateNode(read.getActualLocationOfNode(), expires);
node.setProperties(read.getPropertiesByName());
node.setChildren(read.getChildren());
} else if (request instanceof ReadBlockOfChildrenRequest) {
throw new IllegalStateException();
} else if (request instanceof ReadAllChildrenRequest) {
ReadAllChildrenRequest read = (ReadAllChildrenRequest)request;
- getOrCreateNode(read.getActualLocationOfNode()).setChildren(read.getChildren());
+ DateTime expires = computeExpirationTime(read);
+ getOrCreateNode(read.getActualLocationOfNode(), expires).setChildren(read.getChildren());
} else if (request instanceof ReadBranchRequest) {
ReadBranchRequest read = (ReadBranchRequest)request;
+ DateTime expires = computeExpirationTime(read);
for (Location location : read) {
- BatchResultsNode node = getOrCreateNode(location);
+ BatchResultsNode node = getOrCreateNode(location, expires);
node.setProperties(read.getPropertiesFor(location));
node.setChildren(read.getChildren(location));
}
@@ -5462,24 +5481,29 @@
/*package*/BatchResults( Request request ) {
if (request instanceof ReadAllPropertiesRequest) {
ReadAllPropertiesRequest read = (ReadAllPropertiesRequest)request;
- getOrCreateNode(read.getActualLocationOfNode()).setProperties(read.getPropertiesByName());
+ DateTime expires = computeExpirationTime(read);
+ getOrCreateNode(read.getActualLocationOfNode(), expires).setProperties(read.getPropertiesByName());
} else if (request instanceof ReadPropertyRequest) {
ReadPropertyRequest read = (ReadPropertyRequest)request;
- getOrCreateNode(read.getActualLocationOfNode()).addProperty(read.getProperty());
+ DateTime expires = computeExpirationTime(read);
+ getOrCreateNode(read.getActualLocationOfNode(), expires).addProperty(read.getProperty());
} else if (request instanceof ReadNodeRequest) {
ReadNodeRequest read = (ReadNodeRequest)request;
- BatchResultsNode node = getOrCreateNode(read.getActualLocationOfNode());
+ DateTime expires = computeExpirationTime(read);
+ BatchResultsNode node = getOrCreateNode(read.getActualLocationOfNode(), expires);
node.setProperties(read.getPropertiesByName());
node.setChildren(read.getChildren());
} else if (request instanceof ReadBlockOfChildrenRequest) {
throw new IllegalStateException();
} else if (request instanceof ReadAllChildrenRequest) {
ReadAllChildrenRequest read = (ReadAllChildrenRequest)request;
- getOrCreateNode(read.getActualLocationOfNode()).setChildren(read.getChildren());
+ DateTime expires = computeExpirationTime(read);
+ getOrCreateNode(read.getActualLocationOfNode(), expires).setChildren(read.getChildren());
} else if (request instanceof ReadBranchRequest) {
ReadBranchRequest read = (ReadBranchRequest)request;
+ DateTime expires = computeExpirationTime(read);
for (Location location : read) {
- BatchResultsNode node = getOrCreateNode(location);
+ BatchResultsNode node = getOrCreateNode(location, expires);
node.setProperties(read.getPropertiesFor(location));
node.setChildren(read.getChildren(location));
}
@@ -5492,10 +5516,11 @@
/*package*/BatchResults() {
}
- private BatchResultsNode getOrCreateNode( Location location ) {
+ private BatchResultsNode getOrCreateNode( Location location,
+ DateTime expirationTime ) {
BatchResultsNode node = nodes.get(location);
if (node == null) {
- node = new BatchResultsNode(location);
+ node = new BatchResultsNode(location, expirationTime);
assert location.getPath() != null;
nodes.put(location.getPath(), node);
}
@@ -5566,13 +5591,20 @@
@Immutable
class BatchResultsNode implements Node {
private final Location location;
+ private final DateTime expirationTime;
private Map<Name, Property> properties;
private List<Location> children;
- BatchResultsNode( Location location ) {
+ BatchResultsNode( Location location,
+ DateTime expirationTime ) {
this.location = location;
+ this.expirationTime = expirationTime;
}
+ public DateTime getExpirationTime() {
+ return expirationTime;
+ }
+
void addProperty( Property property ) {
if (this.properties == null) this.properties = new HashMap<Name, Property>();
this.properties.put(property.getName(), property);
@@ -5739,7 +5771,10 @@
}
public SubgraphNode getNode( Name relativePath ) {
- Path path = getGraph().getContext().getValueFactories().getPathFactory().create(getLocation().getPath(), relativePath);
+ Path path = getGraph().getContext()
+ .getValueFactories()
+ .getPathFactory()
+ .create(getLocation().getPath(), relativePath);
path = path.getNormalizedPath();
return getNode(path);
}
@@ -5777,6 +5812,10 @@
this.request = request;
}
+ public DateTime getExpirationTime() {
+ return computeExpirationTime(request);
+ }
+
public List<Location> getChildren() {
List<Location> children = request.getChildren(location);
if (children == null) children = NO_CHILDREN;
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-07-09 16:22:06 UTC (rev 1080)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/GraphI18n.java 2009-07-09 16:23:09 UTC (rev 1081)
@@ -121,6 +121,11 @@
public static I18n moveLimitedToBeWithinSingleSource;
public static I18n cloneLimitedToBeWithinSingleSource;
+ /* Session */
+ public static I18n unableToRefreshBranchBecauseChangesDependOnChangesToNodesOutsideOfBranch;
+ public static I18n unableToSaveBranchBecauseChangesDependOnChangesToNodesOutsideOfBranch;
+ public static I18n nodeHasAlreadyBeenRemovedFromThisSession;
+
static {
try {
I18n.initialize(GraphI18n.class);
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/Node.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/Node.java 2009-07-09 16:22:06 UTC (rev 1080)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/Node.java 2009-07-09 16:23:09 UTC (rev 1081)
@@ -27,6 +27,7 @@
import java.util.List;
import java.util.Map;
import net.jcip.annotations.Immutable;
+import org.jboss.dna.graph.property.DateTime;
import org.jboss.dna.graph.property.Name;
import org.jboss.dna.graph.property.Path;
import org.jboss.dna.graph.property.Property;
@@ -47,6 +48,13 @@
Graph getGraph();
/**
+ * Get the time at which this node representation should no longer be used.
+ *
+ * @return the expiration time, or null if there is none
+ */
+ DateTime getExpirationTime();
+
+ /**
* Get the location of the node.
*
* @return the node's location
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/property/PathNotFoundException.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/property/PathNotFoundException.java 2009-07-09 16:22:06 UTC (rev 1080)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/property/PathNotFoundException.java 2009-07-09 16:23:09 UTC (rev 1081)
@@ -105,8 +105,8 @@
@Override
public String getMessage() {
if (this.lowestAncestorThatDoesExist != null) {
- return GraphI18n.pathNotFoundExceptionLowestExistingLocationFound.text(super.getMessage(),
- this.lowestAncestorThatDoesExist);
+ String locationPart = location.hasPath() ? location.getPath().toString() : location.toString();
+ return GraphI18n.pathNotFoundExceptionLowestExistingLocationFound.text(locationPart, this.lowestAncestorThatDoesExist);
}
return super.getMessage();
}
Added: trunk/dna-graph/src/main/java/org/jboss/dna/graph/session/GraphSession.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/session/GraphSession.java (rev 0)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/session/GraphSession.java 2009-07-09 16:23:09 UTC (rev 1081)
@@ -0,0 +1,2562 @@
+/*
+ * 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.session;
+
+import java.security.AccessControlException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
+import net.jcip.annotations.Immutable;
+import net.jcip.annotations.NotThreadSafe;
+import net.jcip.annotations.ThreadSafe;
+import org.jboss.dna.common.collection.ReadOnlyIterator;
+import org.jboss.dna.common.i18n.I18n;
+import org.jboss.dna.common.util.CheckArg;
+import org.jboss.dna.common.util.HashCode;
+import org.jboss.dna.common.util.StringUtil;
+import org.jboss.dna.graph.ExecutionContext;
+import org.jboss.dna.graph.Graph;
+import org.jboss.dna.graph.GraphI18n;
+import org.jboss.dna.graph.Location;
+import org.jboss.dna.graph.Results;
+import org.jboss.dna.graph.Subgraph;
+import org.jboss.dna.graph.connector.RepositorySourceException;
+import org.jboss.dna.graph.connector.UuidAlreadyExistsException;
+import org.jboss.dna.graph.property.DateTime;
+import org.jboss.dna.graph.property.Name;
+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.request.BatchRequestBuilder;
+import org.jboss.dna.graph.request.ChangeRequest;
+import org.jboss.dna.graph.request.CreateNodeRequest;
+import org.jboss.dna.graph.request.InvalidWorkspaceException;
+import org.jboss.dna.graph.request.Request;
+import org.jboss.dna.graph.session.GraphSession.Authorizer.Action;
+import com.google.common.collect.ListMultimap;
+import com.google.common.collect.Multimaps;
+
+/**
+ * This class represents an interactive session for working with the content within a graph. This session maintains a cache of
+ * content read from the repository, as well as transient changes that have been made to the nodes within this session that are
+ * then pushed to the graph when the session is {@link #save() saved}.
+ * <p>
+ * Like the other Graph APIs, the mutable objects in this session should not be held onto for very long periods of time. When the
+ * session is {@link #save() saved} or {{@link #refresh(boolean) refreshed} (or when a node is {@link #save(Node) saved} or
+ * {@link #refresh(Node, boolean) refreshed}), the session may {@link Node#unload() unload} and discard some of its nodes. Using
+ * nodes after they are discarded may result in assertion errors (assuming Java assertions are enabled).
+ * </p>
+ *
+ * @param <Payload> the type of the payload object for each node, used to allow the nodes to hold additional cached information
+ * @param <PropertyPayload> the type of payload object for each property, used to allow the nodes to hold additional cached
+ * information
+ */
+@NotThreadSafe
+public class GraphSession<Payload, PropertyPayload> {
+
+ protected final ListMultimap<Name, Node<Payload, PropertyPayload>> NO_CHILDREN = Multimaps.immutableMultimap();
+ protected final Map<Name, PropertyInfo<PropertyPayload>> NO_PROPERTIES = Collections.emptyMap();
+
+ protected final Authorizer authorizer;
+ protected final ExecutionContext context;
+ protected final Graph store;
+ protected final Node<Payload, PropertyPayload> root;
+ protected final Operations<Payload, PropertyPayload> nodeOperations;
+ protected final PathFactory pathFactory;
+ protected final NodeIdFactory idFactory;
+ protected final String workspaceName;
+ protected int loadDepth = 1;
+
+ /**
+ * A map of the nodes keyed by their identifier.
+ */
+ protected final Map<NodeId, Node<Payload, PropertyPayload>> nodes = new HashMap<NodeId, Node<Payload, PropertyPayload>>();
+ /**
+ * A map that records how the changes to a node are dependent upon other nodes.
+ */
+ protected final Map<NodeId, Dependencies> changeDependencies = new HashMap<NodeId, Dependencies>();
+
+ private LinkedList<Request> requests;
+ private BatchRequestBuilder requestBuilder;
+ protected Graph.Batch operations;
+
+ /**
+ * Create a session that uses the supplied graph and the supplied node operations.
+ *
+ * @param graph the graph that this session is to use
+ * @param workspaceName the name of the workspace that is to be used, or null if the current workspace should be used
+ * @param nodeOperations the operations that are to be performed during various stages in the lifecycle of a node, or null if
+ * there are no special operations that should be performed
+ */
+ public GraphSession( Graph graph,
+ String workspaceName,
+ Operations<Payload, PropertyPayload> nodeOperations ) {
+ this(graph, workspaceName, nodeOperations, null);
+ }
+
+ /**
+ * Create a session that uses the supplied graph and the supplied node operations.
+ *
+ * @param graph the graph that this session is to use
+ * @param workspaceName the name of the workspace that is to be used, or null if the current workspace should be used
+ * @param nodeOperations the operations that are to be performed during various stages in the lifecycle of a node, or null if
+ * there are no special operations that should be performed
+ * @param authorizer the authorizing component, or null if no special authorization is to be performed
+ * @throws IllegalArgumentException if the graph reference is null
+ * @throws IllegalArgumentException if the depth is not positive
+ */
+ public GraphSession( Graph graph,
+ String workspaceName,
+ Operations<Payload, PropertyPayload> nodeOperations,
+ Authorizer authorizer ) {
+ assert graph != null;
+ this.store = graph;
+ this.context = store.getContext();
+ if (workspaceName != null) {
+ this.workspaceName = this.store.useWorkspace(workspaceName).getName();
+ } else {
+ this.workspaceName = this.store.getCurrentWorkspaceName();
+ }
+ this.nodeOperations = nodeOperations != null ? nodeOperations : new SimpleNodeOperations<Payload, PropertyPayload>();
+ this.pathFactory = context.getValueFactories().getPathFactory();
+ this.authorizer = authorizer != null ? authorizer : new NoOpAuthorizer();
+ // Create the NodeId factory ...
+ this.idFactory = new NodeIdFactory() {
+ private long nextId = 0L;
+
+ public NodeId create() {
+ return new NodeId(++nextId);
+ }
+ };
+ // Create the root node ...
+ Location rootLocation = Location.create(pathFactory.createRootPath());
+ NodeId rootId = idFactory.create();
+ this.root = createNode(null, rootId, rootLocation);
+ this.nodes.put(rootId, root);
+
+ // Create the batch operations ...
+ this.requests = new LinkedList<Request>();
+ this.requestBuilder = new BatchRequestBuilder(this.requests);
+ this.operations = this.store.batch(this.requestBuilder);
+ }
+
+ /**
+ * Get the subgraph depth that is read when a node is loaded from the persistence store. By default, this value is 1.
+ *
+ * @return the loading depth; always positive
+ */
+ public int getDepthForLoadingNodes() {
+ return loadDepth;
+ }
+
+ /**
+ * Set the loading depth parameter, which controls how deep a subgraph should be read when a node is loaded from the
+ * persistence store. By default, this value is 1.
+ *
+ * @param depth the depth that should be read whenever a single node is loaded
+ * @throws IllegalArgumentException if the depth is not positive
+ */
+ public void setDepthForLoadingNodes( int depth ) {
+ CheckArg.isPositive(depth, "depth");
+ this.loadDepth = depth;
+ }
+
+ /**
+ * Get the root node.
+ *
+ * @return the root node; never null
+ */
+ public Node<Payload, PropertyPayload> getRoot() {
+ return root;
+ }
+
+ /**
+ * Get the path factory that should be used to adjust the path objects.
+ *
+ * @return the path factory; never null
+ */
+ public PathFactory getPathFactory() {
+ return pathFactory;
+ }
+
+ /**
+ * Find in the session the node with the supplied identifier.
+ *
+ * @param id the identifier of the node
+ * @return the identified node, or null if the session has no node with the supplied identifier
+ * @throws IllegalArgumentException if the identifier is null
+ */
+ public Node<Payload, PropertyPayload> findNodeWith( NodeId id ) {
+ CheckArg.isNotNull(id, "id");
+ return nodes.get(id);
+ }
+
+ /**
+ * Find the node with the supplied identifier or, if no such node is found, the node at the supplied path. Note that if a node
+ * was found by the identifier, the resulting may not have the same path as that supplied as a parameter.
+ *
+ * @param id the identifier to the node; may be null if the node is to be found by path
+ * @param path the path that should be used to find the node only when the cache doesn't contain a node with the identifier
+ * @return the node with the supplied id and/or path
+ * @throws IllegalArgumentException if the identifier and path are both node
+ * @throws PathNotFoundException if the node at the supplied path does not exist
+ * @throws AccessControlException if the user does not have permission to read the nodes given by the supplied path
+ */
+ public Node<Payload, PropertyPayload> findNodeWith( NodeId id,
+ Path path ) throws PathNotFoundException, AccessControlException {
+ if (id == null && path == null) {
+ CheckArg.isNotNull(path, "path and id");
+ }
+ Node<Payload, PropertyPayload> result = nodes.get(id); // if found, the user should have read privilege since it was
+ // already in the cache
+ if (result == null && path != null) {
+ result = findNodeWith(path);
+ }
+ return result;
+ }
+
+ /**
+ * Find the node with the supplied path. This node quickly finds the node if it exists in the cache, or if it is not in the
+ * cache, it loads the nodes down the supplied path.
+ *
+ * @param path the path to the node
+ * @return the node information
+ * @throws PathNotFoundException if the node at the supplied path does not exist
+ * @throws AccessControlException if the user does not have permission to read the nodes given by the supplied path
+ */
+ public Node<Payload, PropertyPayload> findNodeWith( Path path ) throws PathNotFoundException, AccessControlException {
+ if (path.isRoot()) return getRoot();
+ return findNodeRelativeTo(root, path.relativeTo(root.getPath()));
+ }
+
+ /**
+ * Find the node with the supplied path relative to another node. This node quickly finds the node by walking the supplied
+ * relative path starting at the supplied node. As soon as a cached node is found to not be fully loaded, the persistent
+ * information for that node and all remaining nodes along the relative path are read from the persistent store and inserted
+ * into the cache.
+ *
+ * @param startingPoint the node from which the path is relative
+ * @param relativePath the relative path from the designated starting point to the desired node; may not be null and may not
+ * be an {@link Path#isAbsolute() absolute} path
+ * @return the node information
+ * @throws PathNotFoundException if the node at the supplied path does not exist
+ * @throws AccessControlException if the user does not have permission to read the nodes given by the supplied path
+ */
+ @SuppressWarnings( "synthetic-access" )
+ public Node<Payload, PropertyPayload> findNodeRelativeTo( Node<Payload, PropertyPayload> startingPoint,
+ Path relativePath )
+ throws PathNotFoundException, AccessControlException {
+ Node<Payload, PropertyPayload> node = startingPoint;
+ if (!relativePath.isRoot()) {
+ // Find the absolute path, which ensures that the relative path is well-formed ...
+ Path absolutePath = relativePath.resolveAgainst(startingPoint.getPath());
+
+ // Verify that the user has the appropriate privileges to read these nodes...
+ authorizer.checkPermissions(absolutePath, Action.READ);
+
+ // Walk down the path ...
+ Iterator<Path.Segment> iter = relativePath.iterator();
+ while (iter.hasNext()) {
+ Path.Segment segment = iter.next();
+ try {
+ if (segment.isSelfReference()) continue;
+ if (segment.isParentReference()) {
+ node = node.getParent();
+ assert node != null; // since the relative path is well-formed
+ continue;
+ }
+
+ if (node.isLoaded()) {
+ // The child is the next node we need to process ...
+ node = node.getChild(segment);
+ } else {
+ // The node has not yet been loaded into the cache, so read this node
+ // from the store as well as all nodes along the path to the node we're really
+ // interested in. We'll do this in a batch, so first create this batch ...
+ Graph.Batch batch = store.batch();
+
+ // Figure out which nodes along the path need to be loaded from the store ...
+ Path firstPath = node.getPath();
+ batch.read(firstPath);
+ // Now add the path to the child (which is no longer on the iterator) ...
+ Path nextPath = pathFactory.create(firstPath, segment);
+ if (!iter.hasNext() && loadDepth > 1) {
+ batch.readSubgraphOfDepth(loadDepth).at(nextPath);
+ } else {
+ batch.read(nextPath);
+ }
+ // Now add any remaining paths that are still on the iterator ...
+ while (iter.hasNext()) {
+ nextPath = pathFactory.create(nextPath, iter.next());
+ if (!iter.hasNext() && loadDepth > 1) {
+ batch.readSubgraphOfDepth(loadDepth).at(nextPath);
+ } else {
+ batch.read(nextPath);
+ }
+ }
+
+ // Load all of the nodes (we should be reading at least 2 nodes) ...
+ Results batchResults = batch.execute();
+
+ // Add the children and properties in the lowest cached node ...
+ Path previousPath = null;
+ Node<Payload, PropertyPayload> topNode = node;
+ Node<Payload, PropertyPayload> previousNode = node;
+ for (org.jboss.dna.graph.Node persistentNode : batchResults) {
+ Location location = persistentNode.getLocation();
+ Path path = location.getPath();
+ if (path.isRoot()) {
+ previousNode = root;
+ root.location = location;
+ } else {
+ if (path.getParent().equals(previousPath)) {
+ previousNode = previousNode.getChild(path.getLastSegment());
+ } else {
+ Path subgraphPath = path.relativeTo(topNode.getPath());
+ previousNode = findNodeRelativeTo(topNode, subgraphPath);
+ }
+ // Set the node that we're looking for ...
+ if (path.getLastSegment().equals(relativePath.getLastSegment()) && path.equals(absolutePath)) {
+ node = previousNode;
+ }
+ }
+ nodeOperations.update(persistentNode, previousNode);
+ previousPath = path;
+ }
+ }
+ } catch (PathNotFoundException e) {
+ // Use the correct desired path ...
+ throw new PathNotFoundException(Location.create(relativePath), e.getLowestAncestorThatDoesExist());
+ }
+ }
+ }
+ return node;
+ }
+
+ /**
+ * Returns whether the session cache has any pending changes that need to be executed.
+ *
+ * @return true if there are pending changes, or false if there is currently no changes
+ */
+ public boolean hasPendingChanges() {
+ return root.isChanged(true);
+ }
+
+ /**
+ * Remove any cached information that has been marked as a transient change.
+ */
+ public void clearAllChangedNodes() {
+ root.clearChanges();
+ changeDependencies.clear();
+ requests.clear();
+ }
+
+ /**
+ * Move this node from its current location so that is is a child of the supplied parent, but do so immediately without
+ * enqueuing the operation within the session's operations.
+ *
+ * @param nodeToMove the node that is to be moved; may not be null
+ * @param newParent the new parent for this node; may not be null
+ * @param newName the new name for the node, or null if the node is not to be renamed
+ * @throws RepositorySourceException if the parent node is to be loaded but a problem is encountered while doing so
+ * @throws IllegalArgumentException if the node being moved is the root node
+ */
+ public void immediateMove( Node<Payload, PropertyPayload> nodeToMove,
+ Node<Payload, PropertyPayload> newParent,
+ Name newName ) {
+ CheckArg.isNotNull(nodeToMove, "nodeToMove");
+ CheckArg.isNotNull(newParent, "newParent");
+ nodeToMove.moveTo(newParent, newName, false);
+ }
+
+ /**
+ * Copy the node at the supplied source path in the named workspace, and place the copy at the supplied location within the
+ * current workspace, doing so immediately without enqueuing the operation within the session's operations. The current
+ * session is modified immediately to reflect the copy result.
+ * <p>
+ * Note that the destination path should not include a same-name-sibling index, since this will be ignored and will always be
+ * recomputed (as the copy will be appended to any children already in the destination's parent).
+ * </p>
+ *
+ * @param source the path to the node that is to be copied; may not be null
+ * @param destination the path where the copy is to be placed; may not be null index
+ * @throws IllegalArgumentException either path is null or invalid
+ */
+ public void immediateCopy( Path source,
+ Path destination ) {
+ immediateCopy(source, workspaceName, destination);
+ }
+
+ /**
+ * Copy the node at the supplied source path in the named workspace, and place the copy at the supplied location within the
+ * current workspace, doing so immediately without enqueuing the operation within the session's operations. The current
+ * session is modified immediately to reflect the copy result.
+ * <p>
+ * Note that the destination path should not include a same-name-sibling index, since this will be ignored and will always be
+ * recomputed (as the copy will be appended to any children already in the destination's parent).
+ * </p>
+ *
+ * @param source the path to the node that is to be copied; may not be null
+ * @param sourceWorkspace the name of the workspace where the source node is to be found, or null if the current workspace
+ * should be used
+ * @param destination the path where the copy is to be placed; may not be null index
+ * @throws IllegalArgumentException either path is null or invalid
+ * @throws InvalidWorkspaceException if the source workspace name is invalid or does not exist
+ */
+ public void immediateCopy( Path source,
+ String sourceWorkspace,
+ Path destination ) {
+ CheckArg.isNotNull(source, "source");
+ CheckArg.isNotNull(destination, "destination");
+ if (sourceWorkspace == null) sourceWorkspace = workspaceName;
+
+ // Perform the copy operation, but use the "to" form (not the "into", which takes the parent), but
+ // but use a batch so that we can read the latest list of children ...
+ Results results = store.batch()
+ .copy(source)
+ .fromWorkspace(sourceWorkspace)
+ .to(destination)
+ .and()
+ .readChildren()
+ .of(destination.getParent())
+ .execute();
+
+ // Now get the children of the destination's parent ...
+ Location parentLocation = results.getNode(destination).getLocation();
+ // Find the parent node in the session ...
+ Node<Payload, PropertyPayload> parent = this.findNodeWith(parentLocation.getPath());
+ if (parent.isLoaded()) {
+ // Update the children to make them match the latest snapshot from the store ...
+ List<Location> newChildren = results.getNode(parentLocation).getChildren();
+ parent.synchronize(newChildren);
+ }
+ }
+
+ /**
+ * Clone the supplied source branch and place into the destination location, optionally removing any existing copy that
+ * already exists in the destination location.
+ *
+ * @param source
+ * @param sourceWorkspace
+ * @param destination
+ * @param removeExisting true if the original should be removed, or false if the original should be left
+ * @throws UuidAlreadyExistsException if copy could not be completed because the current workspace already includes at least
+ * one of the nodes at or below the <code>source</code> branch in the source workspace
+ */
+ public void immediateClone( Path source,
+ String sourceWorkspace,
+ Path destination,
+ boolean removeExisting ) {
+
+ // Perform the copy operation, but use the "to" form (not the "into", which takes the parent), but
+ // but use a batch so that we can read the latest list of children ...
+ Graph.Batch batch = store.batch();
+ if (removeExisting) {
+ // Perform the copy operation, but use the "to" form (not the "into", which takes the parent) ...
+ batch.copy(source).replacingExistingNodesWithSameUuids().fromWorkspace(sourceWorkspace).to(destination);
+ } else {
+ // Perform the copy operation, but use the "to" form (not the "into", which takes the parent) ...
+ batch.copy(source).failingIfUuidsMatch().fromWorkspace(sourceWorkspace).to(destination);
+ }
+ // And read the children of the destination's parent ...
+ batch.readChildren().of(destination.getParent());
+ // Now execute these two operations ...
+ Results results = batch.execute();
+
+ // Now get the children of the destination's parent ...
+ Location parentLocation = results.getNode(destination).getLocation();
+ // Find the parent node in the session ...
+ Node<Payload, PropertyPayload> parent = this.findNodeWith(parentLocation.getPath());
+ if (parent.isLoaded()) {
+ // Update the children to make them match the latest snapshot from the store ...
+ List<Location> newChildren = results.getNode(parentLocation).getChildren();
+ parent.synchronize(newChildren);
+ }
+ }
+
+ /**
+ * Refreshes (removes the cached state) for all cached nodes.
+ * <p>
+ * If {@code keepChanges == true}, modified nodes will not have their state refreshed, while all others will either be
+ * unloaded or changed to reflect the current state of the persistent store.
+ * </p>
+ *
+ * @param keepChanges indicates whether changed nodes should be kept or refreshed from the repository.
+ * @throws InvalidStateException if any error resulting while reading information from the repository
+ * @throws RepositorySourceException if any error resulting while reading information from the repository
+ */
+ @SuppressWarnings( "synthetic-access" )
+ public void refresh( boolean keepChanges ) throws InvalidStateException, RepositorySourceException {
+ if (keepChanges) {
+ refresh(root, keepChanges);
+ } else {
+ // Clear out all state ...
+ nodes.clear();
+ nodes.put(root.getNodeId(), root);
+ // Clear out all changes ...
+ requests.clear();
+ changeDependencies.clear();
+ // And force the root node to be 'unloaded' (in an efficient way) ...
+ root.changed = false;
+ root.childrenByName = null;
+ root.expirationTime = Long.MAX_VALUE;
+ }
+ }
+
+ /**
+ * Refreshes (removes the cached state) for the given node and its descendants.
+ * <p>
+ * If {@code keepChanges == true}, modified nodes will not have their state refreshed, while all others will either be
+ * unloaded or changed to reflect the current state of the persistent store.
+ * </p>
+ *
+ * @param node the node that is to be refreshed; may not be null
+ * @param keepChanges indicates whether changed nodes should be kept or refreshed from the repository.
+ * @throws InvalidStateException if any error resulting while reading information from the repository
+ * @throws RepositorySourceException if any error resulting while reading information from the repository
+ */
+ public void refresh( Node<Payload, PropertyPayload> node,
+ boolean keepChanges ) throws InvalidStateException, RepositorySourceException {
+ if (!node.isRoot() && node.isChanged(true)) {
+ // Need to make sure that changes to this branch are not dependent upon changes to nodes outside of this branch...
+ if (!node.containsChangesWithExternalDependencies()) {
+ I18n msg = GraphI18n.unableToRefreshBranchBecauseChangesDependOnChangesToNodesOutsideOfBranch;
+ String path = node.getPath().getString(context.getNamespaceRegistry());
+ throw new InvalidStateException(msg.text(path, workspaceName));
+ }
+ }
+
+ if (keepChanges && node.isChanged(true)) {
+ // Perform the refresh while retaining changes ...
+ // Phase 1: determine which nodes can be unloaded, which must be refreshed, and which must be unchanged ...
+ RefreshState<Payload, PropertyPayload> refreshState = new RefreshState<Payload, PropertyPayload>();
+ node.refreshPhase1(refreshState);
+ // If there are any nodes to be refreshed, read then in a single batch ...
+ Results readResults = null;
+ if (!refreshState.getNodesToBeRefreshed().isEmpty()) {
+ Graph.Batch batch = store.batch();
+ for (Node<Payload, PropertyPayload> nodeToBeRefreshed : refreshState.getNodesToBeRefreshed()) {
+ batch.read(nodeToBeRefreshed.getLocation());
+ }
+ // Execute the reads. No modifications have been made to the cache, so it is not a problem
+ // if this throws a repository exception.
+ readResults = batch.execute();
+ }
+
+ // Phase 2: update the cache by unloading or refreshing the nodes ...
+ node.refreshPhase2(refreshState, readResults);
+ } else {
+ // Get rid of all changes ...
+ node.clearChanges();
+ // And then unload the node ...
+ node.unload();
+
+ // Throw out the old pending operations
+ if (operations.isExecuteRequired()) {
+ // Make sure the builder has finished all the requests ...
+ this.requestBuilder.finishPendingRequest();
+
+ // Remove all of the enqueued requests for this branch ...
+ for (Iterator<Request> iter = this.requests.iterator(); iter.hasNext();) {
+ Request request = iter.next();
+ assert request instanceof ChangeRequest;
+ ChangeRequest change = (ChangeRequest)request;
+ if (change.changes(workspaceName, node.getPath())) {
+ iter.remove();
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Save any changes that have been accumulated by this session.
+ *
+ * @throws PathNotFoundException if the state of this session is invalid and is attempting to change a node that doesn't exist
+ * @throws ValidationException if any of the changes being made result in an invalid node state
+ * @throws InvalidStateException if the supplied node is no longer a node within this cache (because it was unloaded)
+ */
+ public void save() throws PathNotFoundException, ValidationException, InvalidStateException {
+ if (!operations.isExecuteRequired()) return;
+ assert root.isChanged(true);
+
+ // Make sure that each of the changed node is valid. This process requires that all children of
+ // all changed nodes are loaded, so in this process load all unloaded children in one batch ...
+ root.onChangedNodes(new LoadAllChildrenVisitor() {
+ @Override
+ protected void finishParentAfterLoading( Node<Payload, PropertyPayload> node ) {
+ nodeOperations.validate(node);
+ }
+ });
+
+ // Execute the batched operations ...
+ operations.execute();
+
+ // Create a new batch for future operations ...
+ // LinkedList<Request> oldRequests = this.requests;
+ this.requests = new LinkedList<Request>();
+ this.requestBuilder = new BatchRequestBuilder(this.requests);
+ operations = store.batch(this.requestBuilder);
+
+ // Remove all the cached items that have been changed or deleted ...
+ this.root.clearChanges();
+
+ // Remove all the changed and deleted infos ...
+ changeDependencies.clear();
+ }
+
+ /**
+ * Save any changes to the identified node or its descendants. The supplied node may not have been deleted or created in this
+ * session since the last save operation.
+ *
+ * @param node the node being saved; may not be null
+ * @throws PathNotFoundException if the state of this session is invalid and is attempting to change a node that doesn't exist
+ * @throws ValidationException if any of the changes being made result in an invalid node state
+ * @throws InvalidStateException if the supplied node is no longer a node within this cache (because it was unloaded)
+ */
+ public void save( Node<Payload, PropertyPayload> node )
+ throws PathNotFoundException, ValidationException, InvalidStateException {
+ assert node != null;
+ if (node.isRoot()) {
+ // We're actually saving the root, so the other 'save' method is faster and more efficient ...
+ save();
+ return;
+ }
+ if (node.isStale()) {
+ // This node was deleted in this session ...
+ String readableLocation = node.getLocation().getString(context.getNamespaceRegistry());
+ I18n msg = GraphI18n.nodeHasAlreadyBeenRemovedFromThisSession;
+ throw new InvalidStateException(msg.text(readableLocation, workspaceName));
+ }
+ if (!node.isChanged(true)) {
+ // There are no changes within this branch
+ return;
+ }
+
+ // Need to make sure that changes to this branch are not dependent upon changes to nodes outside of this branch...
+ if (!node.containsChangesWithExternalDependencies()) {
+ I18n msg = GraphI18n.unableToSaveBranchBecauseChangesDependOnChangesToNodesOutsideOfBranch;
+ String path = node.getPath().getString(context.getNamespaceRegistry());
+ throw new InvalidStateException(msg.text(path, workspaceName));
+ }
+
+ // Make sure that each of the changed node is valid. This process requires that all children of
+ // all changed nodes are loaded, so in this process load all unloaded children in one batch ...
+ root.onChangedNodes(new LoadAllChildrenVisitor() {
+ @Override
+ protected void finishParentAfterLoading( Node<Payload, PropertyPayload> node ) {
+ nodeOperations.validate(node);
+ }
+ });
+
+ // Make sure the builder has finished all the requests ...
+ this.requestBuilder.finishPendingRequest();
+
+ // Remove all of the enqueued requests for this branch ...
+ Path path = node.getPath();
+ LinkedList<Request> branchRequests = new LinkedList<Request>();
+ LinkedList<Request> nonBranchRequests = new LinkedList<Request>();
+ Set<UUID> branchUuids = new HashSet<UUID>();
+ for (Request request : this.requests) {
+ assert request instanceof ChangeRequest;
+ ChangeRequest change = (ChangeRequest)request;
+ if (change.changes(workspaceName, path)) {
+ branchRequests.add(request);
+ // Record the UUID of the node being saved now ...
+ UUID changedUuid = null;
+ if (change instanceof CreateNodeRequest) {
+ // We want the parent UUID ...
+ changedUuid = ((CreateNodeRequest)change).under().getUuid();
+ } else {
+ changedUuid = change.changedLocation().getUuid();
+ }
+ assert changedUuid != null;
+ branchUuids.add(changedUuid);
+ } else {
+ nonBranchRequests.add(request);
+ }
+ }
+ if (branchRequests.isEmpty()) return;
+
+ // Now execute the branch ...
+ Graph.Batch branchBatch = store.batch(new BatchRequestBuilder(branchRequests));
+ branchBatch.execute();
+
+ // Still have non-branch related requests that we haven't executed ...
+ this.requests = nonBranchRequests;
+ this.requestBuilder = new BatchRequestBuilder(this.requests);
+ this.operations = store.batch(this.requestBuilder);
+
+ // Remove all the cached, changed or deleted items that were just saved ...
+ node.clearChanges();
+ }
+
+ protected Node<Payload, PropertyPayload> createNode( Node<Payload, PropertyPayload> parent,
+ NodeId nodeId,
+ Location location ) {
+ return new Node<Payload, PropertyPayload>(this, parent, nodeId, location);
+ }
+
+ protected long getCurrentTime() {
+ return System.currentTimeMillis();
+ }
+
+ protected void recordMove( Node<Payload, PropertyPayload> nodeBeingMoved,
+ Node<Payload, PropertyPayload> oldParent,
+ Node<Payload, PropertyPayload> newParent ) {
+ // Fix the cache's state ...
+ NodeId id = nodeBeingMoved.getNodeId();
+ Dependencies dependencies = changeDependencies.get(id);
+ if (dependencies == null) {
+ dependencies = new Dependencies();
+ dependencies.setMovedFrom(oldParent.getNodeId());
+ changeDependencies.put(id, dependencies);
+ } else {
+ dependencies.setMovedFrom(newParent.getNodeId());
+ }
+ }
+
+ /**
+ * Record the fact that the supplied node is in the process of being deleted, so any cached information (outside of the node
+ * object itself) should be cleaned up.
+ *
+ * @param node the node being deleted; never null
+ */
+ protected void recordDelete( Node<Payload, PropertyPayload> node ) {
+ // Record the operation ...
+ operations.delete(node.getLocation());
+ // Fix the cache's state ...
+ nodes.remove(node.getNodeId());
+ changeDependencies.remove(node.getNodeId());
+ recordUnloaded(node);
+ }
+
+ /**
+ * Record the fact that the supplied node is in the process of being unloaded, so any cached information (outside of the node
+ * object itself) should be cleaned up.
+ *
+ * @param node the node being unloaded; never null
+ */
+ protected void recordUnloaded( final Node<Payload, PropertyPayload> node ) {
+ if (node.isLoaded() && node.getChildrenCount() > 0) {
+ // Walk the branch and remove all nodes from the map of all nodes ...
+ node.onLoadedNodes(new NodeVisitor<Payload, PropertyPayload>() {
+ @SuppressWarnings( "synthetic-access" )
+ @Override
+ public boolean visit( Node<Payload, PropertyPayload> unloaded ) {
+ if (unloaded != node) { // info for 'node' should not be removed
+ nodes.remove(unloaded.getNodeId());
+ changeDependencies.remove(unloaded.getNodeId());
+ unloaded.parent = null;
+ }
+ return true;
+ }
+ });
+ }
+ }
+
+ @ThreadSafe
+ public static interface Operations<NodePayload, PropertyPayload> {
+
+ /**
+ * Update the node with the information from the persistent store.
+ *
+ * @param persistentNode the persistent node that should be converted into a node info; never null
+ * @param node the session's node representation that is to be updated; never null
+ */
+ void update( org.jboss.dna.graph.Node persistentNode,
+ Node<NodePayload, PropertyPayload> node );
+
+ /**
+ * Signal that the node's {@link GraphSession.Node#getLocation() location} has been changed
+ *
+ * @param node the node with the new location
+ * @param oldLocation the old location of the node
+ */
+ void updateLocation( Node<NodePayload, PropertyPayload> node,
+ Location oldLocation );
+
+ /**
+ * Validate a node for consistency and well-formedness.
+ *
+ * @param node the node to be validated
+ * @throws ValidationException if there is a problem during validation
+ */
+ void validate( Node<NodePayload, PropertyPayload> node ) throws ValidationException;
+ }
+
+ @ThreadSafe
+ public static interface NodeIdFactory {
+ NodeId create();
+ }
+
+ @ThreadSafe
+ public static interface Authorizer {
+
+ public enum Action {
+ READ,
+ REMOVE,
+ ADD_NODE,
+ SET_PROPERTY;
+ }
+
+ /**
+ * Throws an {@link AccessControlException} if the current user is not able to perform the action on the node at the
+ * supplied path in the current workspace.
+ *
+ * @param path the path on which the actions are occurring
+ * @param action the action to check
+ * @throws AccessControlException if the user does not have permission to perform the actions
+ */
+ void checkPermissions( Path path,
+ Action action ) throws AccessControlException;
+ }
+
+ /**
+ * {@link Authorizer} implementation that does nothing.
+ */
+ @ThreadSafe
+ protected static class NoOpAuthorizer implements Authorizer {
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.graph.session.GraphSession.Authorizer#checkPermissions(org.jboss.dna.graph.property.Path,
+ * org.jboss.dna.graph.session.GraphSession.Authorizer.Action)
+ */
+ public void checkPermissions( Path path,
+ Action action ) throws AccessControlException {
+ }
+ }
+
+ @ThreadSafe
+ protected static class SimpleNodeOperations<Payload, PropertyPayload> implements Operations<Payload, PropertyPayload> {
+ /**
+ * {@inheritDoc}
+ *
+ * @see GraphSession.Operations#update(org.jboss.dna.graph.Node, GraphSession.Node)
+ */
+ public void update( org.jboss.dna.graph.Node persistentNode,
+ Node<Payload, PropertyPayload> node ) {
+ // Create the map of property info objects ...
+ Map<Name, PropertyInfo<PropertyPayload>> properties = new HashMap<Name, PropertyInfo<PropertyPayload>>();
+ for (Property property : persistentNode.getProperties()) {
+ Name propertyName = property.getName();
+ PropertyId id = new PropertyId(node.getNodeId(), propertyName);
+ PropertyInfo<PropertyPayload> info = new PropertyInfo<PropertyPayload>(id, property, property.isMultiple(),
+ PropertyStatus.UNCHANGED, null);
+ properties.put(propertyName, info);
+ }
+ // Set only the children ...
+ node.loadedWith(persistentNode.getChildren(), properties, persistentNode.getExpirationTime());
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see GraphSession.Operations#updateLocation(GraphSession.Node, org.jboss.dna.graph.Location)
+ */
+ public void updateLocation( Node<Payload, PropertyPayload> node,
+ Location oldLocation ) {
+ // do nothing here
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see GraphSession.Operations#validate(GraphSession.Node)
+ */
+ public void validate( Node<Payload, PropertyPayload> node ) {
+ // do nothing here
+ }
+ }
+
+ @NotThreadSafe
+ public static class Node<Payload, PropertyPayload> {
+ private final GraphSession<Payload, PropertyPayload> cache;
+ private final NodeId nodeId;
+ private Node<Payload, PropertyPayload> parent;
+ private long expirationTime = Long.MAX_VALUE;
+ private Location location;
+ private boolean changed;
+ private boolean changedBelow;
+ private Map<Name, PropertyInfo<PropertyPayload>> properties;
+ private ListMultimap<Name, Node<Payload, PropertyPayload>> childrenByName;
+ private Payload payload;
+
+ protected Node( GraphSession<Payload, PropertyPayload> cache,
+ Node<Payload, PropertyPayload> parent,
+ NodeId nodeId,
+ Location location ) {
+ this.cache = cache;
+ this.parent = parent;
+ this.nodeId = nodeId;
+ this.location = location;
+ assert this.cache != null;
+ assert this.nodeId != null;
+ assert this.location != null;
+ assert this.location.hasPath();
+ }
+
+ /**
+ * Get the time when this node expires.
+ *
+ * @return the time in milliseconds past the epoch when this node's cached information expires, or {@link Long#MAX_VALUE
+ * Long.MAX_VALUE} if there is no expiration or if the node has not been loaded
+ * @see #isExpired()
+ * @see #isLoaded()
+ */
+ public final long getExpirationTimeInMillis() {
+ assert !isStale();
+ return expirationTime;
+ }
+
+ /**
+ * Determine if this node's information has expired. This method will never return true if the node is not loaded. This
+ * method is idempotent.
+ *
+ * @return true if this node's information has been read from the store and is expired
+ */
+ public final boolean isExpired() {
+ return expirationTime != Long.MAX_VALUE && expirationTime < cache.getCurrentTime();
+ }
+
+ /**
+ * Determine if this node is loaded and usable. Even though the node may have been loaded previously, this method may
+ * return false (and unloads the cached information) if the cached information has expired and thus is no longer usable.
+ * Note, however, that changes on or below this node will prevent the node from being unloaded.
+ *
+ * @return true if the node's information has already been loaded and may be used, or false otherwise
+ */
+ public final boolean isLoaded() {
+ if (childrenByName == null) return false;
+ // Otherwise, it is already loaded. First see if this is expired ...
+ if (isExpired()) {
+ // It is expired, so we'd normally return false. But we should not unload if it has changes ...
+ if (isChanged(true)) return true;
+ // It is expired and contains no changes on this branch, so we can unload it ...
+ unload();
+ return false;
+ }
+ // Otherwise it is loaded and not expired ...
+ return true;
+ }
+
+ /**
+ * Method that causes the information for this node to be read from the store and loaded into the cache
+ *
+ * @throws RepositorySourceException if there is a problem reading the store
+ */
+ protected final void load() throws RepositorySourceException {
+ if (isLoaded()) return;
+ assert !isStale();
+ // Check authorization before reading ...
+ Path path = getPath();
+ cache.authorizer.checkPermissions(path, Action.READ);
+ int depth = cache.getDepthForLoadingNodes();
+ if (depth == 1) {
+ // Then read the node from the store ...
+ org.jboss.dna.graph.Node persistentNode = cache.store.getNodeAt(getLocation());
+ // Check the actual location ...
+ Location actualLocation = persistentNode.getLocation();
+ if (!this.location.equals(actualLocation)) {
+ // The actual location is changed, so update it ...
+ this.location = actualLocation;
+ }
+ // Update the persistent information ...
+ cache.nodeOperations.update(persistentNode, this);
+ } else {
+ // Then read the node from the store ...
+ Subgraph subgraph = cache.store.getSubgraphOfDepth(depth).at(getLocation());
+ Location actualLocation = subgraph.getLocation();
+ if (!this.location.equals(actualLocation)) {
+ // The actual location is changed, so update it ...
+ this.location = actualLocation;
+ }
+ // Update the persistent information ...
+ cache.nodeOperations.update(subgraph.getRoot(), this);
+ // Now update any nodes below this node ...
+ for (org.jboss.dna.graph.Node persistentNode : subgraph) {
+ // Find the node at the path ...
+ Path relativePath = persistentNode.getLocation().getPath().relativeTo(path);
+ Node<Payload, PropertyPayload> node = cache.findNodeRelativeTo(this, relativePath);
+ if (!node.isLoaded()) {
+ // Update the persistent information ...
+ cache.nodeOperations.update(persistentNode, node);
+ }
+ }
+ }
+ }
+
+ /**
+ * Utility method to unload this cached node.
+ */
+ protected final void unload() {
+ assert !isStale();
+ assert !changed;
+ assert !changedBelow;
+ if (!isLoaded()) return;
+ cache.recordUnloaded(this);
+ childrenByName = null;
+ expirationTime = Long.MAX_VALUE;
+ }
+
+ /**
+ * Phase 1 of the process of refreshing the cached content while retaining changes. This phase walks the entire tree to
+ * determine which nodes have changes, which nodes can be unloaded, and which nodes have no changes but are ancestors of
+ * those nodes with changes (and therefore have to be refreshed). Each node has a {@link #isChanged(boolean) changed
+ * state}, and the supplied RefreshState tracks which nodes must be
+ * {@link GraphSession.RefreshState#markAsRequiringRefresh(Node) refreshed} in
+ * {@link #refreshPhase2(RefreshState, Results) phase 2}; all other nodes are able to be unloaded in
+ * {@link #refreshPhase2(RefreshState, Results) phase 2}.
+ *
+ * @param refreshState the holder of the information about which nodes are to be unloaded or refreshed; may not be null
+ * @return true if the node could be (or already is) unloaded, or false otherwise
+ * @see #refreshPhase2(RefreshState, Results)
+ */
+ protected final boolean refreshPhase1( RefreshState<Payload, PropertyPayload> refreshState ) {
+ assert !isStale();
+ if (childrenByName == null) {
+ // This node is not yet loaded, so don't record it as needing to be unloaded but return true
+ return true;
+ }
+ // Perform phase 1 on each of the children ...
+ boolean canUnloadChildren = true;
+ for (Node<Payload, PropertyPayload> child : childrenByName.values()) {
+ if (child.refreshPhase1(refreshState)) {
+ // The child can be unloaded
+ canUnloadChildren = false;
+ }
+ }
+
+ // If this node has changes, then we cannot do anything with this node ...
+ if (isChanged(false)) return false;
+
+ // Otherwise, this node contains no changes ...
+ if (canUnloadChildren) {
+ // Since all the children can be unloaded, we can completely unload this node ...
+ return true;
+ }
+ // Otherwise, we have to hold onto the children, so we can't unload and must be refreshed ...
+ refreshState.markAsRequiringRefresh(this);
+ return false;
+ }
+
+ /**
+ * Phase 2 of the process of refreshing the cached content while retaining changes. This phase walks the graph and either
+ * unloads the node or, if the node is an ancestor of changed nodes, refreshes the node state to reflect that of the
+ * persistent store.
+ *
+ * @param refreshState
+ * @param persistentInfoForRefreshedNodes
+ * @see #refreshPhase1(RefreshState)
+ */
+ protected final void refreshPhase2( RefreshState<Payload, PropertyPayload> refreshState,
+ Results persistentInfoForRefreshedNodes ) {
+ assert !isStale();
+ if (this.changed) {
+ // There's nothing to do ...
+ return;
+ }
+ if (refreshState.requiresRefresh(this)) {
+ // This node must be refreshed since it has no changes but is an ancestor of a node that is changed.
+ // Therefore, update the children and properties with the just-read persistent information ...
+ assert childrenByName != null;
+ org.jboss.dna.graph.Node persistentNode = persistentInfoForRefreshedNodes.getNode(location);
+ assert !persistentNode.getChildren().isEmpty();
+ // Find the map of old Node objects keyed by their identifier ...
+ Map<NodeId, Node<Payload, PropertyPayload>> oldChildren = new HashMap<NodeId, Node<Payload, PropertyPayload>>();
+ for (Node<Payload, PropertyPayload> oldChild : childrenByName.values()) {
+ oldChildren.put(oldChild.getNodeId(), oldChild);
+ }
+ childrenByName.clear();
+ for (Location location : persistentNode.getChildren()) {
+ Name childName = location.getPath().getLastSegment().getName();
+ NodeId nodeId = cache.idFactory.create();
+ Node<Payload, PropertyPayload> child = oldChildren.remove(nodeId);
+ if (child == null) {
+ child = cache.createNode(this, nodeId, location);
+ cache.nodes.put(child.getNodeId(), child);
+ assert child.getName().equals(childName);
+ }
+ assert child.parent == this;
+ List<Node<Payload, PropertyPayload>> currentChildren = childrenByName.get(childName);
+ currentChildren.add(child);
+ // Create a segment with the SNS ...
+ Path.Segment segment = cache.pathFactory.createSegment(childName, currentChildren.size());
+ child.updateLocation(segment);
+ // TODO: Can the location be different? If so, doesn't that mean that the change requests
+ // have to be updated???
+ }
+ return;
+ }
+ // This node can be unloaded (since it has no changes and isn't above a node with changes) ...
+ unload();
+ }
+
+ /**
+ * Define the persistent child information that this node is to be populated with. This method does not cause the node's
+ * information to be read from the store.
+ * <p>
+ * This method is intended to be called by the {@link GraphSession.Operations#update(org.jboss.dna.graph.Node, Node)}, and
+ * should not be called by other components.
+ * </p>
+ *
+ * @param children the children for this node; may not be null
+ * @param properties the properties for this node; may not be null
+ * @param expirationTime the time that this cached information expires, or null if there is no expiration
+ */
+ public void loadedWith( List<Location> children,
+ Map<Name, PropertyInfo<PropertyPayload>> properties,
+ DateTime expirationTime ) {
+ assert !isStale();
+ // Load the children ...
+ if (children.isEmpty()) {
+ childrenByName = cache.NO_CHILDREN;
+ } else {
+ childrenByName = Multimaps.newLinkedListMultimap();
+ for (Location location : children) {
+ NodeId id = cache.idFactory.create();
+ Name childName = location.getPath().getLastSegment().getName();
+ Node<Payload, PropertyPayload> child = cache.createNode(this, id, location);
+ cache.nodes.put(child.getNodeId(), child);
+ List<Node<Payload, PropertyPayload>> currentChildren = childrenByName.get(childName);
+ currentChildren.add(child);
+ child.parent = this;
+ // Create a segment with the SNS ...
+ Path.Segment segment = cache.pathFactory.createSegment(childName, currentChildren.size());
+ child.updateLocation(segment);
+ }
+ }
+ // Load the properties ...
+ if (properties.isEmpty()) {
+ this.properties = cache.NO_PROPERTIES;
+ } else {
+ this.properties = new HashMap<Name, PropertyInfo<PropertyPayload>>(properties);
+ }
+
+ // Set the expiration time ...
+ this.expirationTime = expirationTime != null ? expirationTime.getMilliseconds() : Long.MAX_VALUE;
+ }
+
+ /**
+ * Reconstruct the location object for this node, given the information at the parent.
+ *
+ * @param segment the path segment for this node; may be null only when this node is the root node
+ */
+ protected void updateLocation( Path.Segment segment ) {
+ assert !isStale();
+ Path newPath = null;
+ if (segment != null) {
+ // Recompute the path based upon the parent path ...
+ Path parentPath = getParent().getPath();
+ newPath = cache.pathFactory.create(parentPath, segment);
+ } else {
+ // This must be the root ...
+ newPath = cache.pathFactory.createRootPath();
+ assert this.isRoot();
+ }
+ Location newLocation = this.location.with(newPath);
+ if (newLocation != this.location) {
+ Location oldLocation = this.location;
+ this.location = newLocation;
+ cache.nodeOperations.updateLocation(this, oldLocation);
+ }
+
+ if (isLoaded() && childrenByName != cache.NO_CHILDREN) {
+ // Update all of the children ...
+ for (Map.Entry<Name, Collection<Node<Payload, PropertyPayload>>> entry : childrenByName.asMap().entrySet()) {
+ Name childName = entry.getKey();
+ int sns = 1;
+ for (Node<Payload, PropertyPayload> child : entry.getValue()) {
+ Path.Segment childSegment = cache.pathFactory.createSegment(childName, sns++);
+ child.updateLocation(childSegment);
+ }
+ }
+ }
+ }
+
+ protected void synchronize( List<Location> actualChildren ) {
+ if (!isLoaded()) return;
+ for (Location actualChild : actualChildren) {
+ Path.Segment actualSegment = actualChild.getPath().getLastSegment();
+ Node<Payload, PropertyPayload> existingChild = parent.getChild(actualSegment);
+ if (existingChild == null) {
+ // The child doesn't exist yet ...
+ NodeId nodeId = cache.idFactory.create();
+ Node<Payload, PropertyPayload> newChild = cache.createNode(this, nodeId, actualChild);
+ parent.childrenByName.put(actualSegment.getName(), newChild);
+ }
+ }
+
+ }
+
+ /**
+ * Determine whether this node has been marked as having changes.
+ *
+ * @param recursive true if the nodes under this node should be checked, or false if only this node should be checked
+ * @return true if there are changes in the specified scope, or false otherwise
+ */
+ public final boolean isChanged( boolean recursive ) {
+ assert !isStale();
+ return recursive ? this.changed || this.changedBelow : this.changed;
+ }
+
+ /**
+ * This method determines whether this node, or any nodes below it, contain changes that depend on nodes that are outside
+ * of this branch.
+ *
+ * @return true if this branch has nodes with changes dependent on nodes outside of this branch
+ */
+ public boolean containsChangesWithExternalDependencies() {
+ assert !isStale();
+ if (!isChanged(true)) {
+ // There are no changes in this branch ...
+ return false;
+ }
+ // Need to make sure that nodes were not moved into or out of this branch, since that would mean that we
+ // cannot refresh this branch without also refreshing the other affected branches (per the JCR specification) ...
+ for (Map.Entry<NodeId, Dependencies> entry : cache.changeDependencies.entrySet()) {
+ Dependencies dependency = entry.getValue();
+ NodeId nodeId = entry.getKey();
+ Node<Payload, PropertyPayload> changedNode = cache.nodes.get(nodeId);
+
+ // First, check whether the changed node is within the branch ...
+ if (!changedNode.isAtOrBelow(this)) {
+ // The node is not within this branch, so the original parent must not be at or below this node ...
+ if (cache.nodes.get(dependency.getMovedFrom()).isAtOrBelow(this)) {
+ return false;
+ }
+ // None of the other dependencies can be within this branch ...
+ for (NodeId dependentId : dependency.getRequireChangesTo()) {
+ // The dependent node must not be at or below this node ...
+ if (cache.nodes.get(dependentId).isAtOrBelow(this)) {
+ return false;
+ }
+ }
+ // Otherwise, continue with the next change ...
+ continue;
+ }
+ // The changed node is within this branch!
+
+ // Second, check whether this node was moved from outside this branch ...
+ if (dependency.getMovedFrom() != null) {
+ Node<Payload, PropertyPayload> originalParent = cache.nodes.get(dependency.getMovedFrom());
+ // The original parent must be at or below this node ...
+ if (!originalParent.isAtOrBelow(this)) {
+ return false;
+ }
+ // All of the other dependencies must be within this branch ...
+ for (NodeId dependentId : dependency.getRequireChangesTo()) {
+ // The dependent node must not be at or below this node ...
+ if (!cache.nodes.get(dependentId).isAtOrBelow(this)) {
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Clear any transient changes that have been accumulated in this node.
+ *
+ * @see #markAsChanged()
+ */
+ public void clearChanges() {
+ assert !isStale();
+ if (this.changed) {
+ this.changed = false;
+ this.changedBelow = false;
+ unload();
+ } else {
+ if (!this.changedBelow) return;
+ // This node has not changed but something below has, so call to the children ...
+ if (childrenByName != null && childrenByName != cache.NO_CHILDREN) {
+ for (Node<Payload, PropertyPayload> child : childrenByName.values()) {
+ child.clearChanges();
+ }
+ }
+ this.changedBelow = false;
+ }
+ // Update the parent ...
+ if (this.parent != null) this.parent.recomputeChangedBelow();
+ }
+
+ /**
+ * Mark this node as having changes.
+ *
+ * @see #clearChanges()
+ */
+ public final void markAsChanged() {
+ assert !isStale();
+ this.changed = true;
+ if (this.parent != null) this.parent.markAsChangedBelow();
+ }
+
+ protected final void markAsChangedBelow() {
+ if (!this.changedBelow) {
+ this.changedBelow = true;
+ if (this.parent != null) this.parent.markAsChangedBelow();
+ }
+ }
+
+ protected final void recomputeChangedBelow() {
+ if (!this.changedBelow) return; // we're done
+ // there are changes ...
+ assert childrenByName != null;
+ for (Node<Payload, PropertyPayload> child : childrenByName.values()) {
+ if (child.isChanged(true)) {
+ this.markAsChangedBelow();
+ return;
+ }
+ }
+ // No changes found ...
+ this.changedBelow = false;
+ if (this.parent != null) this.parent.recomputeChangedBelow();
+ }
+
+ /**
+ * Move this node from its current location so that is is a child of the supplied parent.
+ *
+ * @param parent the new parent for this node; may not be null
+ * @throws RepositorySourceException if the parent node is to be loaded but a problem is encountered while doing so
+ * @throws IllegalArgumentException if this is the root node
+ */
+ public void moveTo( Node<Payload, PropertyPayload> parent ) {
+ moveTo(parent, null, true);
+ }
+
+ /**
+ * Move this node from its current location so that is is a child of the supplied parent, renaming the node in the
+ * process.
+ *
+ * @param parent the new parent for this node; may not be null
+ * @param newNodeName the new name for the node, or null if the node should keep the same name
+ * @throws RepositorySourceException if the parent node is to be loaded but a problem is encountered while doing so
+ * @throws IllegalArgumentException if this is the root node
+ */
+ public void moveTo( Node<Payload, PropertyPayload> parent,
+ Name newNodeName ) {
+ moveTo(parent, newNodeName, true);
+ }
+
+ /**
+ * Move this node from its current location so that is is a child of the supplied parent.
+ *
+ * @param parent the new parent for this node; may not be null
+ * @param newNodeName the new name for the node, or null if the node should keep the same name
+ * @param useBatch true if this operation should be performed using the session's current batch operation and executed
+ * upon {@link GraphSession#save()}, or false if the move should be performed immediately
+ * @throws RepositorySourceException if the parent node is to be loaded but a problem is encountered while doing so
+ * @throws IllegalArgumentException if this is the root node
+ */
+ protected void moveTo( Node<Payload, PropertyPayload> parent,
+ Name newNodeName,
+ boolean useBatch ) {
+ final Node<Payload, PropertyPayload> child = this;
+ assert !parent.isStale();
+ assert child.parent != this;
+ assert !child.isRoot();
+ if (newNodeName == null) newNodeName = getName();
+
+ // Check authorization ...
+ cache.authorizer.checkPermissions(parent.getPath(), Action.ADD_NODE);
+ cache.authorizer.checkPermissions(child.getPath().getParent(), Action.REMOVE);
+
+ parent.load();
+ if (parent.childrenByName == cache.NO_CHILDREN) {
+ parent.childrenByName = Multimaps.newLinkedListMultimap();
+ }
+ Name childName = child.getName();
+ List<Node<Payload, PropertyPayload>> currentChildren = parent.childrenByName.get(childName);
+ currentChildren.add(child);
+ parent.markAsChanged();
+ // Remove the child from it's existing parent ...
+ final Node<Payload, PropertyPayload> oldParent = child.parent;
+ // Record the operation ...
+ if (useBatch) {
+ if (newNodeName.equals(getName())) {
+ cache.operations.move(child.getLocation()).into(parent.getLocation());
+ } else {
+ cache.operations.move(child.getLocation()).as(newNodeName).into(parent.getLocation());
+ }
+ } else {
+ if (newNodeName.equals(getName())) {
+ cache.store.move(child.getLocation()).into(parent.getLocation());
+ } else {
+ cache.store.move(child.getLocation()).as(newNodeName).into(parent.getLocation());
+ }
+ }
+ cache.recordMove(child, oldParent, parent);
+ child.remove();
+ // Set the new parent to this node ...
+ child.parent = parent;
+ // Update the new child with the correct location ...
+ Path.Segment segment = cache.pathFactory.createSegment(childName, currentChildren.size());
+ child.updateLocation(segment);
+ }
+
+ /**
+ * Copy this node (and all nodes below it) and place the copy under the supplied parent location. The new copy will be
+ * appended to any existing children of the supplied parent node, and will be given the appropriate same-name-sibling
+ * index.
+ *
+ * @param parent the new parent for the new copy; may not be null
+ * @throws RepositorySourceException if the parent node is to be loaded but a problem is encountered while doing so
+ * @throws IllegalArgumentException if this is the root node
+ */
+ public void copyTo( Node<Payload, PropertyPayload> parent ) {
+ final Node<Payload, PropertyPayload> child = this;
+ assert !parent.isStale();
+ assert child.parent != this;
+ assert !child.isRoot();
+
+ // Check authorization ...
+ cache.authorizer.checkPermissions(parent.getPath(), Action.ADD_NODE);
+ cache.authorizer.checkPermissions(child.getPath(), Action.READ);
+
+ parent.load();
+ if (parent.childrenByName == cache.NO_CHILDREN) {
+ parent.childrenByName = Multimaps.newLinkedListMultimap();
+ }
+ Name childName = child.getName();
+ // Figure out the name and SNS of the new copy ...
+ List<Node<Payload, PropertyPayload>> currentChildren = parent.childrenByName.get(childName);
+ Location copyLocation = Location.create(cache.pathFactory.create(parent.getPath(), childName, currentChildren.size()));
+
+ // Perform the copy ...
+ cache.operations.copy(child.getLocation()).to(copyLocation);
+
+ // Add the child to the parent ...
+ cache.createNode(parent, cache.idFactory.create(), copyLocation);
+ parent.markAsChanged();
+ }
+
+ /**
+ * Clone this node (and all nodes below it). The new copy will be appended to the existing children of the
+ * {@link #getParent() parent}, and will be given the appropriate same-name-sibling index.
+ * <p>
+ * This is equivalent to calling <code>node.copyTo(node.getParent())</code>
+ * </p>
+ *
+ * @throws IllegalArgumentException if this is the root node
+ */
+ public void cloneNode() {
+ copyTo(getParent());
+ }
+
+ /**
+ * Remove this node from it's parent. Note that locations are <i>not</i> updated, since they will be updated if this node
+ * is added to a different parent. However, the locations of same-name-siblings under the parent <i>are</i> updated.
+ */
+ protected void remove() {
+ assert !isStale();
+ assert this.parent != null;
+ assert this.parent.isLoaded();
+ assert this.parent.childrenByName != null;
+ assert this.parent.childrenByName != cache.NO_CHILDREN;
+ this.parent.markAsChanged();
+ Name name = getName();
+ List<Node<Payload, PropertyPayload>> childrenWithSameName = this.parent.childrenByName.get(name);
+ this.parent = null;
+ if (childrenWithSameName.size() == 1) {
+ // No same-name-siblings ...
+ childrenWithSameName.clear();
+ } else {
+ // There is at least one other sibling with the same name ...
+ int lastIndex = childrenWithSameName.size() - 1;
+ assert lastIndex > 0;
+ int index = childrenWithSameName.indexOf(this);
+ // remove this node ...
+ childrenWithSameName.remove(index);
+ if (index != lastIndex) {
+ // There are same-name-siblings that have higher SNS indexes that this node had ...
+ for (int i = index; i != lastIndex; ++i) {
+ Node<Payload, PropertyPayload> sibling = childrenWithSameName.get(i);
+ Path.Segment segment = cache.pathFactory.createSegment(name, i + 1);
+ sibling.updateLocation(segment);
+ }
+ }
+ }
+ }
+
+ /**
+ * Remove this node from it's parent and destroy it's contents. The location of sibling nodes with the same name will be
+ * updated, and the node and all nodes below it will be destroyed and removed from the cache.
+ */
+ public void destroy() {
+ assert !isStale();
+ // Check authorization ...
+ cache.authorizer.checkPermissions(getPath(), Action.REMOVE);
+ // Remove the node from its parent ...
+ remove();
+ // This node was successfully removed, so now remove it from the cache ...
+ cache.recordDelete(this);
+ }
+
+ public final boolean isRoot() {
+ return this.parent == null;
+ }
+
+ /**
+ * Determine whether this node is stale because it was dropped from the cache.
+ *
+ * @return true if the node is stale and should no longer be used
+ */
+ public boolean isStale() {
+ // Find the root of this node ...
+ Node<?, ?> node = this;
+ while (node.parent != null) {
+ node = node.parent;
+ }
+ // The root of this branch MUST be the actual root of the cache
+ return node != cache.root;
+ }
+
+ /**
+ * Get this node's parent node.
+ *
+ * @return the parent node
+ */
+ public final Node<Payload, PropertyPayload> getParent() {
+ assert !isStale();
+ return parent;
+ }
+
+ /**
+ * @return nodeId
+ */
+ public final NodeId getNodeId() {
+ return nodeId;
+ }
+
+ /**
+ * Get the name of this node, without any same-name-sibling index.
+ *
+ * @return the name; never null
+ */
+ public final Name getName() {
+ return location.getPath().getLastSegment().getName();
+ }
+
+ /**
+ * Get the {@link Path.Segment path segment} for this node.
+ *
+ * @return the path segment; never null
+ */
+ public final Path.Segment getSegment() {
+ return location.getPath().getLastSegment();
+ }
+
+ /**
+ * Get the current path to this node.
+ *
+ * @return the current path; never null
+ */
+ public final Path getPath() {
+ return location.getPath();
+ }
+
+ /**
+ * Get the current location for this node.
+ *
+ * @return the current location; never null
+ */
+ public final Location getLocation() {
+ return location;
+ }
+
+ /**
+ * Get the child with the supplied segment.
+ *
+ * @param segment the segment of the child
+ * @return the child with the supplied name and SNS index, or null if the children have not yet been loaded
+ * @throws PathNotFoundException if the children have been loaded and the child does not exist
+ * @throws RepositorySourceException if there is a problem loading this node's information from the store
+ */
+ public Node<Payload, PropertyPayload> getChild( Path.Segment segment ) {
+ return getChild(segment.getName(), segment.getIndex());
+ }
+
+ /**
+ * Get the first child matching the name and lowest SNS index
+ *
+ * @param name the name of the child
+ * @return the first child with the supplied name, or null if the children have not yet been loaded
+ * @throws PathNotFoundException if the children have been loaded and the child does not exist
+ * @throws RepositorySourceException if there is a problem loading this node's information from the store
+ */
+ public Node<Payload, PropertyPayload> getFirstChild( Name name ) {
+ return getChild(name, 1);
+ }
+
+ /**
+ * Get the child with the supplied name and SNS index.
+ *
+ * @param name the name of the child
+ * @param sns the same-name-sibling index; must be 1 or more
+ * @return the child with the supplied name and SNS index; never null
+ * @throws PathNotFoundException if the children have been loaded and the child does not exist
+ * @throws RepositorySourceException if there is a problem loading this node's information from the store
+ */
+ public Node<Payload, PropertyPayload> getChild( Name name,
+ int sns ) {
+ load();
+ List<Node<Payload, PropertyPayload>> children = childrenByName.get(name); // never null
+ try {
+ return children.get(sns - 1); // SNS is 1-based, index is 0-based
+ } catch (IndexOutOfBoundsException e) {
+ Path missingPath = cache.pathFactory.create(getPath(), name, sns);
+ throw new PathNotFoundException(Location.create(missingPath), getPath());
+ }
+ }
+
+ /**
+ * Get an iterator over the children that have the supplied name.
+ *
+ * @param name the of the child nodes to be returned; may not be null
+ * @return an unmodifiable iterator over the cached children that have the supplied name; never null but possibly empty
+ * @throws RepositorySourceException if there is a problem loading this node's information from the store
+ */
+ public Iterable<Node<Payload, PropertyPayload>> getChildren( Name name ) {
+ load();
+ final Collection<Node<Payload, PropertyPayload>> children = childrenByName.get(name);
+ return new Iterable<Node<Payload, PropertyPayload>>() {
+ public Iterator<Node<Payload, PropertyPayload>> iterator() {
+ return new ReadOnlyIterator<Node<Payload, PropertyPayload>>(children.iterator());
+ }
+ };
+ }
+
+ /**
+ * Get an iterator over the children.
+ *
+ * @return an unmodifiable iterator over the cached children; never null
+ * @throws RepositorySourceException if there is a problem loading this node's information from the store
+ */
+ public Iterable<Node<Payload, PropertyPayload>> getChildren() {
+ load();
+ final Collection<Node<Payload, PropertyPayload>> children = childrenByName.values();
+ return new Iterable<Node<Payload, PropertyPayload>>() {
+ public Iterator<Node<Payload, PropertyPayload>> iterator() {
+ return new ReadOnlyIterator<Node<Payload, PropertyPayload>>(children.iterator());
+ }
+ };
+ }
+
+ /**
+ * Get the number of children.
+ *
+ * @return the number of children in the cache
+ * @throws RepositorySourceException if there is a problem loading this node's information from the store
+ */
+ public int getChildrenCount() {
+ load();
+ return childrenByName.size();
+ }
+
+ /**
+ * Get the number of children that have the same supplied name.
+ *
+ * @param name the name of the children to count
+ * @return the number of children in the cache
+ * @throws RepositorySourceException if there is a problem loading this node's information from the store
+ */
+ public int getChildrenCount( Name name ) {
+ load();
+ return childrenByName.get(name).size();
+ }
+
+ /**
+ * Determine if this node is a leaf node with no children.
+ *
+ * @return true if this node has no children
+ * @throws RepositorySourceException if there is a problem loading this node's information from the store
+ */
+ public boolean isLeaf() {
+ load();
+ return childrenByName.isEmpty();
+ }
+
+ /**
+ * Get from this node the property with the supplied name.
+ *
+ * @param name the property name; may not be null
+ * @return the property with the supplied name, or null if there is no such property on this node
+ */
+ public PropertyInfo<PropertyPayload> getProperty( Name name ) {
+ load();
+ return properties.get(name);
+ }
+
+ /**
+ * Set the supplied property information on this node.
+ *
+ * @param property the new property; may not be null
+ * @param isMultiValued true if the property is multi-valued
+ * @param payload the optional payload for this property; may be null
+ * @return the previous information for the property, or null if there was no previous property
+ */
+ public PropertyInfo<PropertyPayload> setProperty( Property property,
+ boolean isMultiValued,
+ PropertyPayload payload ) {
+ load();
+ cache.authorizer.checkPermissions(getPath(), Action.SET_PROPERTY);
+ Name name = property.getName();
+ PropertyInfo<PropertyPayload> previous = properties.get(name);
+ PropertyId id = null;
+ PropertyStatus status = null;
+ if (previous != null) {
+ id = previous.getPropertyId();
+ status = previous.getStatus(); // keep NEW or CHANGED status, but UNCHANGED -> CHANGED
+ if (status == PropertyStatus.UNCHANGED) status = PropertyStatus.CHANGED;
+ } else {
+ id = new PropertyId(getNodeId(), name);
+ status = PropertyStatus.NEW;
+ }
+ PropertyInfo<PropertyPayload> info = new PropertyInfo<PropertyPayload>(id, property, isMultiValued, status, payload);
+ properties.put(name, info);
+ cache.operations.set(property).on(location);
+ markAsChanged();
+ return previous;
+ }
+
+ /**
+ * Remove a property from this node.
+ *
+ * @param name the name of the property to be removed; may not be null
+ * @return the previous information for the property, or null if there was no previous property
+ */
+ public PropertyInfo<PropertyPayload> removeProperty( Name name ) {
+ load();
+ PropertyInfo<PropertyPayload> results = properties.remove(name);
+ markAsChanged();
+ cache.operations.remove(name).on(location);
+ return results;
+ }
+
+ /**
+ * Get the names of the properties on this node.
+ *
+ * @return the names of the properties; never null
+ */
+ public Set<Name> getPropertyNames() {
+ load();
+ return properties.keySet();
+ }
+
+ /**
+ * Get the information for each of the properties on this node.
+ *
+ * @return the information for each of the properties; never null
+ */
+ public Collection<PropertyInfo<PropertyPayload>> getProperties() {
+ load();
+ return properties.values();
+ }
+
+ /**
+ * Get the number of properties owned by this node.
+ *
+ * @return the number of properties; never negative
+ */
+ public int getPropertyCount() {
+ load();
+ return properties.size();
+ }
+
+ public boolean isAtOrBelow( Node<Payload, PropertyPayload> other ) {
+ Node<Payload, PropertyPayload> node = this;
+ while (node != null) {
+ if (node == other) return true;
+ node = node.getParent();
+ }
+ return false;
+ }
+
+ /**
+ * @return payload
+ */
+ public Payload getPayload() {
+ return payload;
+ }
+
+ /**
+ * @param payload Sets payload to the specified value.
+ */
+ public void setPayload( Payload payload ) {
+ this.payload = payload;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public final int hashCode() {
+ return nodeId.hashCode();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ @SuppressWarnings( "unchecked" )
+ @Override
+ public boolean equals( Object obj ) {
+ if (obj == this) return true;
+ if (obj instanceof Node) {
+ Node<Payload, PropertyPayload> that = (Node<Payload, PropertyPayload>)obj;
+ if (!this.nodeId.equals(that.nodeId)) return false;
+ return this.location.equals(that.location);
+ }
+ return false;
+ }
+
+ /**
+ * Utility method to obtain a string representation that uses the namespace prefixes where appropriate.
+ *
+ * @param registry the namespace registry, or null if no prefixes should be used
+ * @return the string representation; never null
+ */
+ public String getString( NamespaceRegistry registry ) {
+ return "Cached node <" + nodeId + "> at " + location.getString(registry);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ return getString(null);
+ }
+
+ /**
+ * Visit all nodes in the cache that are already loaded
+ *
+ * @param visitor the visitor; may not be null
+ */
+ public void onLoadedNodes( NodeVisitor<Payload, PropertyPayload> visitor ) {
+ if (this.isLoaded()) {
+ // Create a queue. This queue will contain all the nodes to be visited,
+ // so if loading is not forced, then the queue should only contain already-loaded nodes...
+ LinkedList<Node<Payload, PropertyPayload>> queue = new LinkedList<Node<Payload, PropertyPayload>>();
+ queue.add(this);
+ while (!queue.isEmpty()) {
+ Node<Payload, PropertyPayload> node = queue.poll();
+ // Get an iterator over the children *before* we visit the node
+ Iterator<Node<Payload, PropertyPayload>> iter = node.getChildren().iterator();
+ // Visit this node ...
+ if (visitor.visit(node)) {
+ // Visit the children ...
+ int index = -1;
+ while (iter.hasNext()) {
+ Node<Payload, PropertyPayload> child = iter.next();
+ if (child.isLoaded()) {
+ queue.add(++index, child);
+ }
+ }
+ }
+ }
+ }
+ visitor.finish();
+ }
+
+ /**
+ * Visit all loaded and unloaded nodes in the cache.
+ *
+ * @param visitor the visitor; may not be null
+ */
+ public void onCachedNodes( NodeVisitor<Payload, PropertyPayload> visitor ) {
+ // Create a queue. This queue will contain all the nodes to be visited,
+ // so if loading is not forced, then the queue should only contain already-loaded nodes...
+ LinkedList<Node<Payload, PropertyPayload>> queue = new LinkedList<Node<Payload, PropertyPayload>>();
+ queue.add(this);
+ while (!queue.isEmpty()) {
+ Node<Payload, PropertyPayload> node = queue.poll();
+ // Get an iterator over the children *before* we visit the node
+ Iterator<Node<Payload, PropertyPayload>> iter = node.getChildren().iterator();
+ // Visit this node ...
+ if (visitor.visit(node)) {
+ // Visit the children ...
+ int index = -1;
+ while (iter.hasNext()) {
+ Node<Payload, PropertyPayload> child = iter.next();
+ queue.add(++index, child);
+ }
+ }
+ }
+ visitor.finish();
+ }
+
+ /**
+ * Visit all changed nodes in the cache.
+ *
+ * @param visitor the visitor; may not be null
+ */
+ public void onChangedNodes( NodeVisitor<Payload, PropertyPayload> visitor ) {
+ if (this.isChanged(true)) {
+ // Create a queue. This queue will contain all the nodes to be visited ...
+ LinkedList<Node<Payload, PropertyPayload>> changedNodes = new LinkedList<Node<Payload, PropertyPayload>>();
+ changedNodes.add(this);
+ while (!changedNodes.isEmpty()) {
+ Node<Payload, PropertyPayload> node = changedNodes.poll();
+ // Visit this node ...
+ boolean visitChildren = true;
+ if (node.changed) {
+ visitChildren = visitor.visit(node);
+ }
+ if (visitChildren && node.changedBelow) {
+ // Visit the children ...
+ int index = -1;
+ Iterator<Node<Payload, PropertyPayload>> iter = node.getChildren().iterator();
+ while (iter.hasNext()) {
+ Node<Payload, PropertyPayload> child = iter.next();
+ if (node.isChanged(true)) {
+ changedNodes.add(++index, child);
+ }
+ }
+ }
+ }
+ }
+ visitor.finish();
+ }
+
+ /**
+ * Obtain a snapshot of the structure below this node.
+ *
+ * @param pathsOnly true if the snapshot should only include paths, or false if the entire locations should be included
+ * @return the snapshot
+ */
+ public StructureSnapshot<PropertyPayload> getSnapshot( final boolean pathsOnly ) {
+ final List<Snapshot<PropertyPayload>> snapshots = new ArrayList<Snapshot<PropertyPayload>>();
+ onCachedNodes(new NodeVisitor<Payload, PropertyPayload>() {
+ @Override
+ public boolean visit( Node<Payload, PropertyPayload> node ) {
+ snapshots.add(new Snapshot<PropertyPayload>(node, pathsOnly, true));
+ return node.isLoaded();
+ }
+ });
+ return new StructureSnapshot<PropertyPayload>(cache.context.getNamespaceRegistry(),
+ Collections.unmodifiableList(snapshots));
+ }
+ }
+
+ public static enum PropertyStatus {
+ NEW,
+ CHANGED,
+ UNCHANGED;
+ }
+
+ @Immutable
+ public static final class PropertyInfo<PropertyPayload> {
+ private final PropertyId propertyId;
+ private final Property property;
+ private final PropertyStatus status;
+ private final boolean multiValued;
+ private final PropertyPayload payload;
+
+ protected PropertyInfo( PropertyId propertyId,
+ Property property,
+ boolean multiValued,
+ PropertyStatus status,
+ PropertyPayload payload ) {
+ assert propertyId != null;
+ assert property != null;
+ assert status != null;
+ this.propertyId = propertyId;
+ this.property = property;
+ this.status = status;
+ this.multiValued = multiValued;
+ this.payload = payload;
+ }
+
+ /**
+ * Get the status of this property.
+ *
+ * @return the current status; never null
+ */
+ public PropertyStatus getStatus() {
+ return status;
+ }
+
+ /**
+ * Get the name of the property.
+ *
+ * @return the propert name; never null
+ */
+ public Name getName() {
+ return propertyId.getPropertyName();
+ }
+
+ /**
+ * Get the Graph API property object containing the values.
+ *
+ * @return the property object; never null
+ */
+ public Property getProperty() {
+ return property;
+ }
+
+ /**
+ * Get the identifier for this property.
+ *
+ * @return the property identifier; never null
+ */
+ public PropertyId getPropertyId() {
+ return propertyId;
+ }
+
+ /**
+ * Get the payload for this property.
+ *
+ * @return the payload; may be null if there is no payload
+ */
+ public PropertyPayload getPayload() {
+ return payload;
+ }
+
+ /**
+ * Determine whether this property has multiple values
+ *
+ * @return multiValued
+ */
+ public boolean isMultiValued() {
+ return multiValued;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ return propertyId.hashCode();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals( Object obj ) {
+ if (obj == this) return true;
+ if (obj instanceof PropertyInfo) {
+ PropertyInfo<?> that = (PropertyInfo<?>)obj;
+ return propertyId.equals(that.getPropertyId());
+ }
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append(propertyId);
+ if (payload != null) sb.append(payload);
+ if (property.isSingle()) {
+ sb.append(" with value ");
+ } else {
+ sb.append(" with values ");
+ }
+ sb.append(property.getValuesAsArray());
+ return sb.toString();
+ }
+ }
+
+ /**
+ * The node visitor.
+ *
+ * @param <NodePayload> the type of node payload object
+ * @param <PropertyPayloadType> the type of property payload object
+ */
+ @NotThreadSafe
+ public static abstract class NodeVisitor<NodePayload, PropertyPayloadType> {
+ /**
+ * Visit the supplied node, returning whether the children should be visited.
+ *
+ * @param node the node to be visited; never null
+ * @return true if the node's children should be visited, or false if no children should be visited
+ */
+ public abstract boolean visit( Node<NodePayload, PropertyPayloadType> node );
+
+ /**
+ * Method that should be called after all visiting has been done successfully (with no exceptions), including when no
+ * nodes were visited.
+ */
+ public void finish() {
+ }
+ }
+
+ /**
+ * An abstract base class for visitors that need to load nodes using a single batch for all read operations. To use, simply
+ * subclass and supply a {@link #visit(Node)} implementation that calls {@link #load(Node)} for each node that is to be
+ * loaded. When the visitor is {@link #finish() finished}, all of these nodes will be read from the store and loaded. The
+ * {@link #finishNodeAfterLoading(Node)} is called after each node is loaded, allowing the subclass to perform an operation on
+ * the newly-loaded nodes.
+ */
+ @NotThreadSafe
+ protected abstract class LoadNodesVisitor extends NodeVisitor<Payload, PropertyPayload> {
+ private Graph.Batch batch = GraphSession.this.store.batch();
+ private List<Node<Payload, PropertyPayload>> nodesToLoad = new LinkedList<Node<Payload, PropertyPayload>>();
+
+ /**
+ * Method that signals that the supplied node should be loaded (if it is not already loaded). This method should be called
+ * from within the {@link #visit(Node)} method of the subclass.
+ *
+ * @param node the node that should be loaded (if it is not already)
+ */
+ protected void load( Node<Payload, PropertyPayload> node ) {
+ if (node != null && !node.isLoaded()) {
+ nodesToLoad.add(node);
+ batch.read(node.getLocation());
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see GraphSession.NodeVisitor#finish()
+ */
+ @Override
+ public void finish() {
+ super.finish();
+ if (!nodesToLoad.isEmpty()) {
+ // Read all of the children in one batch ...
+ Results results = batch.execute();
+ // Now load all of the children into the correct node ...
+ for (Node<Payload, PropertyPayload> childToBeRead : nodesToLoad) {
+ org.jboss.dna.graph.Node persistentNode = results.getNode(childToBeRead.getLocation());
+ nodeOperations.update(persistentNode, childToBeRead);
+ finishNodeAfterLoading(childToBeRead);
+ }
+ }
+ }
+
+ /**
+ * Method that is called on each node loaded by this visitor. This method does nothing by default.
+ *
+ * @param node the just-loaded node; never null
+ */
+ protected void finishNodeAfterLoading( Node<Payload, PropertyPayload> node ) {
+ // do nothing
+ }
+ }
+
+ /**
+ * A visitor that ensures that all children of a node are loaded, and provides a hook to {@link #finishNodeAfterLoading(Node)
+ * post-process the parent}.
+ */
+ @NotThreadSafe
+ protected class LoadAllChildrenVisitor extends LoadNodesVisitor {
+ private List<Node<Payload, PropertyPayload>> parentsVisited = new LinkedList<Node<Payload, PropertyPayload>>();
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see GraphSession.NodeVisitor#visit(GraphSession.Node)
+ */
+ @Override
+ public boolean visit( Node<Payload, PropertyPayload> node ) {
+ parentsVisited.add(node);
+ Iterator<Node<Payload, PropertyPayload>> iter = node.getChildren().iterator();
+ while (iter.hasNext()) {
+ load(iter.next());
+ }
+ return true;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see GraphSession.LoadNodesVisitor#finish()
+ */
+ @Override
+ public void finish() {
+ super.finish();
+ for (Node<Payload, PropertyPayload> parent : parentsVisited) {
+ finishParentAfterLoading(parent);
+ }
+ }
+
+ /**
+ * Method that is called at the end of the {@link #finish()} stage with each parent node whose children were all loaded.
+ *
+ * @param parentNode the parent of the just-loaded children; never null
+ */
+ protected void finishParentAfterLoading( Node<Payload, PropertyPayload> parentNode ) {
+ // do nothing
+ }
+ }
+
+ protected static final class Snapshot<PropertyPayload> {
+ private final Location location;
+ private final boolean isLoaded;
+ private final boolean isChanged;
+ private final Collection<PropertyInfo<PropertyPayload>> properties;
+ private final NodeId id;
+
+ protected Snapshot( Node<?, PropertyPayload> node,
+ boolean pathsOnly,
+ boolean includeProperties ) {
+ this.location = pathsOnly && node.getLocation().hasIdProperties() ? Location.create(node.getLocation().getPath()) : node.getLocation();
+ this.isLoaded = node.isLoaded();
+ this.isChanged = node.isChanged(false);
+ this.id = node.getNodeId();
+ this.properties = includeProperties ? node.getProperties() : null;
+ }
+
+ /**
+ * @return location
+ */
+ public Location getLocation() {
+ return location;
+ }
+
+ /**
+ * @return isChanged
+ */
+ public boolean isChanged() {
+ return isChanged;
+ }
+
+ /**
+ * @return isLoaded
+ */
+ public boolean isLoaded() {
+ return isLoaded;
+ }
+
+ /**
+ * @return id
+ */
+ public NodeId getId() {
+ return id;
+ }
+
+ /**
+ * @return properties
+ */
+ public Collection<PropertyInfo<PropertyPayload>> getProperties() {
+ return properties;
+ }
+ }
+
+ /**
+ * A read-only visitor that walks the cache to obtain a snapshot of the cache structure. The resulting snapshot contains the
+ * location of each node in the tree, including unloaded nodes.
+ *
+ * @param <PropertyPayload> the property payload
+ */
+ @Immutable
+ public static final class StructureSnapshot<PropertyPayload> implements Iterable<Snapshot<PropertyPayload>> {
+ private final List<Snapshot<PropertyPayload>> snapshotsInPreOrder;
+ private final NamespaceRegistry registry;
+
+ protected StructureSnapshot( NamespaceRegistry registry,
+ List<Snapshot<PropertyPayload>> snapshotsInPreOrder ) {
+ assert snapshotsInPreOrder != null;
+ this.snapshotsInPreOrder = snapshotsInPreOrder;
+ this.registry = registry;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Iterable#iterator()
+ */
+ public Iterator<Snapshot<PropertyPayload>> iterator() {
+ return snapshotsInPreOrder.iterator();
+ }
+
+ /**
+ * Get the Location for every node in this cache
+ *
+ * @return the node locations (in pre-order)
+ */
+ public List<Snapshot<PropertyPayload>> getSnapshotsInPreOrder() {
+ return snapshotsInPreOrder;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ int maxLength = 0;
+ for (Snapshot<PropertyPayload> snapshot : this) {
+ String path = snapshot.getLocation().getPath().getString(registry);
+ maxLength = Math.max(maxLength, path.length());
+ }
+ StringBuilder sb = new StringBuilder();
+ for (Snapshot<PropertyPayload> snapshot : this) {
+ Location location = snapshot.getLocation();
+ sb.append(StringUtil.justifyLeft(location.getPath().getString(registry), maxLength, ' '));
+ // Append the node identifier ...
+ sb.append(StringUtil.justifyRight(snapshot.getId().toString(), 10, ' '));
+ // Append the various state flags
+ if (snapshot.isChanged()) sb.append(" (*)");
+ else if (!snapshot.isLoaded()) sb.append(" (-)");
+ else sb.append(" ");
+ // Append the location's identifier properties ...
+ if (location.hasIdProperties()) {
+ sb.append(" ");
+ if (location.getIdProperties().size() == 1 && location.getUuid() != null) {
+ sb.append(location.getUuid());
+ } else {
+ boolean first = true;
+ sb.append('[');
+ for (Property property : location) {
+ sb.append(property.getString(registry));
+ if (first) first = false;
+ else sb.append(", ");
+ }
+ sb.append(']');
+ }
+ }
+ // Append the property information ...
+ if (snapshot.getProperties() != null) {
+ boolean first = true;
+ sb.append(" {");
+ for (PropertyInfo<?> info : snapshot.getProperties()) {
+ if (first) first = false;
+ else sb.append("} {");
+ sb.append(info.getProperty().getString(registry));
+ }
+ sb.append("}");
+ }
+ sb.append("\n");
+ }
+ return sb.toString();
+ }
+ }
+
+ @NotThreadSafe
+ protected static final class RefreshState<Payload, PropertyPayload> {
+ private final Set<Node<Payload, PropertyPayload>> refresh = new HashSet<Node<Payload, PropertyPayload>>();
+
+ public void markAsRequiringRefresh( Node<Payload, PropertyPayload> node ) {
+ refresh.add(node);
+ }
+
+ public boolean requiresRefresh( Node<Payload, PropertyPayload> node ) {
+ return refresh.contains(node);
+ }
+
+ public Set<Node<Payload, PropertyPayload>> getNodesToBeRefreshed() {
+ return refresh;
+ }
+ }
+
+ @NotThreadSafe
+ protected final static class Dependencies {
+ private Set<NodeId> requireChangesTo;
+ private NodeId movedFrom;
+
+ public Dependencies() {
+ }
+
+ /**
+ * @return movedFrom
+ */
+ public NodeId getMovedFrom() {
+ return movedFrom;
+ }
+
+ /**
+ * Record that this node is being moved from one parent to another. This method only records the original parent, so
+ * subsequent calls to this method do nothing.
+ *
+ * @param movedFrom the identifier of the original parent of this node
+ */
+ public void setMovedFrom( NodeId movedFrom ) {
+ if (this.movedFrom == null) this.movedFrom = movedFrom;
+ }
+
+ /**
+ * @return requireChangesTo
+ */
+ public Set<NodeId> getRequireChangesTo() {
+ return requireChangesTo != null ? requireChangesTo : Collections.<NodeId>emptySet();
+ }
+
+ /**
+ * @param other the other node that changes are dependent upon
+ */
+ public void addRequireChangesTo( NodeId other ) {
+ if (other == null) return;
+ if (requireChangesTo == null) {
+ requireChangesTo = new HashSet<NodeId>();
+ }
+ requireChangesTo.add(other);
+ }
+ }
+
+ /**
+ * An immutable identifier for a node, used within the {@link GraphSession}.
+ */
+ @Immutable
+ public final static class NodeId {
+
+ private final long nodeId;
+
+ /**
+ * Create a new node identifier.
+ *
+ * @param nodeId unique identifier
+ */
+ public NodeId( long nodeId ) {
+ this.nodeId = nodeId;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ return (int)nodeId;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals( Object obj ) {
+ if (obj == this) return true;
+ if (obj instanceof NodeId) {
+ NodeId that = (NodeId)obj;
+ return this.nodeId == that.nodeId;
+ }
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ return Long.toString(nodeId);
+ }
+ }
+
+ /**
+ * An immutable identifier for a property on a node, used within the {@link GraphSession}.
+ */
+ @Immutable
+ public final static class PropertyId {
+ private final NodeId nodeId;
+ private final Name propertyName;
+ private final int hc;
+
+ public PropertyId( NodeId nodeId,
+ Name propertyName ) {
+ this.nodeId = nodeId;
+ this.propertyName = propertyName;
+ this.hc = HashCode.compute(this.nodeId, this.propertyName);
+ }
+
+ /**
+ * Get the identifier of the node on which the property exists.
+ *
+ * @return the node identifier; never null
+ */
+ public NodeId getNodeId() {
+ return nodeId;
+ }
+
+ /**
+ * Get the name of the property.
+ *
+ * @return the property name; never null
+ */
+ public Name getPropertyName() {
+ return propertyName;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ return hc;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals( Object obj ) {
+ if (obj == this) return true;
+ if (obj instanceof PropertyId) {
+ PropertyId that = (PropertyId)obj;
+ if (this.hc != that.hc) return false;
+ if (!this.nodeId.equals(that.nodeId)) return false;
+ return this.propertyName.equals(that.propertyName);
+ }
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ return this.nodeId.toString() + '@' + this.propertyName.toString();
+ }
+ }
+}
Property changes on: trunk/dna-graph/src/main/java/org/jboss/dna/graph/session/GraphSession.java
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Added: trunk/dna-graph/src/main/java/org/jboss/dna/graph/session/InvalidStateException.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/session/InvalidStateException.java (rev 0)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/session/InvalidStateException.java 2009-07-09 16:23:09 UTC (rev 1081)
@@ -0,0 +1,65 @@
+/*
+ * 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.session;
+
+/**
+ *
+ */
+public class InvalidStateException extends RuntimeException {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ *
+ */
+ public InvalidStateException() {
+ }
+
+ /**
+ * @param message
+ */
+ public InvalidStateException( String message ) {
+ super(message);
+
+ }
+
+ /**
+ * @param cause
+ */
+ public InvalidStateException( Throwable cause ) {
+ super(cause);
+
+ }
+
+ /**
+ * @param message
+ * @param cause
+ */
+ public InvalidStateException( String message,
+ Throwable cause ) {
+ super(message, cause);
+
+ }
+
+}
Property changes on: trunk/dna-graph/src/main/java/org/jboss/dna/graph/session/InvalidStateException.java
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Added: trunk/dna-graph/src/main/java/org/jboss/dna/graph/session/ValidationException.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/session/ValidationException.java (rev 0)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/session/ValidationException.java 2009-07-09 16:23:09 UTC (rev 1081)
@@ -0,0 +1,65 @@
+/*
+ * 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.session;
+
+/**
+ *
+ */
+public class ValidationException extends RuntimeException {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ *
+ */
+ public ValidationException() {
+ }
+
+ /**
+ * @param message
+ */
+ public ValidationException( String message ) {
+ super(message);
+
+ }
+
+ /**
+ * @param cause
+ */
+ public ValidationException( Throwable cause ) {
+ super(cause);
+
+ }
+
+ /**
+ * @param message
+ * @param cause
+ */
+ public ValidationException( String message,
+ Throwable cause ) {
+ super(message, cause);
+
+ }
+
+}
Property changes on: trunk/dna-graph/src/main/java/org/jboss/dna/graph/session/ValidationException.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-07-09 16:22:06 UTC (rev 1080)
+++ trunk/dna-graph/src/main/resources/org/jboss/dna/graph/GraphI18n.properties 2009-07-09 16:23:09 UTC (rev 1081)
@@ -49,7 +49,7 @@
pathExpressionHasInvalidMatch = Invalid match expression "{0}" in the path expression "{1}"
messageDigestNotFound = The "{0}" message digest algorithm could not be found
unableToAccessResourceFileFromClassLoader = Unable to access "{0}" resource from the class loader
-pathNotFoundExceptionLowestExistingLocationFound = {0}; lowest existing path is {1}
+pathNotFoundExceptionLowestExistingLocationFound = Unable to find "{0}"; lowest existing path is "{1}"
executingRequest = Executing {0}
executedRequest = Executed {0}
@@ -101,9 +101,14 @@
federatedSourceDoesNotSupportCloningWorkspaces = {0} is a source that does not allow cloning workspaces
federatedSourceDoesNotSupportDestroyingWorkspaces = {0} is a source that does not allow destroying workspaces
unableToProjectSourceInformationIntoWorkspace = Unable to project source information at {0} in the "{1} federated repository source using projection {2}
-unableToCreateNodeUnderPlaceholder = Unable to create node "{0}" under {1} in the "{2}" workspace of the "{3}" federated repository because the parent is a placeholder
-unableToUpdatePlaceholder = Unable to update node {0} in the "{1}" workspace of the "{2}" federated repository because the node is a placeholder
-unableToDeletePlaceholder = Unable to delete node {0} in the "{1}" workspace of the "{2}" federated repository because the node is a placeholder
-copyLimitedToBeWithinSingleSource = Unable to copy {0} in the "{1}" workspace of the "{3}" federated repository into {2} in the "{3}" workspace: copy is only supported when the original and new locations are within the same source
-moveLimitedToBeWithinSingleSource = Unable to move {0} in the "{1}" workspace of the "{3}" federated repository into {2} in the "{3}" workspace: move is only supported when the original and new locations are within the same source
+unableToCreateNodeUnderPlaceholder = Unable to create node "{0}" under {1} in the "{2}" workspace of the "{3}" federarted repository because the parent is a placeholder
+unableToUpdatePlaceholder = Unable to update node {0} in the "{1}" workspace of the "{2}" federarted repository because the node is a placeholder
+unableToDeletePlaceholder = Unable to delete node {0} in the "{1}" workspace of the "{2}" federarted repository because the node is a placeholder
+copyLimitedToBeWithinSingleSource = Unable to copy {0} in the "{1}" workspace of the "{3}" federarted repository into {2} in the "{3}" workspace: copy is only supported when the original and new locations are within the same source
+moveLimitedToBeWithinSingleSource = Unable to move {0} in the "{1}" workspace of the "{3}" federarted repository into {2} in the "{3}" workspace: move is only supported when the original and new locations are within the same source
cloneLimitedToBeWithinSingleSource = Unable to clone {0} in the "{1}" workspace of the "{3}" federated repository into {2} in the "{3}" workspace: clone is only supported when the original and new locations are within the same source
+
+# Session
+unableToRefreshBranchBecauseChangesDependOnChangesToNodesOutsideOfBranch = Unable to refresh "{0}" in workspace "{1}" because it contains changes that depend on changes to nodes outside of this branch
+unableToSaveBranchBecauseChangesDependOnChangesToNodesOutsideOfBranch = Unable to save "{0}" in workspace "{1}" because it contains changes that depend on changes to nodes outside of this branch
+nodeHasAlreadyBeenRemovedFromThisSession = Node "{0}" in workspace "{1} has already been removed from this session
Added: trunk/dna-graph/src/test/java/org/jboss/dna/graph/session/GraphCacheTest.java
===================================================================
--- trunk/dna-graph/src/test/java/org/jboss/dna/graph/session/GraphCacheTest.java (rev 0)
+++ trunk/dna-graph/src/test/java/org/jboss/dna/graph/session/GraphCacheTest.java 2009-07-09 16:23:09 UTC (rev 1081)
@@ -0,0 +1,574 @@
+/*
+ * 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.session;
+
+import static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.IsNot.not;
+import static org.hamcrest.core.IsNull.notNullValue;
+import static org.hamcrest.core.IsSame.sameInstance;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.fail;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import org.jboss.dna.graph.ExecutionContext;
+import org.jboss.dna.graph.Graph;
+import org.jboss.dna.graph.connector.RepositoryConnection;
+import org.jboss.dna.graph.connector.RepositoryConnectionFactory;
+import org.jboss.dna.graph.connector.RepositorySourceException;
+import org.jboss.dna.graph.connector.inmemory.InMemoryRepositorySource;
+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.session.GraphSession.Node;
+import org.jboss.dna.graph.session.GraphSession.Operations;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ *
+ */
+public class GraphCacheTest {
+
+ protected ExecutionContext context;
+ protected InMemoryRepositorySource source;
+ private Graph store;
+ private GraphSession<Object, Object> cache;
+ private PathFactory pathFactory;
+ protected int numberOfConnections;
+
+ @Before
+ public void beforeEach() throws Exception {
+ context = new ExecutionContext();
+ pathFactory = context.getValueFactories().getPathFactory();
+ source = new InMemoryRepositorySource();
+ source.setName("store");
+ // Use a connection factory so we can count the number of connections that were made
+ RepositoryConnectionFactory connectionFactory = new RepositoryConnectionFactory() {
+ public RepositoryConnection createConnection( String sourceName ) throws RepositorySourceException {
+ if (source.getName().equals(sourceName)) {
+ ++numberOfConnections;
+ return source.getConnection();
+ }
+ return null;
+ }
+ };
+ store = Graph.create(source.getName(), connectionFactory, context);
+
+ // Load the store with content ...
+ store.importXmlFrom(getClass().getClassLoader().getResourceAsStream("cars.xml")).into("/");
+ numberOfConnections = 0; // reset the number of connections
+
+ Operations<Object, Object> nodeOps = null; // use default
+ String workspaceName = null; // use current
+ cache = new GraphSession<Object, Object>(store, workspaceName, nodeOps);
+ }
+
+ @Test
+ public void shouldHaveRootNodeWithCorrectNodeIdAndLocation() {
+ Node<Object, Object> node = cache.getRoot();
+ assertThat(node, is(notNullValue()));
+ assertThat(node.getNodeId(), is(notNullValue()));
+ assertThat(node.getLocation(), is(notNullValue()));
+ assertNoMoreConnectionsUsed();
+ assertNoChanges();
+ }
+
+ @Test
+ public void shouldNotHaveAutomaticallyLoadedRootNode() {
+ assertThat(cache.getRoot().isLoaded(), is(false));
+ assertNoMoreConnectionsUsed();
+ assertNoChanges();
+ }
+
+ @Test
+ public void shouldHaveRootNodeWithChildren() {
+ Node<Object, Object> node = cache.getRoot();
+ assertChildren(node, "Cars");
+ assertConnectionsUsed(1);
+ assertNoChanges();
+ }
+
+ @Test
+ public void shouldHaveNoExpirationIfSourceDoesNotHaveCachePolicy() {
+ Node<Object, Object> node = cache.getRoot();
+ node.load();
+ assertThat(node.getExpirationTimeInMillis(), is(Long.MAX_VALUE));
+ assertConnectionsUsed(1);
+ assertNoChanges();
+ }
+
+ @Test
+ public void shouldAutomaticallyLoadNodesWhenNavigatingToChildren() {
+ Node<Object, Object> root = cache.getRoot();
+ assertThat(root.isLoaded(), is(false));
+ assertChildren(root, "Cars"); // causes loading of the root node
+ assertThat(root.isLoaded(), is(true));
+ assertConnectionsUsed(1);
+
+ Node<Object, Object> cars = root.getChildren().iterator().next(); // only one child
+ assertThat(cars.isLoaded(), is(false));
+ assertChildren(cars, "Hybrid", "Sports", "Luxury", "Utility");
+ assertConnectionsUsed(1);
+ assertThat(cars.isLoaded(), is(true));
+ assertThat(cars.getParent(), is(sameInstance(root)));
+
+ Node<Object, Object> sports = cars.getChild(segment("Sports"));
+ assertThat(sports.isLoaded(), is(false));
+ assertChildren(sports, "Aston Martin DB9", "Infiniti G37");
+ assertConnectionsUsed(1);
+ assertThat(sports.isLoaded(), is(true));
+ assertThat(sports.getParent(), is(sameInstance(cars)));
+
+ Node<Object, Object> g37 = sports.getChild(segment("Infiniti G37"));
+ assertThat(g37.isLoaded(), is(false));
+ assertChildren(g37);
+ assertConnectionsUsed(1);
+ assertThat(g37.isLoaded(), is(true));
+ assertThat(g37.isLeaf(), is(true));
+ assertThat(g37.getParent(), is(sameInstance(sports)));
+
+ // Try another branch ...
+ Node<Object, Object> utility = cars.getChild(segment("Utility"));
+ assertThat(utility.isLoaded(), is(false));
+ assertChildren(utility, "Land Rover LR2", "Land Rover LR3", "Hummer H3", "Ford F-150");
+ assertConnectionsUsed(1);
+ assertThat(utility.isLoaded(), is(true));
+ assertThat(utility.getParent(), is(sameInstance(cars)));
+
+ Node<Object, Object> lr3 = utility.getChild(segment("Land Rover LR3"));
+ assertThat(lr3.isLoaded(), is(false));
+ assertChildren(lr3);
+ assertConnectionsUsed(1);
+ assertThat(lr3.isLoaded(), is(true));
+ assertThat(lr3.isLeaf(), is(true));
+ assertThat(lr3.getParent(), is(sameInstance(utility)));
+
+ assertNoMoreConnectionsUsed();
+ assertNoChanges();
+ }
+
+ @Test
+ public void shouldFindNodesByPath() {
+ Node<Object, Object> g37 = cache.findNodeWith(path("/Cars/Sports/Infiniti G37")); // loads the node and all parents
+ assertConnectionsUsed(1);
+ assertThat(g37.isLoaded(), is(true));
+ assertChildren(g37);
+ assertThat(g37.isLoaded(), is(true));
+ assertThat(g37.isLeaf(), is(true));
+
+ Node<Object, Object> sports = g37.getParent();
+ assertThat(sports.isLoaded(), is(true));
+ assertChildren(sports, "Aston Martin DB9", "Infiniti G37");
+
+ Node<Object, Object> cars = sports.getParent();
+ assertThat(cars.isLoaded(), is(true));
+ assertChildren(cars, "Hybrid", "Sports", "Luxury", "Utility");
+
+ Node<Object, Object> root = cars.getParent();
+ assertThat(root, is(sameInstance(cache.getRoot())));
+ assertThat(root.isLoaded(), is(true));
+ assertChildren(root, "Cars"); // causes loading of the root node
+
+ assertNoMoreConnectionsUsed();
+
+ // Try another branch that should not be loaded...
+ Node<Object, Object> utility = cars.getChild(segment("Utility"));
+ assertThat(utility.isLoaded(), is(false));
+ assertChildren(utility, "Land Rover LR2", "Land Rover LR3", "Hummer H3", "Ford F-150");
+ assertConnectionsUsed(1);
+ assertThat(utility.isLoaded(), is(true));
+ assertThat(utility.getParent(), is(sameInstance(cars)));
+
+ assertNoMoreConnectionsUsed();
+ assertNoChanges();
+ }
+
+ @Test
+ public void shouldFindNodesById() {
+ cache.findNodeWith(path("/Cars/Sports/Infiniti G37")); // loads the node and all parents
+ assertConnectionsUsed(1); // "Utility" was found because it is child of "Cars" loaded when "Sports" was loaded
+
+ cache.getRoot().onCachedNodes(new GraphSession.NodeVisitor<Object, Object>() {
+ @SuppressWarnings( "synthetic-access" )
+ @Override
+ public boolean visit( Node<Object, Object> node ) {
+ assertThat(cache.findNodeWith(node.getNodeId(), null), is(sameInstance(node)));
+ return true;
+ }
+ });
+ }
+
+ @Test
+ public void shouldFindNodesByLocation() {
+ cache.findNodeWith(path("/Cars/Sports/Infiniti G37")); // loads the node and all parents
+ assertConnectionsUsed(1); // "Utility" was found because it is child of "Cars" loaded when "Sports" was loaded
+
+ cache.getRoot().onCachedNodes(new GraphSession.NodeVisitor<Object, Object>() {
+ @SuppressWarnings( "synthetic-access" )
+ @Override
+ public boolean visit( Node<Object, Object> node ) {
+ assertThat(cache.findNodeWith(null, node.getLocation().getPath()), is(sameInstance(node)));
+ return true;
+ }
+ });
+ }
+
+ @Test
+ public void shouldFindNodesByIdAfterClearing() {
+ Node<Object, Object> g37 = cache.findNodeWith(path("/Cars/Sports/Infiniti G37")); // loads the node and all parents
+ assertConnectionsUsed(1);
+ assertThat(g37.isLoaded(), is(true));
+ assertChildren(g37);
+ assertThat(g37.isLoaded(), is(true));
+ assertThat(g37.isLeaf(), is(true));
+
+ Node<Object, Object> sports = g37.getParent();
+ Node<Object, Object> cars = sports.getParent();
+ Node<Object, Object> root = cars.getParent();
+
+ assertNoMoreConnectionsUsed();
+
+ cache.getRoot().unload();
+
+ Node<Object, Object> g37_b = cache.findNodeWith(g37.getNodeId(), g37.getPath());
+ assertConnectionsUsed(1);
+
+ Node<Object, Object> sports_b = g37_b.getParent();
+ Node<Object, Object> cars_b = sports_b.getParent();
+ Node<Object, Object> root_b = cars_b.getParent();
+ assertThat(g37_b, is(not(sameInstance(g37))));
+ assertThat(sports_b, is(not(sameInstance(sports))));
+ assertThat(cars_b, is(not(sameInstance(cars))));
+ assertThat(root_b, is(sameInstance(root)));
+ assertThat(g37_b.isLeaf(), is(true));
+ assertChildren(sports_b, "Aston Martin DB9", "Infiniti G37");
+ assertChildren(cars_b, "Hybrid", "Sports", "Luxury", "Utility");
+ assertChildren(root_b, "Cars");
+
+ assertNoMoreConnectionsUsed();
+ assertNoChanges();
+ }
+
+ @Test
+ public void shouldMoveBranchAndRefresh() {
+ Node<Object, Object> sports = cache.findNodeWith(path("/Cars/Sports"));
+ Node<Object, Object> utility = cache.findNodeWith(path("/Cars/Utility"));
+ assertConnectionsUsed(1); // "Utility" was found because it is child of "Cars" loaded when "Sports" was loaded
+
+ sports.moveTo(utility);
+ assertConnectionsUsed(1); // "Utility" was not fully loaded before
+ assertNoMoreConnectionsUsed();
+
+ Node<Object, Object> cars = cache.findNodeWith(path("/Cars"));
+
+ for (int i = 0; i != 3; ++i) {
+ assertChildren(cars, "Hybrid", "Luxury", "Utility");
+ assertChildren(utility, "Land Rover LR2", "Land Rover LR3", "Hummer H3", "Ford F-150", "Sports");
+ assertThat(sports.getParent(), is(utility));
+ assertThat(utility.getParent(), is(cars));
+
+ // Ensure that the changes were recorded appropriately ...
+ assertThat(cars.isChanged(false), is(true));
+ assertThat(sports.isChanged(false), is(false));
+ assertThat(utility.isChanged(false), is(true));
+ assertThat(cache.hasPendingChanges(), is(true));
+ assertThat(cache.changeDependencies.size(), is(1));
+ assertThat(cache.changeDependencies.get(sports.getNodeId()).getMovedFrom(), is(cars.getNodeId()));
+ assertThat(cache.operations.isExecuteRequired(), is(true));
+
+ if (i == 0) {
+ // 1st time: Refreshing "Utility" shouldn't work because "/Cars" was involved in the same move ...
+ try {
+ cache.refresh(utility, false);
+ fail("Expected exception from the call to refresh");
+ } catch (InvalidStateException e) {
+ // expected ...
+ }
+ } else if (i == 1) {
+ // 2nd time: refresh "/Cars" but keep the changes ...
+ cache.refresh(cars, true);
+ } else if (i == 2) {
+ // 3rd time:
+ cache.refresh(cars, false);
+ }
+ }
+
+ // Now the state should be back to the original representation, but we need to refind the nodes ...
+ sports = cache.findNodeWith(path("/Cars/Sports"));
+ utility = cache.findNodeWith(path("/Cars/Utility"));
+ cars = cache.findNodeWith(path("/Cars"));
+
+ assertChildren(cars, "Hybrid", "Sports", "Luxury", "Utility");
+ assertChildren(utility, "Land Rover LR2", "Land Rover LR3", "Hummer H3", "Ford F-150");
+ assertThat(sports.getParent(), is(cars));
+ assertThat(utility.getParent(), is(cars));
+
+ // Now there should be no changes ...
+ assertNoChanges();
+ System.out.println(cache.root.getSnapshot(false));
+ }
+
+ @Test
+ public void shouldMoveBranchAndSaveBranch() {
+ Node<Object, Object> sports = cache.findNodeWith(path("/Cars/Sports"));
+ Node<Object, Object> utility = cache.findNodeWith(path("/Cars/Utility"));
+ assertConnectionsUsed(1); // "Utility" was found because it is child of "Cars" loaded when "Sports" was loaded
+
+ sports.moveTo(utility);
+ assertConnectionsUsed(1); // "Utility" was not fully loaded before
+ assertNoMoreConnectionsUsed();
+
+ Node<Object, Object> cars = cache.findNodeWith(path("/Cars"));
+ Node<Object, Object> root = cache.getRoot();
+
+ for (int i = 0; i != 2; ++i) {
+ assertChildren(cars, "Hybrid", "Luxury", "Utility");
+ assertChildren(utility, "Land Rover LR2", "Land Rover LR3", "Hummer H3", "Ford F-150", "Sports");
+ assertThat(sports.getParent(), is(utility));
+ assertThat(utility.getParent(), is(cars));
+
+ // Ensure that the changes were recorded appropriately ...
+ assertThat(cars.isChanged(false), is(true));
+ assertThat(sports.isChanged(false), is(false));
+ assertThat(utility.isChanged(false), is(true));
+ assertThat(cache.hasPendingChanges(), is(true));
+ assertThat(cache.changeDependencies.size(), is(1));
+ assertThat(cache.changeDependencies.get(sports.getNodeId()).getMovedFrom(), is(cars.getNodeId()));
+ assertThat(cache.operations.isExecuteRequired(), is(true));
+
+ if (i == 0) {
+ // 1st time: Saving "Utility" shouldn't work because "/Cars" was involved in the same move ...
+ try {
+ cache.save(utility);
+ fail("Expected exception from the call to save");
+ } catch (InvalidStateException e) {
+ // expected ...
+ }
+ } else if (i == 1) {
+ // 2nd time: Save "/Cars" but keep the changes ...
+ assertConnectionsUsed(0);
+ cache.save(cars);
+ assertConnectionsUsed(2); // 1 to load children required by validation, 1 to perform save
+ }
+ // i=2 do nothing
+ }
+
+ // The affected nodes should now be stale ...
+ assertThat(sports.isStale(), is(true));
+ assertThat(utility.isStale(), is(true));
+ assertThat(cars.isStale(), is(false)); // not stale because it was unloaded
+ assertThat(cars.isLoaded(), is(false));
+ assertThat(root.isStale(), is(false)); // not touched during saves
+
+ // Now the state should reflect our changes, but we need to refind the nodes ...
+ sports = cache.findNodeWith(path("/Cars/Utility/Sports"));
+ assertConnectionsUsed(1);
+ utility = cache.findNodeWith(path("/Cars/Utility"));
+ assertNoMoreConnectionsUsed();
+
+ assertChildren(cars, "Hybrid", "Luxury", "Utility");
+ assertChildren(utility, "Land Rover LR2", "Land Rover LR3", "Hummer H3", "Ford F-150", "Sports");
+ assertThat(sports.getParent(), is(utility));
+ assertThat(utility.getParent(), is(cars));
+
+ // Now there should be no changes ...
+ assertNoChanges();
+
+ System.out.println(cache.root.getSnapshot(false));
+ }
+
+ @Test
+ public void shouldMoveBranchAndSaveAll() {
+ Node<Object, Object> sports = cache.findNodeWith(path("/Cars/Sports"));
+ Node<Object, Object> utility = cache.findNodeWith(path("/Cars/Utility"));
+ assertConnectionsUsed(1); // "Utility" was found because it is child of "Cars" loaded when "Sports" was loaded
+
+ sports.moveTo(utility);
+ assertConnectionsUsed(1); // "Utility" was not fully loaded before
+ assertNoMoreConnectionsUsed();
+
+ Node<Object, Object> cars = cache.findNodeWith(path("/Cars"));
+ Node<Object, Object> root = cache.getRoot();
+
+ assertChildren(cars, "Hybrid", "Luxury", "Utility");
+ assertChildren(utility, "Land Rover LR2", "Land Rover LR3", "Hummer H3", "Ford F-150", "Sports");
+ assertThat(sports.getParent(), is(utility));
+ assertThat(utility.getParent(), is(cars));
+
+ // Ensure that the changes were recorded appropriately ...
+ assertThat(cars.isChanged(false), is(true));
+ assertThat(sports.isChanged(false), is(false));
+ assertThat(utility.isChanged(false), is(true));
+ assertThat(cache.hasPendingChanges(), is(true));
+ assertThat(cache.changeDependencies.size(), is(1));
+ assertThat(cache.changeDependencies.get(sports.getNodeId()).getMovedFrom(), is(cars.getNodeId()));
+ assertThat(cache.operations.isExecuteRequired(), is(true));
+
+ // Save the changes ...
+ assertConnectionsUsed(0);
+ cache.save();
+ assertConnectionsUsed(2); // 1 to load children required by validation, 1 to perform save
+
+ // The affected nodes should now be stale ...
+ assertThat(sports.isStale(), is(true));
+ assertThat(utility.isStale(), is(true));
+ assertThat(cars.isStale(), is(false)); // not stale because it was unloaded
+ assertThat(cars.isLoaded(), is(false));
+ assertThat(root.isStale(), is(false)); // not touched during saves
+
+ // Now the state should reflect our changes, but we need to refind the nodes ...
+ sports = cache.findNodeWith(path("/Cars/Utility/Sports"));
+ assertConnectionsUsed(1);
+ utility = cache.findNodeWith(path("/Cars/Utility"));
+ assertNoMoreConnectionsUsed();
+
+ assertChildren(cars, "Hybrid", "Luxury", "Utility");
+ assertChildren(utility, "Land Rover LR2", "Land Rover LR3", "Hummer H3", "Ford F-150", "Sports");
+ assertThat(sports.getParent(), is(utility));
+ assertThat(utility.getParent(), is(cars));
+
+ // Now there should be no changes ...
+ assertNoChanges();
+
+ // System.out.println(cache.root.getSnapshot(false));
+ }
+
+ @Test
+ public void shouldLoadSubgraphs() {
+ cache.setDepthForLoadingNodes(4);
+ Node<Object, Object> cars = cache.findNodeWith(path("/Cars")); // loads the node and all parents
+ assertChildren(cars, "Hybrid", "Sports", "Luxury", "Utility");
+ assertConnectionsUsed(1);
+
+ Node<Object, Object> sports = cache.findNodeWith(path("/Cars/Sports"));
+ Node<Object, Object> g37 = cache.findNodeWith(path("/Cars/Sports/Infiniti G37"));
+ Node<Object, Object> db9 = cache.findNodeWith(path("/Cars/Sports/Aston Martin DB9"));
+ assertConnectionsUsed(0); // should have been loaded with sports subgraph
+
+ assertThat(sports.isLoaded(), is(true));
+ assertThat(g37.isLoaded(), is(true));
+ assertThat(db9.isLoaded(), is(true));
+ assertChildren(sports, "Aston Martin DB9", "Infiniti G37");
+ assertChildren(g37);
+ assertChildren(db9);
+
+ assertNoMoreConnectionsUsed();
+ assertNoChanges();
+ }
+
+ @Test
+ public void shouldMarkAsChangedWhenSettingProperties() {
+ Node<Object, Object> g37 = cache.findNodeWith(path("/Cars/Sports/Infiniti G37"));
+ assertThat(g37.isChanged(false), is(false));
+
+ // Set the new property ...
+ Property newProperty = createProperty("something", "value1");
+ g37.setProperty(newProperty, false, null);
+ assertThat(g37.isChanged(false), is(true));
+ assertThat(cache.getRoot().isChanged(true), is(true));
+
+ // Save the changes ...
+ cache.save();
+ }
+
+ @Test
+ public void shouldClearPropertyChangesWhenRefreshing() {
+ Node<Object, Object> g37 = cache.findNodeWith(path("/Cars/Sports/Infiniti G37"));
+ assertThat(g37.isChanged(false), is(false));
+
+ // Set the new property ...
+ Property newProperty = createProperty("something", "value1");
+ g37.setProperty(newProperty, false, null);
+ assertThat(g37.isChanged(false), is(true));
+ assertThat(cache.getRoot().isChanged(true), is(true));
+
+ // Refresh the changes ...
+ cache.refresh(g37, false);
+
+ assertThat(g37.isChanged(true), is(false));
+ assertThat(cache.getRoot().isChanged(true), is(false));
+ assertNoChanges();
+ }
+
+ protected void assertChildren( Node<Object, Object> node,
+ String... childNames ) {
+ assertThat(node.getChildrenCount(), is(childNames.length));
+ List<Path.Segment> segments = new LinkedList<Path.Segment>();
+ for (String childName : childNames) {
+ segments.add(pathFactory.createSegment(childName));
+ }
+ Iterator<Path.Segment> expectedIter = segments.iterator();
+ Iterator<Node<Object, Object>> actualIter = node.getChildren().iterator();
+ while (expectedIter.hasNext() && actualIter.hasNext()) {
+ Node<Object, Object> actualNode = actualIter.next();
+ Path actualPath = actualNode.getPath();
+ Path.Segment actualSegment = actualPath.getLastSegment();
+ Path.Segment expectedSegment = expectedIter.next();
+ assertThat(actualSegment, is(expectedSegment));
+ }
+ assertThat(expectedIter.hasNext(), is(false));
+ assertThat(actualIter.hasNext(), is(false));
+ }
+
+ protected Name name( String name ) {
+ return context.getValueFactories().getNameFactory().create(name);
+ }
+
+ protected Path.Segment segment( String segment ) {
+ return context.getValueFactories().getPathFactory().createSegment(segment);
+ }
+
+ protected Path path( String path ) {
+ return context.getValueFactories().getPathFactory().create(path);
+ }
+
+ protected Property createProperty( String name,
+ Object... values ) {
+ return context.getPropertyFactory().create(name(name), values);
+ }
+
+ protected void assertChildrenNotLoaded( Node<Object, Object> node ) {
+ for (Node<Object, Object> child : node.getChildren()) {
+ assertThat(child.isLoaded(), is(false));
+ }
+ }
+
+ protected void assertNoChanges() {
+ assertThat(cache.hasPendingChanges(), is(false));
+ assertThat(cache.changeDependencies.isEmpty(), is(true));
+ assertThat(cache.operations.isExecuteRequired(), is(false));
+ }
+
+ protected void assertNoMoreConnectionsUsed() {
+ assertThat(numberOfConnections, is(0));
+ }
+
+ protected void assertConnectionsUsed( int number ) {
+ assertThat(numberOfConnections, is(number));
+ numberOfConnections = 0;
+ }
+
+}
Property changes on: trunk/dna-graph/src/test/java/org/jboss/dna/graph/session/GraphCacheTest.java
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
16 years, 6 months