Author: rhauch
Date: 2008-12-11 12:37:40 -0500 (Thu, 11 Dec 2008)
New Revision: 679
Added:
trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/util/RequestProcessorCache.java
trunk/extensions/dna-connector-store-jpa/src/test/java/org/jboss/dna/connector/store/jpa/JpaConnectionUsingHsqldbTest.java
trunk/extensions/dna-connector-store-jpa/src/test/java/org/jboss/dna/connector/store/jpa/util/RequestProcessorCacheTest.java
Removed:
trunk/dna-graph/src/test/java/org/jboss/dna/graph/IsNodeWithChildren.java
Modified:
trunk/dna-graph/src/main/java/org/jboss/dna/graph/Location.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/Subgraph.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/properties/Property.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/properties/basic/BasicName.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/properties/basic/BasicProperty.java
trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/models/basic/BasicRequestProcessor.java
trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/models/basic/SubgraphNodeEntity.java
trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/models/basic/SubgraphQuery.java
trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/models/common/NamespaceEntity.java
trunk/extensions/dna-connector-store-jpa/src/test/java/org/jboss/dna/connector/store/jpa/JpaConnectionTest.java
trunk/extensions/dna-connector-store-jpa/src/test/java/org/jboss/dna/connector/store/jpa/models/basic/SubgraphQueryTest.java
trunk/extensions/dna-connector-store-jpa/src/test/resources/log4j.properties
Log:
DNA-40 Added some optimizations to the basic model implementation, centered around a cache
of locations that have been found during the current transaction. This dramatically
improves the performance of the connector when requests are processed in batches. Also
corrected some behavior related to getting subgraphs and to making changes (primarily
deleting).
Finally, I added some 'getString(...)' methods to Property and Location, making it
easier to get usable string representations that use namespaces and encodings.
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 2008-12-10 02:27:52
UTC (rev 678)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/Location.java 2008-12-11 17:37:40
UTC (rev 679)
@@ -28,9 +28,11 @@
import java.util.NoSuchElementException;
import java.util.UUID;
import net.jcip.annotations.Immutable;
+import org.jboss.dna.common.text.TextEncoder;
import org.jboss.dna.common.util.CheckArg;
import org.jboss.dna.common.util.HashCode;
import org.jboss.dna.graph.properties.Name;
+import org.jboss.dna.graph.properties.NamespaceRegistry;
import org.jboss.dna.graph.properties.Path;
import org.jboss.dna.graph.properties.Property;
import org.jboss.dna.graph.properties.basic.BasicSingleValueProperty;
@@ -461,6 +463,108 @@
}
/**
+ * Get the string form of the location.
+ *
+ * @return the string
+ * @see #getString(TextEncoder)
+ * @see #getString(NamespaceRegistry)
+ * @see #getString(NamespaceRegistry, TextEncoder)
+ * @see #getString(NamespaceRegistry, TextEncoder, TextEncoder)
+ */
+ public String getString() {
+ return getString(null, null, null);
+ }
+
+ /**
+ * Get the encoded string form of the location, using the supplied encoder to encode
characters in each of the location's path
+ * and properties.
+ *
+ * @param encoder the encoder to use, or null if the default encoder should be used
+ * @return the encoded string
+ * @see #getString()
+ * @see #getString(NamespaceRegistry)
+ * @see #getString(NamespaceRegistry, TextEncoder)
+ * @see #getString(NamespaceRegistry, TextEncoder, TextEncoder)
+ */
+ public String getString( TextEncoder encoder ) {
+ return getString(null, encoder, null);
+ }
+
+ /**
+ * Get the encoded string form of the location, using the supplied encoder to encode
characters in each of the location's path
+ * and properties.
+ *
+ * @param namespaceRegistry the namespace registry to use for getting the string form
of the path and properties, or null if
+ * no namespace registry should be used
+ * @return the encoded string
+ * @see #getString()
+ * @see #getString(TextEncoder)
+ * @see #getString(NamespaceRegistry, TextEncoder)
+ * @see #getString(NamespaceRegistry, TextEncoder, TextEncoder)
+ */
+ public String getString( NamespaceRegistry namespaceRegistry ) {
+ CheckArg.isNotNull(namespaceRegistry, "namespaceRegistry");
+ return getString(namespaceRegistry, null, null);
+ }
+
+ /**
+ * Get the encoded string form of the location, using the supplied encoder to encode
characters in each of the location's path
+ * and properties.
+ *
+ * @param namespaceRegistry the namespace registry to use for getting the string form
of the path and properties, or null if
+ * no namespace registry should be used
+ * @param encoder the encoder to use, or null if the default encoder should be used
+ * @return the encoded string
+ * @see #getString()
+ * @see #getString(TextEncoder)
+ * @see #getString(NamespaceRegistry)
+ * @see #getString(NamespaceRegistry, TextEncoder, TextEncoder)
+ */
+ public String getString( NamespaceRegistry namespaceRegistry,
+ TextEncoder encoder ) {
+ CheckArg.isNotNull(namespaceRegistry, "namespaceRegistry");
+ return getString(namespaceRegistry, encoder, null);
+ }
+
+ /**
+ * Get the encoded string form of the location, using the supplied encoder to encode
characters in each of the location's path
+ * and properties.
+ *
+ * @param namespaceRegistry the namespace registry to use for getting the string form
of the path and properties, or null if
+ * no namespace registry should be used
+ * @param encoder the encoder to use, or null if the default encoder should be used
+ * @param delimiterEncoder the encoder to use for encoding the delimiters in paths,
names, and properties, or null if the
+ * standard delimiters should be used
+ * @return the encoded string
+ * @see #getString()
+ * @see #getString(TextEncoder)
+ * @see #getString(NamespaceRegistry)
+ * @see #getString(NamespaceRegistry, TextEncoder)
+ */
+ public String getString( NamespaceRegistry namespaceRegistry,
+ TextEncoder encoder,
+ TextEncoder delimiterEncoder ) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("{ ");
+ if (this.hasPath()) {
+ sb.append(this.getPath().getString(namespaceRegistry, encoder,
delimiterEncoder));
+ if (this.hasIdProperties()) sb.append(" && ");
+ }
+ if (this.hasIdProperties()) {
+ sb.append("[");
+ boolean first = true;
+ for (Property idProperty : this.getIdProperties()) {
+ if (first) first = false;
+ else sb.append(", ");
+ sb.append(idProperty.getString(namespaceRegistry, encoder,
delimiterEncoder));
+ }
+ sb.append("]");
+ }
+ sb.append(" }");
+ return sb.toString();
+ }
+
+ /**
* {@inheritDoc}
*
* @see java.lang.Object#toString()
@@ -468,15 +572,22 @@
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
+ sb.append("{ ");
if (this.hasPath()) {
- if (this.hasIdProperties()) sb.append("[ ");
sb.append(this.getPath());
if (this.hasIdProperties()) sb.append(" && ");
}
if (this.hasIdProperties()) {
- sb.append(this.getIdProperties().toString());
- if (this.hasPath()) sb.append(" ]");
+ sb.append("[");
+ boolean first = true;
+ for (Property idProperty : this.getIdProperties()) {
+ if (first) first = false;
+ else sb.append(", ");
+ sb.append(idProperty);
+ }
+ sb.append("]");
}
+ sb.append(" }");
return sb.toString();
}
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/Subgraph.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/Subgraph.java 2008-12-10 02:27:52
UTC (rev 678)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/Subgraph.java 2008-12-11 17:37:40
UTC (rev 679)
@@ -31,6 +31,12 @@
* Since this subgraph has a single {@link #getLocation() node that is the top of the
subgraph}, the methods that take a String
* path or {@link Path path object} will accept absolute or relative paths.
* </p>
+ * <p>
+ * This subgraph will not contain any {@link #iterator() nodes} that exist below the
{@link #getMaximumDepth() maximum depth}.
+ * Also, all nodes included in the subgraph have all their properties and children.
However, nodes that are at the maximum depth
+ * of the subgraph will contain the locations for child nodes that are below the maximum
depth and therefore not included in this
+ * subgraph.
+ * </p>
*
* @author Randall Hauch
*/
@@ -38,9 +44,9 @@
public interface Subgraph extends Results {
/**
- * Get the location of the node.
+ * Get the location of the subgraph, which is the location of the node at the top of
the subgraph.
*
- * @return the node's location
+ * @return the location of the top node in the subgraph; never null
*/
Location getLocation();
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/properties/Property.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/properties/Property.java 2008-12-10
02:27:52 UTC (rev 678)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/properties/Property.java 2008-12-11
17:37:40 UTC (rev 679)
@@ -23,6 +23,7 @@
import java.util.Iterator;
import net.jcip.annotations.Immutable;
+import org.jboss.dna.common.text.TextEncoder;
/**
* Representation of a property consisting of a name and value(s). Note that this
property is immutable, meaning that the property
@@ -153,4 +154,66 @@
*/
Object[] getValuesAsArray();
+ /**
+ * Get the string form of the property, using the default encoder.
+ *
+ * @return the encoded string
+ * @see #getString(TextEncoder)
+ */
+ public String getString();
+
+ /**
+ * Get the encoded string form of the property, using the supplied encoder to encode
characters in the property's name and
+ * values.
+ *
+ * @param encoder the encoder to use, or null if the default encoder should be used
+ * @return the encoded string
+ * @see #getString()
+ */
+ public String getString( TextEncoder encoder );
+
+ /**
+ * Get the string form of the property, using the supplied namespace registry to
convert the property's name and values.
+ *
+ * @param namespaceRegistry the namespace registry that should be used to obtain the
prefix for the
+ * {@link Name#getNamespaceUri() namespace URIs} in the property {@link
#getName() name}
+ * @return the string
+ * @throws IllegalArgumentException if the namespace registry is null
+ * @see #getString(NamespaceRegistry,TextEncoder)
+ * @see #getString(NamespaceRegistry, TextEncoder, TextEncoder)
+ */
+ public String getString( NamespaceRegistry namespaceRegistry );
+
+ /**
+ * Get the encoded string form of the property, using the supplied namespace registry
to convert the property's namespace URIs
+ * to prefixes and the supplied encoder to encode characters in the property's
name and values.
+ *
+ * @param namespaceRegistry the namespace registry that should be used to obtain the
prefix for the
+ * {@link Name#getNamespaceUri() namespace URIs} in the property {@link
#getName() name}, or null if the namespace
+ * registry should not be used
+ * @param encoder the encoder to use for encoding the name and values, or null if the
default encoder should be used
+ * @return the encoded string
+ * @see #getString(NamespaceRegistry)
+ * @see #getString(NamespaceRegistry, TextEncoder, TextEncoder)
+ */
+ public String getString( NamespaceRegistry namespaceRegistry,
+ TextEncoder encoder );
+
+ /**
+ * Get the encoded string form of the property, using the supplied namespace registry
to convert the property's namespace URIs
+ * to prefixes and the supplied encoder to encode characters in the property's
name and values.
+ *
+ * @param namespaceRegistry the namespace registry that should be used to obtain the
prefix for the
+ * {@link Name#getNamespaceUri() namespace URIs} in the property {@link
#getName() name}, or null if the namespace
+ * registry should not be used
+ * @param encoder the encoder to use for encoding the name and values, or null if the
default encoder should be used
+ * @param delimiterEncoder the encoder to use for encoding delimiters used in paths
and names, or null if the standard
+ * delimiters should be used
+ * @return the encoded string
+ * @see #getString(NamespaceRegistry)
+ * @see #getString(NamespaceRegistry, TextEncoder)
+ */
+ public String getString( NamespaceRegistry namespaceRegistry,
+ TextEncoder encoder,
+ TextEncoder delimiterEncoder );
}
Modified:
trunk/dna-graph/src/main/java/org/jboss/dna/graph/properties/basic/BasicName.java
===================================================================
---
trunk/dna-graph/src/main/java/org/jboss/dna/graph/properties/basic/BasicName.java 2008-12-10
02:27:52 UTC (rev 678)
+++
trunk/dna-graph/src/main/java/org/jboss/dna/graph/properties/basic/BasicName.java 2008-12-11
17:37:40 UTC (rev 679)
@@ -134,6 +134,7 @@
return "{" + encoder.encode(this.namespaceUri) + "}" +
encoder.encode(this.localName);
}
+ if (encoder == null) encoder = Path.DEFAULT_ENCODER;
String prefix = namespaceRegistry.getPrefixForNamespaceUri(this.namespaceUri,
true);
if (prefix != null && prefix.length() != 0) {
String delim = delimiterEncoder != null ?
delimiterEncoder.encode(":") : ":";
Modified:
trunk/dna-graph/src/main/java/org/jboss/dna/graph/properties/basic/BasicProperty.java
===================================================================
---
trunk/dna-graph/src/main/java/org/jboss/dna/graph/properties/basic/BasicProperty.java 2008-12-10
02:27:52 UTC (rev 678)
+++
trunk/dna-graph/src/main/java/org/jboss/dna/graph/properties/basic/BasicProperty.java 2008-12-11
17:37:40 UTC (rev 679)
@@ -24,7 +24,11 @@
import java.util.Arrays;
import java.util.Iterator;
import net.jcip.annotations.Immutable;
+import org.jboss.dna.common.text.TextEncoder;
+import org.jboss.dna.common.util.CheckArg;
import org.jboss.dna.graph.properties.Name;
+import org.jboss.dna.graph.properties.NamespaceRegistry;
+import org.jboss.dna.graph.properties.Path;
import org.jboss.dna.graph.properties.Property;
import org.jboss.dna.graph.properties.ValueComparators;
@@ -111,7 +115,73 @@
/**
* {@inheritDoc}
+ */
+ public String getString() {
+ return getString(null, null, null);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getString( TextEncoder encoder ) {
+ return getString(null, encoder, null);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getString( NamespaceRegistry namespaceRegistry ) {
+ CheckArg.isNotNull(namespaceRegistry, "namespaceRegistry");
+ return getString(namespaceRegistry, null, null);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getString( NamespaceRegistry namespaceRegistry,
+ TextEncoder encoder ) {
+ CheckArg.isNotNull(namespaceRegistry, "namespaceRegistry");
+ return getString(namespaceRegistry, encoder, null);
+ }
+
+ /**
+ * {@inheritDoc}
*
+ * @see
org.jboss.dna.graph.properties.Path#getString(org.jboss.dna.graph.properties.NamespaceRegistry,
+ * org.jboss.dna.common.text.TextEncoder,
org.jboss.dna.common.text.TextEncoder)
+ */
+ public String getString( NamespaceRegistry namespaceRegistry,
+ TextEncoder encoder,
+ TextEncoder delimiterEncoder ) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(getName().getString(namespaceRegistry, encoder, delimiterEncoder));
+ sb.append(" = ");
+ if (isEmpty()) {
+ sb.append("null");
+ } else {
+ if (isMultiple()) sb.append("[");
+ boolean first = true;
+ for (Object value : this) {
+ if (first) first = false;
+ else sb.append(",");
+ if (value instanceof Path) {
+ Path path = (Path)value;
+ sb.append(path.getString(namespaceRegistry, encoder,
delimiterEncoder));
+ } else if (value instanceof Name) {
+ Name name = (Name)value;
+ sb.append(name.getString(namespaceRegistry, encoder,
delimiterEncoder));
+ } else {
+ sb.append(value);
+ }
+ }
+ if (isMultiple()) sb.append("]");
+ }
+ return sb.toString();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
* @see java.lang.Object#toString()
*/
@Override
Deleted: trunk/dna-graph/src/test/java/org/jboss/dna/graph/IsNodeWithChildren.java
===================================================================
--- trunk/dna-graph/src/test/java/org/jboss/dna/graph/IsNodeWithChildren.java 2008-12-10
02:27:52 UTC (rev 678)
+++ trunk/dna-graph/src/test/java/org/jboss/dna/graph/IsNodeWithChildren.java 2008-12-11
17:37:40 UTC (rev 679)
@@ -1,82 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source.
- * Copyright 2008, Red Hat Middleware LLC, and individual contributors
- * as indicated by the @author tags. See the copyright.txt file in the
- * distribution for a full listing of individual contributors.
- *
- * This is free software; you can redistribute it and/or modify it
- * 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.
- *
- * This software 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;
-
-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.properties.Name;
-import org.jboss.dna.graph.properties.Path;
-import org.jboss.dna.graph.properties.basic.BasicPathSegment;
-import org.junit.matchers.IsCollectionContaining;
-import org.junit.matchers.TypeSafeMatcher;
-
-/**
- * @author Randall Hauch
- */
-public class IsNodeWithChildren extends TypeSafeMatcher<Node> {
- private final Matcher<Iterable<Path.Segment>> childMatcher;
-
- public IsNodeWithChildren( Matcher<Iterable<Path.Segment>> childMatcher )
{
- this.childMatcher = childMatcher;
- }
-
- @Override
- public boolean matchesSafely( Node node ) {
- List<Location> children = node.getChildren();
- List<Path.Segment> childSegments = new
ArrayList<Path.Segment>(children.size());
- for (Location child : children) {
- childSegments.add(child.getPath().getLastSegment());
- }
- return childMatcher.matches(childSegments);
- }
-
- public void describeTo( Description description ) {
- description.appendText("a node containing
children").appendDescriptionOf(childMatcher);
- }
-
- @Factory
- public static IsNodeWithChildren hasChild( Name name,
- int sameNameSiblingIndex ) {
- Path.Segment segment = new BasicPathSegment(name, sameNameSiblingIndex);
- return new IsNodeWithChildren(IsCollectionContaining.hasItem(segment));
- }
-
- @Factory
- public static IsNodeWithChildren hasChild( Path.Segment child ) {
- return new IsNodeWithChildren(IsCollectionContaining.hasItem(child));
- }
-
- @Factory
- public static IsNodeWithChildren hasChildren( Path.Segment... childSegments ) {
- return new IsNodeWithChildren(IsCollectionContaining.hasItems(childSegments));
- }
-
- @Factory
- public static IsNodeWithChildren hasNoChildren() {
- Path.Segment[] childSegments = new Path.Segment[] {};
- return new IsNodeWithChildren(IsCollectionContaining.hasItems(childSegments));
- }
-
-}
Modified:
trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/models/basic/BasicRequestProcessor.java
===================================================================
---
trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/models/basic/BasicRequestProcessor.java 2008-12-10
02:27:52 UTC (rev 678)
+++
trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/models/basic/BasicRequestProcessor.java 2008-12-11
17:37:40 UTC (rev 679)
@@ -35,11 +35,12 @@
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
+import java.util.ListIterator;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
-import java.util.zip.ZipInputStream;
-import java.util.zip.ZipOutputStream;
+import java.util.zip.GZIPInputStream;
+import java.util.zip.GZIPOutputStream;
import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;
import javax.persistence.NoResultException;
@@ -52,10 +53,12 @@
import org.jboss.dna.connector.store.jpa.JpaConnectorI18n;
import org.jboss.dna.connector.store.jpa.models.common.NamespaceEntity;
import org.jboss.dna.connector.store.jpa.util.Namespaces;
+import org.jboss.dna.connector.store.jpa.util.RequestProcessorCache;
import org.jboss.dna.connector.store.jpa.util.Serializer;
import org.jboss.dna.connector.store.jpa.util.Serializer.LargeValues;
import org.jboss.dna.graph.DnaLexicon;
import org.jboss.dna.graph.ExecutionContext;
+import org.jboss.dna.graph.JcrLexicon;
import org.jboss.dna.graph.Location;
import org.jboss.dna.graph.properties.Binary;
import org.jboss.dna.graph.properties.Name;
@@ -97,6 +100,7 @@
protected final long largeValueMinimumSizeInBytes;
protected final boolean compressData;
protected final Logger logger;
+ protected final RequestProcessorCache cache;
/**
* @param sourceName
@@ -126,6 +130,7 @@
this.compressData = compressData;
this.serializer = new Serializer(context, true);
this.logger = getExecutionContext().getLogger(getClass());
+ this.cache = new RequestProcessorCache(this.pathFactory);
// Start the transaction ...
this.entities.getTransaction().begin();
@@ -166,40 +171,72 @@
NamespaceEntity ns = namespaces.get(childNsUri, true);
assert ns != null;
- // Find the largest SNS index in the existing ChildEntity objects with the
same name ...
- String childLocalName = childName.getLocalName();
- Query query =
entities.createNamedQuery("ChildEntity.findMaximumSnsIndex");
- query.setParameter("parentUuid", parentUuidString);
- query.setParameter("ns", ns.getId());
- query.setParameter("childName", childLocalName);
+ // Figure out the next SNS index and index-in-parent for this new child ...
int nextSnsIndex = 1;
- try {
- Integer result = (Integer)query.getSingleResult();
- nextSnsIndex = result != null ? result + 1 : 1;
- } catch (NoResultException e) {
- }
+ int nextIndexInParent = 1;
+ final Path parentPath = actual.location.getPath();
+ assert parentPath != null;
+ // Look in the cache for the children of the parent node.
+ LinkedList<Location> childrenOfParent =
cache.getAllChildren(parentPath);
+ if (childrenOfParent != null) {
+ // The cache had the complete list of children for the parent node, which
means
+ // we know about all of the children and can walk the children to figure
out the next indexes.
+ nextIndexInParent = childrenOfParent.size() + 1;
+ if (nextIndexInParent > 1) {
+ // Since we want the last indexes, process the list backwards ...
+ ListIterator<Location> iter =
childrenOfParent.listIterator(childrenOfParent.size());
+ while (iter.hasPrevious()) {
+ Location existing = iter.previous();
+ Path.Segment segment = existing.getPath().getLastSegment();
+ if (!segment.getName().equals(childName)) continue;
+ // Otherwise the name matched, so get the indexes ...
+ nextSnsIndex = segment.getIndex() + 1;
+ }
+ }
+ } else {
+ // The cache did not have the complete list of children for the parent
node,
+ // so we need to look the values up by querying the database ...
- // Find the largest child index in the existing ChildEntity objects ...
- query =
entities.createNamedQuery("ChildEntity.findMaximumChildIndex");
- query.setParameter("parentUuid", parentUuidString);
- int nextIndexInParent = 1;
- try {
- Integer result = (Integer)query.getSingleResult();
- nextIndexInParent = result != null ? result + 1 : 1;
- } catch (NoResultException e) {
+ // Find the largest SNS index in the existing ChildEntity objects with
the same name ...
+ String childLocalName = childName.getLocalName();
+ Query query =
entities.createNamedQuery("ChildEntity.findMaximumSnsIndex");
+ query.setParameter("parentUuid", parentUuidString);
+ query.setParameter("ns", ns.getId());
+ query.setParameter("childName", childLocalName);
+ try {
+ Integer result = (Integer)query.getSingleResult();
+ nextSnsIndex = result != null ? result + 1 : 1;
+ } catch (NoResultException e) {
+ }
+
+ // Find the largest child index in the existing ChildEntity objects ...
+ query =
entities.createNamedQuery("ChildEntity.findMaximumChildIndex");
+ query.setParameter("parentUuid", parentUuidString);
+ try {
+ Integer result = (Integer)query.getSingleResult();
+ nextIndexInParent = result != null ? result + 1 : 1;
+ } catch (NoResultException e) {
+ }
}
// Create the new ChildEntity ...
ChildId id = new ChildId(parentUuidString, childUuidString);
- ChildEntity entity = new ChildEntity(id, nextIndexInParent, ns,
childLocalName, nextSnsIndex);
+ ChildEntity entity = new ChildEntity(id, nextIndexInParent, ns,
childName.getLocalName(), nextSnsIndex);
entities.persist(entity);
- // Look up the actual path, regardless of the supplied path...
+ // Set the actual path, regardless of the supplied path...
assert childUuidString != null;
- assert actual.location.getPath() != null;
- Path path = pathFactory.create(actual.location.getPath(), childName,
nextSnsIndex);
+ Path path = pathFactory.create(parentPath, childName, nextSnsIndex);
actualLocation = new Location(path, UUID.fromString(childUuidString));
+ // Finally, update the cache with the information we know ...
+ if (childrenOfParent != null) {
+ // Add to the cached list of children ...
+ childrenOfParent.add(actualLocation);
+ }
+ // Since we've just created this node, we know about all the children
(actually, there are none).
+ cache.setAllChildren(path, new LinkedList<Location>());
+
} catch (Throwable e) { // Includes PathNotFoundException
request.setError(e);
logger.trace(e, "Problem " + request);
@@ -213,7 +250,6 @@
*
* @see
org.jboss.dna.graph.requests.processor.RequestProcessor#process(org.jboss.dna.graph.requests.ReadNodeRequest)
*/
- @SuppressWarnings( "unchecked" )
@Override
public void process( ReadNodeRequest request ) {
logger.trace(request.toString());
@@ -223,7 +259,6 @@
ActualLocation actual = getActualLocation(location);
String parentUuidString = actual.uuid;
actualLocation = actual.location;
- Path path = actualLocation.getPath();
// Record the UUID as a property, since it's not stored in the serialized
properties...
request.addProperty(actualLocation.getIdProperty(DnaLexicon.UUID));
@@ -240,7 +275,7 @@
byte[] data = entity.getData();
LargeValueSerializer largeValues = new LargeValueSerializer(entity);
ByteArrayInputStream bais = new ByteArrayInputStream(data);
- InputStream is = compressed ? new ZipInputStream(bais) : bais;
+ InputStream is = compressed ? new GZIPInputStream(bais) : bais;
ObjectInputStream ois = new ObjectInputStream(is);
try {
serializer.deserializeAllProperties(ois, properties, largeValues);
@@ -254,18 +289,9 @@
} catch (NoResultException e) {
// No properties, but that's okay...
}
- // Find the children of the supplied node ...
- query =
entities.createNamedQuery("ChildEntity.findAllUnderParent");
- query.setParameter("parentUuidString", parentUuidString);
- List<ChildEntity> children = query.getResultList();
- for (ChildEntity child : children) {
- String namespaceUri = child.getChildNamespace().getUri();
- String localName = child.getChildName();
- Name childName = nameFactory.create(namespaceUri, localName);
- int sns = child.getSameNameSiblingIndex();
- Path childPath = pathFactory.create(path, childName, sns);
- String childUuidString = child.getId().getChildUuidString();
- Location childLocation = new Location(childPath,
UUID.fromString(childUuidString));
+
+ // Get the children for this node ...
+ for (Location childLocation : getAllChildren(actual)) {
request.addChild(childLocation);
}
} catch (NoResultException e) {
@@ -282,7 +308,6 @@
*
* @see
org.jboss.dna.graph.requests.processor.RequestProcessor#process(org.jboss.dna.graph.requests.ReadAllChildrenRequest)
*/
- @SuppressWarnings( "unchecked" )
@Override
public void process( ReadAllChildrenRequest request ) {
logger.trace(request.toString());
@@ -290,22 +315,10 @@
try {
Location location = request.of();
ActualLocation actual = getActualLocation(location);
- String parentUuidString = actual.uuid;
actualLocation = actual.location;
- Path path = actualLocation.getPath();
- // Find the children of the supplied node ...
- Query query =
entities.createNamedQuery("ChildEntity.findAllUnderParent");
- query.setParameter("parentUuidString", parentUuidString);
- List<ChildEntity> children = query.getResultList();
- for (ChildEntity child : children) {
- String namespaceUri = child.getChildNamespace().getUri();
- String localName = child.getChildName();
- Name childName = nameFactory.create(namespaceUri, localName);
- int sns = child.getSameNameSiblingIndex();
- Path childPath = pathFactory.create(path, childName, sns);
- String childUuidString = child.getId().getChildUuidString();
- Location childLocation = new Location(childPath,
UUID.fromString(childUuidString));
+ // Get the children for this node ...
+ for (Location childLocation : getAllChildren(actual)) {
request.addChild(childLocation);
}
} catch (NoResultException e) {
@@ -318,6 +331,44 @@
}
/**
+ * Utility method to obtain all of the children for a node, either from the cache (if
all children are known to this
+ * processor) or by querying the database (and caching the list of children).
+ *
+ * @param parent the actual location of the parent node; may not be null
+ * @return the list of child locations
+ */
+ protected LinkedList<Location> getAllChildren( ActualLocation parent ) {
+ assert parent != null;
+ Path parentPath = parent.location.getPath();
+ assert parentPath != null;
+ LinkedList<Location> cachedChildren = cache.getAllChildren(parentPath);
+ if (cachedChildren != null) {
+ // The cache has all of the children for the node ...
+ return cachedChildren;
+ }
+
+ // Not found in the cache, so query the database ...
+ Query query =
entities.createNamedQuery("ChildEntity.findAllUnderParent");
+ query.setParameter("parentUuidString", parent.uuid);
+ LinkedList<Location> childLocations = new LinkedList<Location>();
+ @SuppressWarnings( "unchecked" )
+ List<ChildEntity> children = query.getResultList();
+ for (ChildEntity child : children) {
+ String namespaceUri = child.getChildNamespace().getUri();
+ String localName = child.getChildName();
+ Name childName = nameFactory.create(namespaceUri, localName);
+ int sns = child.getSameNameSiblingIndex();
+ Path childPath = pathFactory.create(parentPath, childName, sns);
+ String childUuidString = child.getId().getChildUuidString();
+ Location childLocation = new Location(childPath,
UUID.fromString(childUuidString));
+ childLocations.add(childLocation);
+ }
+ // Update the cache ...
+ cache.setAllChildren(parentPath, childLocations);
+ return childLocations;
+ }
+
+ /**
* {@inheritDoc}
*
* @see
org.jboss.dna.graph.requests.processor.RequestProcessor#process(org.jboss.dna.graph.requests.ReadAllPropertiesRequest)
@@ -347,7 +398,7 @@
byte[] data = entity.getData();
LargeValueSerializer largeValues = new LargeValueSerializer(entity);
ByteArrayInputStream bais = new ByteArrayInputStream(data);
- InputStream is = compressed ? new ZipInputStream(bais) : bais;
+ InputStream is = compressed ? new GZIPInputStream(bais) : bais;
ObjectInputStream ois = new ObjectInputStream(is);
try {
serializer.deserializeAllProperties(ois, properties, largeValues);
@@ -407,7 +458,7 @@
byte[] data = entity.getData();
LargeValueSerializer largeValues = new LargeValueSerializer(entity);
ByteArrayInputStream bais = new ByteArrayInputStream(data);
- InputStream is = compressed ? new ZipInputStream(bais) : bais;
+ InputStream is = compressed ? new GZIPInputStream(bais) : bais;
ObjectInputStream ois = new ObjectInputStream(is);
try {
Serializer.LargeValues skippedLargeValues = Serializer.NO_LARGE_VALUES;
@@ -453,10 +504,10 @@
// properties ...
boolean compressed = entity.isCompressed();
ByteArrayInputStream bais = new ByteArrayInputStream(entity.getData());
- InputStream is = compressed ? new ZipInputStream(bais) : bais;
+ InputStream is = compressed ? new GZIPInputStream(bais) : bais;
ObjectInputStream ois = new ObjectInputStream(is);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
- OutputStream os = compressed ? new ZipOutputStream(baos) : baos;
+ OutputStream os = compressed ? new GZIPOutputStream(baos) : baos;
ObjectOutputStream oos = new ObjectOutputStream(os);
int numProperties = 0;
Set<String> largeValueHashesWritten = hadLargeValues ? new
HashSet<String>() : null;
@@ -517,40 +568,49 @@
locationsByUuid.put(actual.uuid, location);
// Compute the subgraph, including the root ...
- SubgraphQuery query = SubgraphQuery.create(getExecutionContext(), entities,
actualLocation.getUuid(), path, 0);
+ int maxDepth = request.maximumDepth();
+ SubgraphQuery query = SubgraphQuery.create(getExecutionContext(), entities,
actualLocation.getUuid(), path, maxDepth);
// Record all of the children ...
Path parent = path;
+ String parentUuid = actual.uuid;
Location parentLocation = actualLocation;
List<Location> children = new LinkedList<Location>();
- for (ChildEntity child : query.getNodes(false)) {
+ boolean includeChildrenOfNodesAtMaxDepth = true;
+ for (ChildEntity child : query.getNodes(false,
includeChildrenOfNodesAtMaxDepth)) {
String namespaceUri = child.getChildNamespace().getUri();
String localName = child.getChildName();
Name childName = nameFactory.create(namespaceUri, localName);
int sns = child.getSameNameSiblingIndex();
- Path childPath = pathFactory.create(path, childName, sns);
- String childUuidString = child.getId().getChildUuidString();
- Location childLocation = new Location(childPath,
UUID.fromString(childUuidString));
- locationsByUuid.put(childUuidString, childLocation);
- // Determine if this child goes into the current list of children ...
- Path childParent = childPath.getParent();
- if (childParent.equals(parent)) {
- children.add(childLocation);
- } else {
- // Record the children found so far ...
+ // Figure out who the parent is ...
+ String childParentUuid = child.getId().getParentUuidString();
+ if (!parentUuid.equals(childParentUuid)) {
+ // The parent isn't the last parent, so record the children found
so far ...
request.setChildren(parentLocation, children);
- parentLocation =
locationsByUuid.get(child.getId().getParentUuidString());
+ // And find the correct parent ...
+ parentLocation = locationsByUuid.get(childParentUuid);
parent = parentLocation.getPath();
+ parentUuid = childParentUuid;
children = new LinkedList<Location>();
- children.add(childLocation);
}
+ Path childPath = pathFactory.create(parent, childName, sns);
+ String childUuidString = child.getId().getChildUuidString();
+ Location childLocation = new Location(childPath,
UUID.fromString(childUuidString));
+ locationsByUuid.put(childUuidString, childLocation);
+ children.add(childLocation);
}
if (!children.isEmpty()) {
request.setChildren(parentLocation, children);
}
+ // Note that we've found children for nodes that are at the maximum
depth. This is so that the nodes
+ // in the subgraph all have the correct children. However, we don't want
to store the properties for
+ // any node whose depth is greater than the maximum depth. Therefore, only
get the properties that
+ // include nodes within the maximum depth...
+ includeChildrenOfNodesAtMaxDepth = false;
+
// Now record all of the properties ...
- for (PropertiesEntity props : query.getProperties(true)) {
+ for (PropertiesEntity props : query.getProperties(true,
includeChildrenOfNodesAtMaxDepth)) {
boolean compressed = props.isCompressed();
int propertyCount = props.getPropertyCount();
Collection<Property> properties = new
ArrayList<Property>(propertyCount);
@@ -562,7 +622,7 @@
byte[] data = props.getData();
LargeValueSerializer largeValues = new LargeValueSerializer(props);
ByteArrayInputStream bais = new ByteArrayInputStream(data);
- InputStream is = compressed ? new ZipInputStream(bais) : bais;
+ InputStream is = compressed ? new GZIPInputStream(bais) : bais;
ObjectInputStream ois = new ObjectInputStream(is);
try {
serializer.deserializeAllProperties(ois, properties, largeValues);
@@ -572,8 +632,6 @@
}
}
- // TODO: Now update the 'index in parent' and SNS indexes of the
siblings of the deleted node.
-
} catch (Throwable e) { // Includes PathNotFoundException
request.setError(e);
return;
@@ -610,11 +668,17 @@
SubgraphQuery query = SubgraphQuery.create(getExecutionContext(), entities,
actualLocation.getUuid(), path, 0);
// Get the locations of all deleted nodes, which will be required by events
...
- // List<Location> deletedLocations = query.getNodeLocations(true);
+ List<Location> deletedLocations = query.getNodeLocations(true, true);
// Now delete the subgraph ...
query.deleteSubgraph(true);
+ // And adjust the SNS index and indexes ...
+ // adjustSnsIndexesAndIndexesAfterRemoving(oldParentUuid, childLocalName,
ns.getId(), oldIndex, oldSnsIndex);
+
+ // Remove from the cache of children locations all entries for deleted nodes
...
+ cache.removeBranch(deletedLocations);
+
} catch (Throwable e) { // Includes PathNotFoundException
request.setError(e);
return;
@@ -637,9 +701,10 @@
ActualLocation actualLocation = getActualLocation(fromLocation);
String fromUuidString = actualLocation.uuid;
actualOldLocation = actualLocation.location;
+ Path oldPath = actualOldLocation.getPath();
// It's not possible to move the root node
- if (actualOldLocation.getPath().isRoot()) {
+ if (oldPath.isRoot()) {
String msg =
JpaConnectorI18n.unableToMoveRootNode.text(getSourceName());
throw new InvalidRequestException(msg);
}
@@ -689,9 +754,19 @@
fromEntity.setIndexInParent(nextIndexInParent);
fromEntity.setSameNameSiblingIndex(nextSnsIndex);
+ // Determine the new location ...
+ Path newParentPath = actualIntoLocation.location.getPath();
+ Name childName = oldPath.getLastSegment().getName();
+ Path newPath = pathFactory.create(newParentPath, childName,
nextSnsIndex);
+ actualNewLocation = actualOldLocation.with(newPath);
+
// And adjust the SNS index and indexes ...
adjustSnsIndexesAndIndexesAfterRemoving(oldParentUuid,
childLocalName, ns.getId(), oldIndex, oldSnsIndex);
+
+ // Update the cache ...
+ cache.moveNode(actualOldLocation, oldIndex, actualNewLocation);
}
+
}
} catch (Throwable e) { // Includes PathNotFoundException
@@ -703,15 +778,18 @@
protected void adjustSnsIndexesAndIndexesAfterRemoving( String uuidParent,
String childName,
- int childNamespaceIndex,
+ long childNamespaceIndex,
int childIndex,
int childSnsIndex ) {
+ // TODO: Now update the 'index in parent' and SNS indexes of the siblings
of the deleted node.
}
protected String createProperties( String uuidString,
Collection<Property> properties ) throws
IOException {
assert uuidString != null;
+ if (properties.isEmpty()) return uuidString;
+ if (properties.size() == 1 &&
properties.iterator().next().getName().equals(JcrLexicon.NAME)) return uuidString;
// Create the PropertiesEntity ...
NodeId nodeId = new NodeId(uuidString);
@@ -719,7 +797,7 @@
LargeValueSerializer largeValues = new LargeValueSerializer(props);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
- OutputStream os = compressData ? new ZipOutputStream(baos) : baos;
+ OutputStream os = compressData ? new GZIPOutputStream(baos) : baos;
ObjectOutputStream oos = new ObjectOutputStream(os);
int numProperties = properties.size();
try {
@@ -781,6 +859,15 @@
Property uuidProperty = original.getIdProperty(DnaLexicon.UUID);
String uuidString = uuidProperty != null && !uuidProperty.isEmpty() ?
stringFactory.create(uuidProperty.getFirstValue()) : null;
+ Path path = original.getPath();
+ if (path != null) {
+ // See if the location is already in the cache ...
+ Location cached = cache.getLocationFor(path);
+ if (cached != null) {
+ return new ActualLocation(cached, cached.getUuid().toString(), null);
+ }
+ }
+
// If the original location has a UUID, then use that to find the child entity
that represents the location ...
if (uuidString != null) {
// The original has a UUID, so use that to find the child entity.
@@ -805,11 +892,12 @@
}
}
Path fullPath = pathFactory.createAbsolutePath(segments);
- return new ActualLocation(new Location(fullPath, uuidProperty),
nodeUuidString, entity);
+ Location newLocation = new Location(fullPath, uuidProperty);
+ cache.addNewNode(newLocation);
+ return new ActualLocation(newLocation, nodeUuidString, entity);
}
// There is no UUID, so look for a path ...
- Path path = original.getPath();
if (path == null) {
String propName =
DnaLexicon.UUID.getString(getExecutionContext().getNamespaceRegistry());
String msg =
JpaConnectorI18n.locationShouldHavePathAndOrProperty.text(getSourceName(), propName);
@@ -818,36 +906,11 @@
// Walk the child entities, starting at the root, down the to the path ...
if (path.isRoot()) {
- return new ActualLocation(original.with(rootNodeUuid), rootNodeUuidString,
null);
+ Location newLocation = original.with(rootNodeUuid);
+ cache.addNewNode(newLocation);
+ return new ActualLocation(newLocation, rootNodeUuidString, null);
}
String parentUuid = this.rootNodeUuidString;
- // String childUuid = null;
- // for (Path.Segment segment : path) {
- // Name name = segment.getName();
- // String localName = name.getLocalName();
- // String nsUri = name.getNamespaceUri();
- // int snsIndex = segment.hasIndex() ? segment.getIndex() : 1;
- //
- // Query query =
entities.createNamedQuery("ChildEntity.findChildUuidByPathSegment");
- // query.setParameter("parentUuidString", parentUuid);
- // query.setParameter("nsUri", nsUri);
- // query.setParameter("childName", localName);
- // query.setParameter("sns", snsIndex);
- // try {
- // childUuid = (String)query.getSingleResult();
- // } catch (NoResultException e) {
- // // Unable to complete the path, so prepare the exception by determining the
lowest path that exists ...
- // Path lowest = path;
- // while (lowest.getLastSegment() != segment) {
- // lowest = lowest.getParent();
- // }
- // lowest = lowest.getParent();
- // throw new PathNotFoundException(original, lowest);
- // }
- // parentUuid = childUuid;
- // }
- // return new ActualLocation(original.with(UUID.fromString(childUuid)),
childUuid, null);
-
ChildEntity child = null;
for (Path.Segment segment : path) {
child = findByPathSegment(parentUuid, segment);
@@ -864,7 +927,9 @@
}
assert child != null;
uuidString = child.getId().getChildUuidString();
- return new ActualLocation(original.with(UUID.fromString(uuidString)), uuidString,
child);
+ Location newLocation = original.with(UUID.fromString(uuidString));
+ cache.addNewNode(newLocation);
+ return new ActualLocation(newLocation, uuidString, child);
}
/**
@@ -960,6 +1025,14 @@
if (entity != null) {
// Find the large value from the existing property entity ...
byte[] data = entity.getData();
+ if (entity.isCompressed()) {
+ InputStream stream = new GZIPInputStream(new
ByteArrayInputStream(data));
+ try {
+ data = IoUtil.readBytes(stream);
+ } finally {
+ stream.close();
+ }
+ }
return valueFactories.getValueFactory(entity.getType()).create(data);
}
throw new
IOException(JpaConnectorI18n.unableToReadLargeValue.text(getSourceName(), hashStr));
@@ -1004,7 +1077,7 @@
try {
binary.acquire();
stream = binary.getStream();
- if (compressData) stream = new ZipInputStream(stream);
+ if (compressData) stream = new GZIPInputStream(stream);
bytes = IoUtil.readBytes(stream);
} finally {
try {
@@ -1016,14 +1089,17 @@
break;
default:
String str = factories.getStringFactory().create(value);
- bytes = str.getBytes();
if (compressData) {
- InputStream strStream = new ZipInputStream(new
ByteArrayInputStream(bytes));
+ ByteArrayOutputStream bs = new ByteArrayOutputStream();
+ OutputStream strStream = new GZIPOutputStream(bs);
try {
- bytes = IoUtil.readBytes(strStream);
+ IoUtil.write(str, strStream);
} finally {
strStream.close();
}
+ bytes = bs.toByteArray();
+ } else {
+ bytes = str.getBytes();
}
break;
}
Modified:
trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/models/basic/SubgraphNodeEntity.java
===================================================================
---
trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/models/basic/SubgraphNodeEntity.java 2008-12-10
02:27:52 UTC (rev 678)
+++
trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/models/basic/SubgraphNodeEntity.java 2008-12-11
17:37:40 UTC (rev 679)
@@ -43,9 +43,9 @@
@NamedQueries( {
@NamedQuery( name = "SubgraphNodeEntity.insertChildren", query =
"insert into
SubgraphNodeEntity(queryId,nodeUuid,depth,parentIndexInParent,indexInParent) select
parentNode.queryId, child.id.childUuidString, parentNode.depth+1,
parentNode.indexInParent, child.indexInParent from ChildEntity child, SubgraphNodeEntity
parentNode where child.deleted is null and child.id.parentUuidString = parentNode.nodeUuid
and parentNode.queryId = :queryId and parentNode.depth = :parentDepth" ),
@NamedQuery( name = "SubgraphNodeEntity.getCount", query = "select
count(*) from SubgraphNodeEntity where queryId = :queryId" ),
- @NamedQuery( name = "SubgraphNodeEntity.getPropertiesEntities", query =
"select props from PropertiesEntity props, SubgraphNodeEntity node where
props.id.uuidString = node.nodeUuid and node.queryId = :queryId and node.depth >=
:depth order by node.depth, node.parentIndexInParent, node.indexInParent" ),
+ @NamedQuery( name = "SubgraphNodeEntity.getPropertiesEntities", query =
"select props from PropertiesEntity props, SubgraphNodeEntity node where
props.id.uuidString = node.nodeUuid and node.queryId = :queryId and node.depth >=
:depth and node.depth <= :maxDepth order by node.depth, node.parentIndexInParent,
node.indexInParent" ),
@NamedQuery( name =
"SubgraphNodeEntity.getPropertiesEntitiesWithLargeValues", query = "select
props from PropertiesEntity props, SubgraphNodeEntity node where props.id.uuidString =
node.nodeUuid and node.queryId = :queryId and node.depth >= :depth and
size(props.largeValues) > 0" ),
- @NamedQuery( name = "SubgraphNodeEntity.getChildEntities", query =
"select child from ChildEntity child, SubgraphNodeEntity node where
child.id.childUuidString = node.nodeUuid and node.queryId = :queryId and node.depth >=
:depth order by node.depth, node.parentIndexInParent, node.indexInParent" ),
+ @NamedQuery( name = "SubgraphNodeEntity.getChildEntities", query =
"select child from ChildEntity child, SubgraphNodeEntity node where
child.id.childUuidString = node.nodeUuid and node.queryId = :queryId and node.depth >=
:depth and node.depth <= :maxDepth order by node.depth, node.parentIndexInParent,
node.indexInParent" ),
@NamedQuery( name = "SubgraphNodeEntity.deletePropertiesEntities", query =
"delete PropertiesEntity props where props.id.uuidString in ( select node.nodeUuid
from SubgraphNodeEntity node where node.queryId = :queryId and node.depth >= :depth
)" ),
@NamedQuery( name = "SubgraphNodeEntity.deleteChildEntities", query =
"delete ChildEntity child where child.id.childUuidString in ( select node.nodeUuid
from SubgraphNodeEntity node where node.queryId = :queryId and node.depth >= :depth
)" ),
@NamedQuery( name = "SubgraphNodeEntity.deleteByQueryId", query =
"delete SubgraphNodeEntity where queryId = :queryId" )} )
@@ -54,7 +54,7 @@
@Id
@Column( name = "ID" )
@GeneratedValue( strategy = GenerationType.AUTO )
- private Integer id;
+ private Long id;
@Column( name = "QUERY_ID", nullable = false, unique = false, updatable =
false )
private Long queryId;
@@ -85,7 +85,7 @@
/**
* @return id
*/
- public Integer getId() {
+ public Long getId() {
return id;
}
@@ -131,7 +131,7 @@
*/
@Override
public int hashCode() {
- return id;
+ return id != null ? id.intValue() : 0;
}
/**
Modified:
trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/models/basic/SubgraphQuery.java
===================================================================
---
trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/models/basic/SubgraphQuery.java 2008-12-10
02:27:52 UTC (rev 678)
+++
trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/models/basic/SubgraphQuery.java 2008-12-11
17:37:40 UTC (rev 679)
@@ -80,11 +80,14 @@
SubgraphNodeEntity root = new SubgraphNodeEntity(queryId,
subgraphRootUuidString, 0);
entities.persist(root);
- // Now add the children by inserting the children, one level at a time ...
+ // Now add the children by inserting the children, one level at a time.
+ // Note that we do this for the root, and for each level until 1 BEYOND
+ // the max depth (so that we can get the children for the nodes that are
+ // at the maximum depth)...
Query statement =
entities.createNamedQuery("SubgraphNodeEntity.insertChildren");
int numChildrenInserted = 0;
int parentLevel = 0;
- while (parentLevel < maxDepth - 1) {
+ while (parentLevel <= maxDepth) {
// Insert the children of the next level by inserting via a select (join)
of the children
statement.setParameter("queryId", queryId);
statement.setParameter("parentDepth", parentLevel);
@@ -175,15 +178,19 @@
* Get the {@link ChildEntity nodes} in the subgraph. This must be called before the
query is {@link #close() closed}.
*
* @param includeRoot true if the subgraph's root node is to be included, or
false otherwise
+ * @param includeChildrenOfMaxDepthNodes true if the method is to include nodes that
are children of nodes that are at the
+ * maximum depth, or false if only nodes up to the maximum depth are to be
included
* @return the list of nodes, in breadth-first order
*/
@SuppressWarnings( "unchecked" )
- public List<ChildEntity> getNodes( boolean includeRoot ) {
+ public List<ChildEntity> getNodes( boolean includeRoot,
+ boolean includeChildrenOfMaxDepthNodes ) {
if (query == null) throw new IllegalStateException();
// Now query for all the nodes and put into a list ...
Query search =
manager.createNamedQuery("SubgraphNodeEntity.getChildEntities");
search.setParameter("queryId", query.getId());
search.setParameter("depth", includeRoot ? 0 : 1);
+ search.setParameter("maxDepth", includeChildrenOfMaxDepthNodes ?
maxDepth : maxDepth - 1);
// Now process the nodes below the subgraph's root ...
return search.getResultList();
@@ -194,15 +201,19 @@
* {@link #close() closed}.
*
* @param includeRoot true if the properties for the subgraph's root node are to
be included, or false otherwise
+ * @param includeChildrenOfMaxDepthNodes true if the method is to include nodes that
are children of nodes that are at the
+ * maximum depth, or false if only nodes up to the maximum depth are to be
included
* @return the list of properties for each of the nodes, in breadth-first order
*/
@SuppressWarnings( "unchecked" )
- public List<PropertiesEntity> getProperties( boolean includeRoot ) {
+ public List<PropertiesEntity> getProperties( boolean includeRoot,
+ boolean includeChildrenOfMaxDepthNodes )
{
if (query == null) throw new IllegalStateException();
// Now query for all the nodes and put into a list ...
Query search =
manager.createNamedQuery("SubgraphNodeEntity.getPropertiesEntities");
search.setParameter("queryId", query.getId());
search.setParameter("depth", includeRoot ? 0 : 1);
+ search.setParameter("maxDepth", includeChildrenOfMaxDepthNodes ?
maxDepth : maxDepth - 1);
// Now process the nodes below the subgraph's root ...
return search.getResultList();
@@ -212,14 +223,17 @@
* Get the {@link Location} for each of the nodes in the subgraph. This must be
called before the query is {@link #close()
* closed}.
* <p>
- * This method calls {@link #getNodes(boolean)}. Therefore, calling {@link
#getNodes(boolean)} and this method for the same
- * subgraph is not efficient; consider just calling {@link #getNodes(boolean)}
alone.
+ * This method calls {@link #getNodes(boolean,boolean)}. Therefore, calling {@link
#getNodes(boolean,boolean)} and this method
+ * for the same subgraph is not efficient; consider just calling {@link
#getNodes(boolean,boolean)} alone.
* </p>
*
* @param includeRoot true if the properties for the subgraph's root node are to
be included, or false otherwise
+ * @param includeChildrenOfMaxDepthNodes true if the method is to include nodes that
are children of nodes that are at the
+ * maximum depth, or false if only nodes up to the maximum depth are to be
included
* @return the list of {@link Location locations}, one for each of the nodes in the
subgraph, in breadth-first order
*/
- public List<Location> getNodeLocations( boolean includeRoot ) {
+ public List<Location> getNodeLocations( boolean includeRoot,
+ boolean includeChildrenOfMaxDepthNodes ) {
if (query == null) throw new IllegalStateException();
// Set up a map of the paths to the nodes, keyed by UUIDs. This saves us from
having to build
// the paths every time ...
@@ -235,7 +249,7 @@
// Now iterate over the child nodes in the subgraph (we've already included
the root) ...
final PathFactory pathFactory = context.getValueFactories().getPathFactory();
final NameFactory nameFactory = context.getValueFactories().getNameFactory();
- for (ChildEntity entity : getNodes(false)) {
+ for (ChildEntity entity : getNodes(false, includeChildrenOfMaxDepthNodes)) {
String parentUuid = entity.getId().getParentUuidString();
Path parentPath = pathByUuid.get(parentUuid);
assert parentPath != null;
Modified:
trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/models/common/NamespaceEntity.java
===================================================================
---
trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/models/common/NamespaceEntity.java 2008-12-10
02:27:52 UTC (rev 678)
+++
trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/models/common/NamespaceEntity.java 2008-12-11
17:37:40 UTC (rev 679)
@@ -50,7 +50,7 @@
@Id
@GeneratedValue( strategy = GenerationType.AUTO )
- private Integer id;
+ private Long id;
@Column( name = "URI", nullable = false, unique = false, length = 512,
updatable = false )
private String uri;
@@ -71,14 +71,14 @@
/**
* @return id
*/
- public Integer getId() {
+ public Long getId() {
return id;
}
/**
* @param id Sets id to the specified value.
*/
- public void setId( Integer id ) {
+ public void setId( Long id ) {
this.id = id;
}
Added:
trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/util/RequestProcessorCache.java
===================================================================
---
trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/util/RequestProcessorCache.java
(rev 0)
+++
trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/util/RequestProcessorCache.java 2008-12-11
17:37:40 UTC (rev 679)
@@ -0,0 +1,276 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * 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.
+ *
+ * This software 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.store.jpa.util;
+
+import java.util.ArrayList;
+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.ListIterator;
+import java.util.Map;
+import java.util.Set;
+import org.jboss.dna.common.util.StringUtil;
+import org.jboss.dna.graph.Location;
+import org.jboss.dna.graph.properties.Name;
+import org.jboss.dna.graph.properties.NamespaceRegistry;
+import org.jboss.dna.graph.properties.Path;
+import org.jboss.dna.graph.properties.PathFactory;
+
+/**
+ * Represents a cache of the known node information, including a node's actual {@link
Location} and the complete set of children.
+ *
+ * @author Randall Hauch
+ */
+public class RequestProcessorCache {
+
+ private final PathFactory pathFactory;
+ private final Map<Path, Location> locationByPath = new HashMap<Path,
Location>();
+ private final Map<Path, LinkedList<Location>> childrenByParentPath = new
HashMap<Path, LinkedList<Location>>();
+
+ public RequestProcessorCache( PathFactory pathFactory ) {
+ assert pathFactory != null;
+ this.pathFactory = pathFactory;
+ }
+
+ public Location getLocationFor( Path node ) {
+ return locationByPath.get(node);
+ }
+
+ public void addNewNode( Location location ) {
+ assert location != null;
+ Path path = location.getPath();
+ assert path != null;
+ locationByPath.put(path, location);
+ }
+
+ public LinkedList<Location> getAllChildren( Path parent ) {
+ return childrenByParentPath.get(parent);
+ }
+
+ public void setAllChildren( Path parent,
+ LinkedList<Location> children ) {
+ if (children == null) {
+ childrenByParentPath.remove(parent);
+ } else {
+ childrenByParentPath.put(parent, children);
+ }
+ }
+
+ public boolean moveNode( Location oldLocation,
+ int oldIndexInParent,
+ Location newLocation ) {
+ assert oldLocation != null;
+ assert newLocation != null;
+ Path oldPath = oldLocation.getPath();
+ assert oldPath != null;
+
+ // Now the locations of all nodes below the old location are invalid, as are all
lists of children ...
+ // The easiest and most efficient thing to do would be to simply remove them from
the cache ...
+ removeNodesBelow(oldPath, true);
+
+ // Remove the node from the list of children for the old parent ...
+ LinkedList<Location> siblings =
childrenByParentPath.get(oldPath.getParent());
+ boolean removed = false;
+ if (siblings != null) {
+ removed = removeChildFromParentListOfChildren(siblings, oldLocation, -1);
+ }
+
+ // If the children are cached for the new parent ...
+ Path newPath = newLocation.getPath();
+ assert newPath != null;
+ LinkedList<Location> newSiblings =
childrenByParentPath.get(newPath.getParent());
+ if (newSiblings != null) {
+ newSiblings.add(newLocation);
+ }
+
+ return removed;
+ }
+
+ protected void removeNodesBelow( Path path,
+ boolean removeNodeAtSuppliedPath ) {
+ if (removeNodeAtSuppliedPath) {
+ locationByPath.remove(path);
+ childrenByParentPath.remove(path);
+ }
+ for (Iterator<Path> iter = locationByPath.keySet().iterator();
iter.hasNext();) {
+ Path nextPath = iter.next();
+ if (nextPath.isDecendantOf(path)) iter.remove();
+ }
+ for (Iterator<Path> iter = childrenByParentPath.keySet().iterator();
iter.hasNext();) {
+ Path nextPath = iter.next();
+ if (nextPath.isDecendantOf(path)) iter.remove();
+ }
+ }
+
+ public boolean removeBranch( Iterable<Location> locations ) {
+ if (locations == null) return false;
+ Iterator<Location> iter = locations.iterator();
+ if (!iter.hasNext()) return false;
+
+ Location topNode = iter.next();
+
+ // Now remove all cached locations and child lists for each deleted node ...
+ boolean removed = false;
+ while (iter.hasNext()) {
+ Location location = iter.next();
+ Path path = location.getPath();
+ assert path != null;
+ if (locationByPath.remove(path) != null) removed = true;
+ if (childrenByParentPath.remove(path) != null) removed = true;
+ }
+
+ // The first node will be the root of the branch, so remove this from the
parent's list of children
+ // and adjust all SNS indexes of same-name-siblings that appear after the removed
node ...
+ Path path = topNode.getPath();
+ assert path != null;
+ LinkedList<Location> siblings =
childrenByParentPath.get(path.getParent());
+ if (siblings != null) {
+ removed = removeChildFromParentListOfChildren(siblings, topNode, -1);
+ }
+ childrenByParentPath.remove(path);
+
+ return removed;
+ }
+
+ protected boolean removeChildFromParentListOfChildren( LinkedList<Location>
siblings,
+ Location deletedNode,
+ int expectedIndex ) {
+ assert siblings != null;
+ Path path = deletedNode.getPath();
+ Path parentPath = path.getParent();
+
+ // Find and remove the deleted node ...
+ boolean removed = false;
+ int index = 0;
+ Path.Segment deletedNodeSegment = path.getLastSegment();
+ ListIterator<Location> iter = null;
+ if (expectedIndex > -1 && expectedIndex < siblings.size()) {
+ Location locationAtExpectedIndex = siblings.get(expectedIndex);
+ if (locationAtExpectedIndex.equals(deletedNode)) {
+ siblings.remove(expectedIndex);
+ removed = true;
+ index = expectedIndex;
+ }
+ }
+ if (!removed) {
+ iter = siblings.listIterator();
+ while (iter.hasNext()) {
+ Location sibling = iter.next();
+ Path.Segment segment = sibling.getPath().getLastSegment();
+ if (segment.equals(deletedNodeSegment)) {
+ iter.remove();
+ removed = true;
+ break;
+ }
+ ++index;
+ }
+ }
+
+ // Iterate starting at the supplied index, and adjust the locations for
same-name-siblings ...
+ iter = siblings.listIterator(index);
+ Name name = deletedNodeSegment.getName();
+ while (iter.hasNext()) {
+ Location laterSibling = iter.next();
+ Path siblingPath = laterSibling.getPath();
+ Path.Segment segment = siblingPath.getLastSegment();
+ // If this sibling has the same name and appeared after deleted node, so
decrement the SNS index ...
+ if (segment.getName().equals(name)) {
+ assert segment.getIndex() > 1;
+ Path newPath = pathFactory.create(parentPath, name, segment.getIndex() -
1);
+ Location newLocation = laterSibling.with(newPath);
+ iter.set(newLocation);
+
+ // Remove the existing location for the old path ...
+ locationByPath.remove(siblingPath);
+
+ // Remove all nodes below (not at) this sibling ...
+ removeNodesBelow(siblingPath, false);
+
+ // Now put in the location for the modified sibling ...
+ locationByPath.put(newPath, newLocation);
+ }
+ }
+ return removed;
+ }
+
+ public String getString( NamespaceRegistry namespaces ) {
+ StringBuilder sb = new StringBuilder();
+ Set<Path> pathSet = new HashSet<Path>();
+ pathSet.addAll(locationByPath.keySet());
+ pathSet.addAll(childrenByParentPath.keySet());
+ List<Path> paths = new ArrayList<Path>(pathSet);
+ Collections.sort(paths);
+
+ // For printing purposes, figure out the maximum length needed for the paths ...
+ int maxLength = 0;
+ for (Path path : paths) {
+ String str = pathString(path, namespaces);
+ maxLength = Math.max(maxLength, str.length());
+ }
+ for (Path path : paths) {
+ Location loc = locationByPath.get(path);
+ String str = pathString(path, namespaces);
+ sb.append(StringUtil.justifyLeft(str, maxLength, ' '));
+ if (loc != null) {
+ // sb.append("\t\tlocation");
+ sb.append(" @" + loc.getUuid());
+ }
+ LinkedList<Location> children = childrenByParentPath.get(path);
+ if (children != null) {
+ sb.append("\twith children: ");
+ for (int i = 0; i < children.size(); i++) {
+ Location child = children.get(i);
+ String segmentString =
pathSegmentString(child.getPath().getLastSegment(), namespaces);
+ sb.append("\n");
+ sb.append(StringUtil.justifyRight(segmentString, maxLength, '
'));
+ sb.append(" @" + child.getUuid());
+ }
+ }
+ sb.append("\n");
+ }
+ return sb.toString();
+ }
+
+ protected String pathString( Path path,
+ NamespaceRegistry registry ) {
+ return path.getString(registry, null, null);
+ }
+
+ protected String pathSegmentString( Path.Segment segment,
+ NamespaceRegistry registry ) {
+ return registry != null ? segment.getString(registry) : segment.getString();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ return getString(null);
+ }
+
+}
Modified:
trunk/extensions/dna-connector-store-jpa/src/test/java/org/jboss/dna/connector/store/jpa/JpaConnectionTest.java
===================================================================
---
trunk/extensions/dna-connector-store-jpa/src/test/java/org/jboss/dna/connector/store/jpa/JpaConnectionTest.java 2008-12-10
02:27:52 UTC (rev 678)
+++
trunk/extensions/dna-connector-store-jpa/src/test/java/org/jboss/dna/connector/store/jpa/JpaConnectionTest.java 2008-12-11
17:37:40 UTC (rev 679)
@@ -25,7 +25,7 @@
import static org.hamcrest.core.IsNull.notNullValue;
import static org.jboss.dna.graph.IsNodeWithChildren.hasChild;
import static org.jboss.dna.graph.IsNodeWithChildren.hasChildren;
-import static org.jboss.dna.graph.IsNodeWithChildren.hasNoChildren;
+import static org.jboss.dna.graph.IsNodeWithChildren.isEmpty;
import static org.jboss.dna.graph.IsNodeWithProperty.hasProperty;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.mock;
@@ -58,7 +58,7 @@
*
* @author Randall Hauch
*/
-public class JpaConnectionTest {
+public abstract class JpaConnectionTest {
private ExecutionContext context;
private JpaConnection connection;
@@ -71,6 +71,7 @@
private boolean compressData;
private Graph graph;
private String[] validLargeValues;
+ private int numPropsOnEach;
@Before
public void beforeEach() throws Exception {
@@ -78,7 +79,8 @@
model = getModel();
rootNodeUuid = UUID.randomUUID();
largeValueSize = 2 ^ 10; // 1 kilobyte
- compressData = false;
+ compressData = true;
+ numPropsOnEach = 0;
// Load in the large value ...
validLargeValues = new String[]
{IoUtil.read(getClass().getClassLoader().getResourceAsStream("LoremIpsum1.txt")),
@@ -88,11 +90,12 @@
// Connect to the database ...
Ejb3Configuration configurator = new Ejb3Configuration();
model.configure(configurator);
- configurator.setProperty("hibernate.dialect",
"org.hibernate.dialect.HSQLDialect");
- configurator.setProperty("hibernate.connection.driver_class",
"org.hsqldb.jdbcDriver");
- configurator.setProperty("hibernate.connection.username",
"sa");
- configurator.setProperty("hibernate.connection.password",
"");
- configurator.setProperty("hibernate.connection.url",
"jdbc:hsqldb:.");
+ configureDatabaseProperties(configurator);
+ // configurator.setProperty("hibernate.dialect",
"org.hibernate.dialect.HSQLDialect");
+ // configurator.setProperty("hibernate.connection.driver_class",
"org.hsqldb.jdbcDriver");
+ // configurator.setProperty("hibernate.connection.username",
"sa");
+ // configurator.setProperty("hibernate.connection.password",
"");
+ // configurator.setProperty("hibernate.connection.url",
"jdbc:hsqldb:.");
configurator.setProperty("hibernate.show_sql", "false");
configurator.setProperty("hibernate.format_sql", "true");
configurator.setProperty("hibernate.use_sql_comments",
"true");
@@ -108,6 +111,8 @@
graph = Graph.create(connection, context);
}
+ protected abstract void configureDatabaseProperties( Ejb3Configuration configurator
);
+
@After
public void afterEach() throws Exception {
try {
@@ -152,6 +157,12 @@
return context.getValueFactories().getNameFactory().create(name);
}
+ protected Property property( String name,
+ Object... values ) {
+ Name propName = name(name);
+ return context.getPropertyFactory().create(propName, values);
+ }
+
protected Path.Segment child( String name ) {
return context.getValueFactories().getPathFactory().createSegment(name);
}
@@ -192,57 +203,56 @@
Node root = graph.getNodeAt("/");
assertThat(root, is(notNullValue()));
assertThat(root, hasProperty(DnaLexicon.UUID, rootNodeUuid));
- assertThat(root, hasChild(child("a")));
+ assertThat(root.getChildren(), hasChild(child("a")));
// Now look up node A ...
Node nodeA = graph.getNodeAt("/a");
assertThat(nodeA, is(notNullValue()));
assertThat(nodeA, hasProperty("propB", "valueB"));
assertThat(nodeA, hasProperty("propC", "valueC"));
- assertThat(nodeA, hasNoChildren());
+ assertThat(nodeA.getChildren(), isEmpty());
}
@Test
public void shouldAddChildrenOnRootNode() {
-
graph.batch().set("propA").to("valueA").on("/").and()
- .create("/a").with("propB",
"valueB").and("propC", "valueC").and()
- .create("/b").with("propD",
"valueD").and("propE", "valueE")
- .execute();
+
graph.batch().set("propA").to("valueA").on("/").and().create("/a").with("propB",
"valueB").and("propC",
"valueC").and().create("/b").with("propD",
+
"valueD").and("propE",
+
"valueE").execute();
// Now look up the root node ...
Node root = graph.getNodeAt("/");
assertThat(root, is(notNullValue()));
assertThat(root, hasProperty(DnaLexicon.UUID, rootNodeUuid));
assertThat(root, hasProperty("propA", "valueA"));
- assertThat(root, hasChildren(child("a"), child("b")));
+ assertThat(root.getChildren(), hasChildren(child("a"),
child("b")));
// Now look up node A ...
Node nodeA = graph.getNodeAt("/a");
assertThat(nodeA, is(notNullValue()));
assertThat(nodeA, hasProperty("propB", "valueB"));
assertThat(nodeA, hasProperty("propC", "valueC"));
- assertThat(nodeA, hasNoChildren());
+ assertThat(nodeA.getChildren(), isEmpty());
// Now look up node B ...
Node nodeB = graph.getNodeAt("/b");
assertThat(nodeB, is(notNullValue()));
assertThat(nodeB, hasProperty("propD", "valueD"));
assertThat(nodeB, hasProperty("propE", "valueE"));
- assertThat(nodeB, hasNoChildren());
+ assertThat(nodeB.getChildren(), isEmpty());
// Get the subgraph ...
Subgraph subgraph = graph.getSubgraphOfDepth(3).at("/");
assertThat(subgraph, is(notNullValue()));
assertThat(subgraph.getNode("."), hasProperty(DnaLexicon.UUID,
rootNodeUuid));
assertThat(subgraph.getNode("."), hasProperty("propA",
"valueA"));
- assertThat(subgraph.getNode("."), hasChildren(child("a"),
child("b")));
+ assertThat(subgraph.getNode(".").getChildren(),
hasChildren(child("a"), child("b")));
assertThat(subgraph.getNode("a"), is(notNullValue()));
assertThat(subgraph.getNode("a"), hasProperty("propB",
"valueB"));
assertThat(subgraph.getNode("a"), hasProperty("propC",
"valueC"));
- assertThat(subgraph.getNode("a"), hasNoChildren());
+ assertThat(subgraph.getNode("a").getChildren(), isEmpty());
assertThat(subgraph.getNode("b"), is(notNullValue()));
assertThat(subgraph.getNode("b"), hasProperty("propD",
"valueD"));
assertThat(subgraph.getNode("b"), hasProperty("propE",
"valueE"));
- assertThat(subgraph.getNode("b"), hasNoChildren());
+ assertThat(subgraph.getNode("b").getChildren(), isEmpty());
}
@Test
@@ -258,7 +268,7 @@
for (int i = 0; i != 100; ++i) {
assertThat(nodeA, hasProperty("property" + i, "value" +
i));
}
- assertThat(nodeA, hasNoChildren());
+ assertThat(nodeA.getChildren(), isEmpty());
}
@Test
@@ -276,7 +286,7 @@
for (int i = 0; i != 10; ++i) {
assertThat(nodeA, hasProperty("property" + i, "value" +
i));
}
- assertThat(nodeA, hasNoChildren());
+ assertThat(nodeA.getChildren(), isEmpty());
// Now, remove some of the properties and add some others ...
Graph.Batch batch = graph.batch();
@@ -296,7 +306,7 @@
assertThat(nodeA, hasProperty("property" + i, "value"
+ i));
}
}
- assertThat(nodeA, hasNoChildren());
+ assertThat(nodeA.getChildren(), isEmpty());
}
@@ -319,7 +329,7 @@
}
assertThat(nodeA, hasProperty("largeProperty1", validLargeValues[0]));
assertThat(nodeA, hasProperty("largeProperty2", validLargeValues[1]));
- assertThat(nodeA, hasNoChildren());
+ assertThat(nodeA.getChildren(), isEmpty());
// Now, remove some of the properties and add some others ...
Graph.Batch batch = graph.batch();
@@ -342,7 +352,7 @@
}
assertThat(nodeA, hasProperty("largeProperty2", validLargeValues[1]));
assertThat(nodeA, hasProperty("largeProperty3", validLargeValues[2]));
- assertThat(nodeA, hasNoChildren());
+ assertThat(nodeA.getChildren(), isEmpty());
}
@@ -404,97 +414,349 @@
@Test
public void shouldCreateDeepBranch() {
- createTree("", 1, 50, "deep and narrow tree, 1x50", false);
+ createTree("", 1, 50, numPropsOnEach, "deep and narrow tree,
1x50", false, false);
}
+ @Test
+ public void shouldCreateDeepBranchUsingOneBatch() {
+ createTree("", 1, 50, numPropsOnEach, "deep and narrow tree,
1x50", true, false);
+ }
+
// @Test
// public void shouldCreateBinaryTree() {
- // createTree("", 2, 8, "binary tree, 2x8", false);
+ // createTree("", 2, 8, "binary tree, 2x8", false,false);
// }
@Test
public void shouldCreate10x2Tree() {
- createTree("", 10, 2, null, false);
+ createTree("", 10, 2, numPropsOnEach, null, false, false);
}
+ @Test
+ public void shouldCreate10x2TreeUsingOneBatch() {
+ createTree("", 10, 2, numPropsOnEach, null, true, false);
+ }
+
+ @Test
+ public void shouldCreate10x2TreeWith10PropertiesOnEachNodeUsingOneBatch() {
+ numPropsOnEach = 10;
+ createTree("", 10, 2, numPropsOnEach, null, true, false);
+ }
+
// @Test
// public void shouldCreate10x3DecimalTree() {
- // createTree("", 10, 3, null, false);
+ // createTree("", 10, 3, numPropsOnEach, null, false, true);
// }
-
+ //
// @Test
- // public void shouldCreateWideTree() {
- // createTree("", 1000, 1, "wide/flat tree, 1000x1", false);
+ // public void shouldCreate10x3DecimalTreeUsingOneBatch() {
+ // createTree("", 10, 3, numPropsOnEach, null, true, false);
// }
-
+ //
// @Test
- // public void shouldCreateVeryWideTree() {
- // createTree("", 3000, 1, "wide/flat tree, 3000x1", false);
+ // public void
shouldCreate10x3DecimalTreeWith10PropertiesOnEachNodeCompressedUsingOneBatch() {
+ // // compressData = true; the default
+ // connection = new JpaConnection("source", cachePolicy, manager, model,
rootNodeUuid, largeValueSize, compressData);
+ // graph = Graph.create(connection, context);
+ //
+ // numPropsOnEach = 10;
+ // createTree("", 10, 3, numPropsOnEach, null, true, false);
// }
-
+ //
// @Test
- // public void shouldCreate10KDecimalTree() {
- // createTree("", 10, 4, "10K decimal tree, 10x4", false);
+ // public void shouldCreate10x3DecimalTreeWith10PropertiesOnEachNodeUsingOneBatch()
{
+ // compressData = false;
+ // connection = new JpaConnection("source", cachePolicy, manager, model,
rootNodeUuid, largeValueSize, compressData);
+ // graph = Graph.create(connection, context);
+ //
+ // numPropsOnEach = 10;
+ // createTree("", 10, 3, numPropsOnEach, null, true, false);
// }
- // @Test
- // public void shouldCreate8x4Tree() {
- // createTree("", 8, 4, null, false);
- // }
+ @Test
+ public void shouldReadNodes() {
+ // Create the tree (at total of 40 nodes, plus the extra 6 added later)...
+ // /
+ // /node1
+ // /node1/node1
+ // /node1/node1/node1
+ // /node1/node1/node2
+ // /node1/node1/node3
+ // /node1/node2
+ // /node1/node2/node1
+ // /node1/node2/node2
+ // /node1/node2/node3
+ // /node1/node3
+ // /node1/node3/node1
+ // /node1/node3/node2
+ // /node1/node3/node3
+ // /node2
+ // /node2/node1
+ // /node2/node1/node1
+ // /node2/node1/node2
+ // /node2/node1/node3
+ // /node2/node2
+ // /node2/node2/node1
+ // /node2/node2/node2
+ // /node2/node2/node3
+ // /node2/node3
+ // /node2/node3/node1
+ // /node2/node3/node2
+ // /node2/node3/node3
+ // /node3
+ // /node3/node1
+ // /node3/node1/node1
+ // /node3/node1/node2
+ // /node3/node1/node3
+ // /node3/node2
+ // /node3/node2/node1
+ // /node3/node2/node2
+ // /node3/node2/node3
+ // /node3/node3
+ // /node3/node3/node1
+ // /node3/node3/node2
+ // /node3/node3/node3
+ // /secondBranch1
+ // /secondBranch1/secondBranch1
+ // /secondBranch1/secondBranch2
+ // /secondBranch2
+ // /secondBranch2/secondBranch1
+ // /secondBranch2/secondBranch2
+ numPropsOnEach = 3;
+ createTree("", 3, 3, numPropsOnEach, null, true, false);
+ assertThat(graph.getChildren().of("/node1"),
hasChildren(child("node1"), child("node2"),
child("node3")));
+ assertThat(graph.getChildren().of("/node1/node1"),
hasChildren(child("node1"), child("node2"),
child("node3")));
+ assertThat(graph.getChildren().of("/node1/node2"),
hasChildren(child("node1"), child("node2"),
child("node3")));
+ assertThat(graph.getChildren().of("/node1/node3"),
hasChildren(child("node1"), child("node2"),
child("node3")));
+ assertThat(graph.getChildren().of("/node1/node3/node1"), isEmpty());
+
+ assertThat(graph.getChildren().of("/node2"),
hasChildren(child("node1"), child("node2"),
child("node3")));
+ assertThat(graph.getChildren().of("/node2/node1"),
hasChildren(child("node1"), child("node2"),
child("node3")));
+ assertThat(graph.getChildren().of("/node2/node2"),
hasChildren(child("node1"), child("node2"),
child("node3")));
+ assertThat(graph.getChildren().of("/node2/node3"),
hasChildren(child("node1"), child("node2"),
child("node3")));
+ assertThat(graph.getChildren().of("/node2/node3/node1"), isEmpty());
+
+ assertThat(graph.getChildren().of("/node3"),
hasChildren(child("node1"), child("node2"),
child("node3")));
+ assertThat(graph.getChildren().of("/node3/node1"),
hasChildren(child("node1"), child("node2"),
child("node3")));
+ assertThat(graph.getChildren().of("/node3/node2"),
hasChildren(child("node1"), child("node2"),
child("node3")));
+ assertThat(graph.getChildren().of("/node3/node3"),
hasChildren(child("node1"), child("node2"),
child("node3")));
+ assertThat(graph.getChildren().of("/node3/node3/node1"), isEmpty());
+
+ Subgraph subgraph = graph.getSubgraphOfDepth(2).at("/node3/node2");
+ assertThat(subgraph, is(notNullValue()));
+ assertThat(subgraph.getNode(".").getChildren(),
hasChildren(child("node1"), child("node2"),
child("node3")));
+ assertThat(subgraph.getNode("."), hasProperty("property1",
"The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("."), hasProperty("property2",
"The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("."), hasProperty("property3",
"The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node1").getChildren(), isEmpty());
+ assertThat(subgraph.getNode("node1"),
hasProperty("property1", "The quick brown fox jumped over the moon. What?
"));
+ assertThat(subgraph.getNode("node1"),
hasProperty("property2", "The quick brown fox jumped over the moon. What?
"));
+ assertThat(subgraph.getNode("node1"),
hasProperty("property3", "The quick brown fox jumped over the moon. What?
"));
+ assertThat(subgraph.getNode("node2").getChildren(), isEmpty());
+ assertThat(subgraph.getNode("node2"),
hasProperty("property1", "The quick brown fox jumped over the moon. What?
"));
+ assertThat(subgraph.getNode("node2"),
hasProperty("property2", "The quick brown fox jumped over the moon. What?
"));
+ assertThat(subgraph.getNode("node2"),
hasProperty("property3", "The quick brown fox jumped over the moon. What?
"));
+ assertThat(subgraph.getNode("node3").getChildren(), isEmpty());
+ assertThat(subgraph.getNode("node3"),
hasProperty("property1", "The quick brown fox jumped over the moon. What?
"));
+ assertThat(subgraph.getNode("node3"),
hasProperty("property2", "The quick brown fox jumped over the moon. What?
"));
+ assertThat(subgraph.getNode("node3"),
hasProperty("property3", "The quick brown fox jumped over the moon. What?
"));
+
+ subgraph = graph.getSubgraphOfDepth(2).at("/node3");
+ assertThat(subgraph, is(notNullValue()));
+ assertThat(subgraph.getNode(".").getChildren(),
hasChildren(child("node1"), child("node2"),
child("node3")));
+ assertThat(subgraph.getNode("."), hasProperty("property1",
"The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("."), hasProperty("property2",
"The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("."), hasProperty("property3",
"The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node1").getChildren(), isEmpty());
+ assertThat(subgraph.getNode("node1"),
hasProperty("property1", "The quick brown fox jumped over the moon. What?
"));
+ assertThat(subgraph.getNode("node1"),
hasProperty("property2", "The quick brown fox jumped over the moon. What?
"));
+ assertThat(subgraph.getNode("node1"),
hasProperty("property3", "The quick brown fox jumped over the moon. What?
"));
+ assertThat(subgraph.getNode("node2").getChildren(), isEmpty());
+ assertThat(subgraph.getNode("node2"),
hasProperty("property1", "The quick brown fox jumped over the moon. What?
"));
+ assertThat(subgraph.getNode("node2"),
hasProperty("property2", "The quick brown fox jumped over the moon. What?
"));
+ assertThat(subgraph.getNode("node2"),
hasProperty("property3", "The quick brown fox jumped over the moon. What?
"));
+ assertThat(subgraph.getNode("node3").getChildren(), isEmpty());
+ assertThat(subgraph.getNode("node3"),
hasProperty("property1", "The quick brown fox jumped over the moon. What?
"));
+ assertThat(subgraph.getNode("node3"),
hasProperty("property2", "The quick brown fox jumped over the moon. What?
"));
+ assertThat(subgraph.getNode("node3"),
hasProperty("property3", "The quick brown fox jumped over the moon. What?
"));
+ }
+
+ @Test
+ public void shouldDeleteNodes() {
+ // Create the tree (at total of 40 nodes, plus the extra 6 added later)...
+ // /
+ // /node1
+ // /node1/node1
+ // /node1/node1/node1
+ // /node1/node1/node2
+ // /node1/node1/node3
+ // /node1/node2
+ // /node1/node2/node1
+ // /node1/node2/node2
+ // /node1/node2/node3
+ // /node1/node3
+ // /node1/node3/node1
+ // /node1/node3/node2
+ // /node1/node3/node3
+ // /node2
+ // /node2/node1
+ // /node2/node1/node1
+ // /node2/node1/node2
+ // /node2/node1/node3
+ // /node2/node2
+ // /node2/node2/node1
+ // /node2/node2/node2
+ // /node2/node2/node3
+ // /node2/node3
+ // /node2/node3/node1
+ // /node2/node3/node2
+ // /node2/node3/node3
+ // /node3
+ // /node3/node1
+ // /node3/node1/node1
+ // /node3/node1/node2
+ // /node3/node1/node3
+ // /node3/node2
+ // /node3/node2/node1
+ // /node3/node2/node2
+ // /node3/node2/node3
+ // /node3/node3
+ // /node3/node3/node1
+ // /node3/node3/node2
+ // /node3/node3/node3
+ // /secondBranch1
+ // /secondBranch1/secondBranch1
+ // /secondBranch1/secondBranch2
+ // /secondBranch2
+ // /secondBranch2/secondBranch1
+ // /secondBranch2/secondBranch2
+
+ numPropsOnEach = 3;
+ createTree("", 3, 3, numPropsOnEach, null, true, false);
+
+ // Delete two branches ...
+ graph.delete("/node2/node2").and().delete("/node3/node1");
+
+ assertThat(graph.getChildren().of("/node1"),
hasChildren(child("node1"), child("node2"),
child("node3")));
+ assertThat(graph.getChildren().of("/node1/node1"),
hasChildren(child("node1"), child("node2"),
child("node3")));
+ assertThat(graph.getChildren().of("/node1/node2"),
hasChildren(child("node1"), child("node2"),
child("node3")));
+ assertThat(graph.getChildren().of("/node1/node3"),
hasChildren(child("node1"), child("node2"),
child("node3")));
+ assertThat(graph.getChildren().of("/node1/node3/node1"),
hasChildren());
+
+ assertThat(graph.getChildren().of("/node2"),
hasChildren(child("node1"), child("node3")));
+ assertThat(graph.getChildren().of("/node2/node1"),
hasChildren(child("node1"), child("node2"),
child("node3")));
+ assertThat(graph.getChildren().of("/node2/node3"),
hasChildren(child("node1"), child("node2"),
child("node3")));
+ assertThat(graph.getChildren().of("/node2/node3/node1"),
hasChildren());
+
+ assertThat(graph.getChildren().of("/node3"),
hasChildren(child("node2"), child("node3")));
+ assertThat(graph.getChildren().of("/node3/node2"),
hasChildren(child("node1"), child("node2"),
child("node3")));
+ assertThat(graph.getChildren().of("/node3/node3"),
hasChildren(child("node1"), child("node2"),
child("node3")));
+ assertThat(graph.getChildren().of("/node3/node3/node1"),
hasChildren());
+
+ Subgraph subgraph = graph.getSubgraphOfDepth(3).at("/");
+ assertThat(subgraph, is(notNullValue()));
+ assertThat(subgraph.getNode(".").getChildren(),
hasChildren(child("node1"), child("node3")));
+ assertThat(subgraph.getNode("node1").getChildren(),
hasChildren(child("node1"), child("node2"),
child("node3")));
+ assertThat(subgraph.getNode("node1"),
hasProperty("property1", "The quick brown fox jumped over the moon. What?
"));
+ assertThat(subgraph.getNode("node1"),
hasProperty("property2", "The quick brown fox jumped over the moon. What?
"));
+ assertThat(subgraph.getNode("node1"),
hasProperty("property3", "The quick brown fox jumped over the moon. What?
"));
+ assertThat(subgraph.getNode("node2").getChildren(),
hasChildren(child("node1"), child("node3")));
+ assertThat(subgraph.getNode("node2"),
hasProperty("property1", "The quick brown fox jumped over the moon. What?
"));
+ assertThat(subgraph.getNode("node2"),
hasProperty("property2", "The quick brown fox jumped over the moon. What?
"));
+ assertThat(subgraph.getNode("node2"),
hasProperty("property3", "The quick brown fox jumped over the moon. What?
"));
+ assertThat(subgraph.getNode("node3").getChildren(),
hasChildren(child("node2"), child("node3")));
+ assertThat(subgraph.getNode("node3"),
hasProperty("property1", "The quick brown fox jumped over the moon. What?
"));
+ assertThat(subgraph.getNode("node3"),
hasProperty("property2", "The quick brown fox jumped over the moon. What?
"));
+ assertThat(subgraph.getNode("node3"),
hasProperty("property3", "The quick brown fox jumped over the moon. What?
"));
+
+ subgraph = graph.getSubgraphOfDepth(2).at("/node3");
+ assertThat(subgraph, is(notNullValue()));
+ assertThat(subgraph.getNode(".").getChildren(),
hasChildren(child("node2"), child("node3")));
+ assertThat(subgraph.getNode("."), hasProperty("property1",
"The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("."), hasProperty("property2",
"The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("."), hasProperty("property3",
"The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node2").getChildren(), isEmpty());
+ assertThat(subgraph.getNode("node2"),
hasProperty("property1", "The quick brown fox jumped over the moon. What?
"));
+ assertThat(subgraph.getNode("node2"),
hasProperty("property2", "The quick brown fox jumped over the moon. What?
"));
+ assertThat(subgraph.getNode("node2"),
hasProperty("property3", "The quick brown fox jumped over the moon. What?
"));
+ assertThat(subgraph.getNode("node3").getChildren(), isEmpty());
+ assertThat(subgraph.getNode("node3"),
hasProperty("property1", "The quick brown fox jumped over the moon. What?
"));
+ assertThat(subgraph.getNode("node3"),
hasProperty("property2", "The quick brown fox jumped over the moon. What?
"));
+ assertThat(subgraph.getNode("node3"),
hasProperty("property3", "The quick brown fox jumped over the moon. What?
"));
+ }
+
protected int createTree( String initialPath,
int numberPerDepth,
int depth,
+ int numProps,
String description,
- boolean oneBatch ) {
- int totalNumber = numberNodesInTree(numberPerDepth, depth) - 1; // this method
doesn't create the root
- if (description == null) description = "" + numberPerDepth +
"x" + depth + " tree";
- boolean printIntermediate = totalNumber > 500;
+ boolean oneBatch,
+ boolean printIntermediate ) {
+ long totalNumber = numberNodesInTree(numberPerDepth, depth) - 1; // this method
doesn't create the root
+ if (description == null) description = "" + numberPerDepth +
"x" + depth + " tree with " + numProps
+ + " properties per node" +
(compressData ? " (compressed)" : "");
System.out.println(description + " (" + totalNumber + "
nodes):");
- int totalNumberCreated = 0;
+ long totalNumberCreated = 0;
+ String batchStr = "batch ";
Graph.Batch batch = oneBatch ? graph.batch() : null;
Stopwatch sw = new Stopwatch();
if (batch != null) {
- totalNumberCreated += createChildren(batch, initialPath, "node",
numberPerDepth, depth, printIntermediate);
+ totalNumberCreated += createChildren(batch, initialPath, "node",
numberPerDepth, numProps, depth, printIntermediate);
sw.start();
batch.execute();
} else {
+ batchStr = "";
sw.start();
- totalNumberCreated += createChildren(null, initialPath, "node",
numberPerDepth, depth, printIntermediate);
+ totalNumberCreated += createChildren(null, initialPath, "node",
numberPerDepth, numProps, depth, printIntermediate);
}
sw.stop();
- long totalDurationInMillis =
TimeUnit.NANOSECONDS.toMillis(sw.getTotalDuration().longValue());
- long avgDurationInMillis = totalDurationInMillis / totalNumber;
- System.out.println(" Total = " + sw.getTotalDuration() + ";
avg = " + avgDurationInMillis + " ms");
+ long totalDurationInMicroseconds =
TimeUnit.NANOSECONDS.toMicros(sw.getTotalDuration().longValue());
+ long avgDuration = totalDurationInMicroseconds / totalNumber / 1000L;
+ String units = " millisecond(s)";
+ if (avgDuration == 0L) {
+ avgDuration = totalDurationInMicroseconds / totalNumber;
+ units = " microsecond(s)";
+ }
+ System.out.println(" Total = " + sw.getTotalDuration() + ";
avg = " + avgDuration + units);
// Perform second batch ...
batch = graph.batch();
- totalNumberCreated += createChildren(batch, initialPath,
"secondBranch", 2, 2, printIntermediate);
+ totalNumberCreated += createChildren(batch, initialPath,
"secondBranch", 2, numProps, 2, printIntermediate);
sw = new Stopwatch();
sw.start();
batch.execute();
sw.stop();
- System.out.println(" Final batch total = " + sw.getTotalDuration()
+ "; avg = " + avgDurationInMillis + " ms");
+ totalDurationInMicroseconds =
TimeUnit.NANOSECONDS.toMicros(sw.getTotalDuration().longValue());
+ avgDuration = totalDurationInMicroseconds / totalNumber / 1000L;
+ units = " millisecond(s)";
+ if (avgDuration == 0L) {
+ avgDuration = totalDurationInMicroseconds / totalNumber;
+ units = " microsecond(s)";
+ }
+ System.out.println(" Final " + batchStr + "total = " +
sw.getTotalDuration() + "; avg = " + avgDuration + units);
assertThat(totalNumberCreated, is(totalNumber + numberNodesInTree(2, 2) - 1));
- return totalNumberCreated;
+ return (int)totalNumberCreated;
}
protected int createChildren( Graph.Batch useBatch,
String parentPath,
String nodePrefix,
int number,
+ int numProps,
int depthRemaining,
boolean printIntermediateStatus ) {
int numberCreated = 0;
Graph.Batch batch = useBatch;
if (batch == null) batch = graph.batch();
for (int i = 0; i != number; ++i) {
- String path = parentPath + "/" + nodePrefix + i;
+ String path = parentPath + "/" + nodePrefix + (i + 1);
Graph.Create<Graph.Batch> create = batch.create(path);
- String value = "the quick brown fox jumped over the moon. What? ";
- for (int j = 0; j != 10; ++j) {
- // value = value + value;
- create = create.with("property" + j, value);
+ String originalValue = "The quick brown fox jumped over the moon. What?
";
+ String value = originalValue;
+ for (int j = 0; j != numProps; ++j) {
+ // value = value + originalValue;
+ create = create.with("property" + (j + 1), value);
}
create.and();
}
@@ -507,8 +769,8 @@
}
if (depthRemaining > 1) {
for (int i = 0; i != number; ++i) {
- String path = parentPath + "/" + nodePrefix + i;
- numberCreated += createChildren(useBatch, path, nodePrefix, number,
depthRemaining - 1, false);
+ String path = parentPath + "/" + nodePrefix + (i + 1);
+ numberCreated += createChildren(useBatch, path, nodePrefix, number,
numProps, depthRemaining - 1, false);
if (printIntermediateStatus) {
System.out.println(" total created ... " +
numberCreated);
}
Added:
trunk/extensions/dna-connector-store-jpa/src/test/java/org/jboss/dna/connector/store/jpa/JpaConnectionUsingHsqldbTest.java
===================================================================
---
trunk/extensions/dna-connector-store-jpa/src/test/java/org/jboss/dna/connector/store/jpa/JpaConnectionUsingHsqldbTest.java
(rev 0)
+++
trunk/extensions/dna-connector-store-jpa/src/test/java/org/jboss/dna/connector/store/jpa/JpaConnectionUsingHsqldbTest.java 2008-12-11
17:37:40 UTC (rev 679)
@@ -0,0 +1,45 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * 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.
+ *
+ * This software 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.store.jpa;
+
+import org.hibernate.ejb.Ejb3Configuration;
+
+/**
+ * @author Randall Hauch
+ */
+public class JpaConnectionUsingHsqldbTest extends JpaConnectionTest {
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.connector.store.jpa.JpaConnectionTest#configureDatabaseProperties(org.hibernate.ejb.Ejb3Configuration)
+ */
+ @Override
+ protected void configureDatabaseProperties( Ejb3Configuration configurator ) {
+ configurator.setProperty("hibernate.dialect",
"org.hibernate.dialect.HSQLDialect");
+ configurator.setProperty("hibernate.connection.driver_class",
"org.hsqldb.jdbcDriver");
+ configurator.setProperty("hibernate.connection.username",
"sa");
+ configurator.setProperty("hibernate.connection.password",
"");
+ configurator.setProperty("hibernate.connection.url",
"jdbc:hsqldb:.");
+ }
+
+}
Modified:
trunk/extensions/dna-connector-store-jpa/src/test/java/org/jboss/dna/connector/store/jpa/models/basic/SubgraphQueryTest.java
===================================================================
---
trunk/extensions/dna-connector-store-jpa/src/test/java/org/jboss/dna/connector/store/jpa/models/basic/SubgraphQueryTest.java 2008-12-10
02:27:52 UTC (rev 678)
+++
trunk/extensions/dna-connector-store-jpa/src/test/java/org/jboss/dna/connector/store/jpa/models/basic/SubgraphQueryTest.java 2008-12-11
17:37:40 UTC (rev 679)
@@ -275,7 +275,7 @@
Path path = path("/a/a1");
UUID uuid = uuidByPath.get(path);
query = SubgraphQuery.create(context, manager, uuid, path, Integer.MAX_VALUE);
- locations = query.getNodeLocations(true);
+ locations = query.getNodeLocations(true, true);
verifyNextLocationIs("/a/a1");
verifyNextLocationIs("/a/a1/a1");
verifyNextLocationIs("/a/a1/a2");
@@ -289,7 +289,7 @@
Path path = path("/a/a2");
UUID uuid = uuidByPath.get(path);
query = SubgraphQuery.create(context, manager, uuid, path, Integer.MAX_VALUE);
- locations = query.getNodeLocations(true);
+ locations = query.getNodeLocations(true, true);
verifyNextLocationIs("/a/a2");
verifyNextLocationIs("/a/a2/a1");
verifyNextLocationIs("/a/a2/a2");
@@ -308,7 +308,7 @@
Path path = path("/a");
UUID uuid = uuidByPath.get(path);
query = SubgraphQuery.create(context, manager, uuid, path, Integer.MAX_VALUE);
- locations = query.getNodeLocations(true);
+ locations = query.getNodeLocations(true, true);
verifyNextLocationIs("/a");
verifyNextLocationIs("/a/a1");
verifyNextLocationIs("/a/a2");
@@ -332,7 +332,7 @@
Path path = path("/a");
UUID uuid = uuidByPath.get(path);
query = SubgraphQuery.create(context, manager, uuid, path, 4);
- locations = query.getNodeLocations(true);
+ locations = query.getNodeLocations(true, true);
verifyNextLocationIs("/a");
verifyNextLocationIs("/a/a1");
verifyNextLocationIs("/a/a2");
@@ -345,19 +345,50 @@
verifyNextLocationIs("/a/a2/a4");
verifyNextLocationIs("/a/a2/a1/a1");
verifyNextLocationIs("/a/a2/a1/a2");
+ verifyNextLocationIs("/a/a2/a1/a1/a1");
+ verifyNextLocationIs("/a/a2/a1/a1/a2");
verifyNoMoreLocations();
+
+ locations = query.getNodeLocations(true, false);
+ verifyNextLocationIs("/a");
+ verifyNextLocationIs("/a/a1");
+ verifyNextLocationIs("/a/a2");
+ verifyNextLocationIs("/a/a1/a1");
+ verifyNextLocationIs("/a/a1/a2");
+ verifyNextLocationIs("/a/a1/a3");
+ verifyNextLocationIs("/a/a2/a1");
+ verifyNextLocationIs("/a/a2/a2");
+ verifyNextLocationIs("/a/a2/a3");
+ verifyNextLocationIs("/a/a2/a4");
+ verifyNextLocationIs("/a/a2/a1/a1");
+ verifyNextLocationIs("/a/a2/a1/a2");
+ verifyNoMoreLocations();
query.close();
query = SubgraphQuery.create(context, manager, uuid, path, 2);
- locations = query.getNodeLocations(true);
+ locations = query.getNodeLocations(true, true);
verifyNextLocationIs("/a");
verifyNextLocationIs("/a/a1");
verifyNextLocationIs("/a/a2");
+ verifyNextLocationIs("/a/a1/a1");
+ verifyNextLocationIs("/a/a1/a2");
+ verifyNextLocationIs("/a/a1/a3");
+ verifyNextLocationIs("/a/a2/a1");
+ verifyNextLocationIs("/a/a2/a2");
+ verifyNextLocationIs("/a/a2/a3");
+ verifyNextLocationIs("/a/a2/a4");
verifyNoMoreLocations();
+
+ locations = query.getNodeLocations(true, false);
+ verifyNextLocationIs("/a");
+ verifyNextLocationIs("/a/a1");
+ verifyNextLocationIs("/a/a2");
+ verifyNoMoreLocations();
+
query.close();
query = SubgraphQuery.create(context, manager, uuid, path, 3);
- locations = query.getNodeLocations(true);
+ locations = query.getNodeLocations(true, false);
verifyNextLocationIs("/a");
verifyNextLocationIs("/a/a1");
verifyNextLocationIs("/a/a2");
@@ -369,6 +400,21 @@
verifyNextLocationIs("/a/a2/a3");
verifyNextLocationIs("/a/a2/a4");
verifyNoMoreLocations();
+
+ locations = query.getNodeLocations(true, true);
+ verifyNextLocationIs("/a");
+ verifyNextLocationIs("/a/a1");
+ verifyNextLocationIs("/a/a2");
+ verifyNextLocationIs("/a/a1/a1");
+ verifyNextLocationIs("/a/a1/a2");
+ verifyNextLocationIs("/a/a1/a3");
+ verifyNextLocationIs("/a/a2/a1");
+ verifyNextLocationIs("/a/a2/a2");
+ verifyNextLocationIs("/a/a2/a3");
+ verifyNextLocationIs("/a/a2/a4");
+ verifyNextLocationIs("/a/a2/a1/a1");
+ verifyNextLocationIs("/a/a2/a1/a2");
+ verifyNoMoreLocations();
query.close();
}
@@ -388,7 +434,7 @@
UUID uuid = uuidByPath.get(path);
query = SubgraphQuery.create(context, manager, uuid, path, Integer.MAX_VALUE);
- locations = query.getNodeLocations(true);
+ locations = query.getNodeLocations(true, true);
verifyNextLocationIs("/a/a1");
verifyNextLocationIs("/a/a1/a1");
verifyNextLocationIs("/a/a1/a2");
@@ -411,7 +457,7 @@
path = path("/a");
uuid = uuidByPath.get(path);
query = SubgraphQuery.create(context, manager, uuid, path, 4);
- locations = query.getNodeLocations(true);
+ locations = query.getNodeLocations(true, true);
verifyNextLocationIs("/a");
verifyNextLocationIs("/a/a2");
verifyNextLocationIs("/a/a2/a1");
@@ -420,7 +466,20 @@
verifyNextLocationIs("/a/a2/a4");
verifyNextLocationIs("/a/a2/a1/a1");
verifyNextLocationIs("/a/a2/a1/a2");
+ verifyNextLocationIs("/a/a2/a1/a1/a1");
+ verifyNextLocationIs("/a/a2/a1/a1/a2");
verifyNoMoreLocations();
+
+ locations = query.getNodeLocations(true, false);
+ verifyNextLocationIs("/a");
+ verifyNextLocationIs("/a/a2");
+ verifyNextLocationIs("/a/a2/a1");
+ verifyNextLocationIs("/a/a2/a2");
+ verifyNextLocationIs("/a/a2/a3");
+ verifyNextLocationIs("/a/a2/a4");
+ verifyNextLocationIs("/a/a2/a1/a1");
+ verifyNextLocationIs("/a/a2/a1/a2");
+ verifyNoMoreLocations();
query.close();
// Verify that all the nodes with large values do indeed have them ...
Added:
trunk/extensions/dna-connector-store-jpa/src/test/java/org/jboss/dna/connector/store/jpa/util/RequestProcessorCacheTest.java
===================================================================
---
trunk/extensions/dna-connector-store-jpa/src/test/java/org/jboss/dna/connector/store/jpa/util/RequestProcessorCacheTest.java
(rev 0)
+++
trunk/extensions/dna-connector-store-jpa/src/test/java/org/jboss/dna/connector/store/jpa/util/RequestProcessorCacheTest.java 2008-12-11
17:37:40 UTC (rev 679)
@@ -0,0 +1,422 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * 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.
+ *
+ * This software 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.store.jpa.util;
+
+import static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.IsNull.nullValue;
+import static org.hamcrest.core.IsSame.sameInstance;
+import static org.junit.Assert.assertThat;
+import static org.junit.matchers.JUnitMatchers.hasItems;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.UUID;
+import org.jboss.dna.graph.BasicExecutionContext;
+import org.jboss.dna.graph.ExecutionContext;
+import org.jboss.dna.graph.Location;
+import org.jboss.dna.graph.properties.Name;
+import org.jboss.dna.graph.properties.NameFactory;
+import org.jboss.dna.graph.properties.NamespaceRegistry;
+import org.jboss.dna.graph.properties.Path;
+import org.jboss.dna.graph.properties.PathFactory;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * @author Randall Hauch
+ */
+public class RequestProcessorCacheTest {
+
+ private RequestProcessorCache cache;
+ private PathFactory pathFactory;
+ private NameFactory nameFactory;
+ private NamespaceRegistry namespaces;
+ private Location location;
+ private Location[] children;
+ private LinkedList<Location> childrenList;
+ private Location location2;
+ private Location[] children2;
+ private LinkedList<Location> childrenList2;
+
+ @Before
+ public void beforeEach() {
+ ExecutionContext context = new BasicExecutionContext();
+ pathFactory = context.getValueFactories().getPathFactory();
+ nameFactory = context.getValueFactories().getNameFactory();
+ namespaces = context.getNamespaceRegistry();
+ cache = new RequestProcessorCache(pathFactory);
+
+ Path parent = pathFactory.create("/a/b/c");
+ location = new Location(parent, UUID.randomUUID());
+ children = new Location[] {new Location(pathFactory.create(parent,
"d1"), UUID.randomUUID()),
+ new Location(pathFactory.create(parent, "d2"), UUID.randomUUID()),
+ new Location(pathFactory.create(parent, "d3"), UUID.randomUUID()),
+ new Location(pathFactory.create(parent, "d4"), UUID.randomUUID()),
+ new Location(pathFactory.create(parent, name("e"), 1),
UUID.randomUUID()),
+ new Location(pathFactory.create(parent, name("e"), 2),
UUID.randomUUID()),
+ new Location(pathFactory.create(parent, name("e"), 3),
UUID.randomUUID()),
+ new Location(pathFactory.create(parent, name("e"), 4),
UUID.randomUUID())};
+ childrenList = new LinkedList<Location>();
+ for (Location loc : children) {
+ childrenList.add(loc);
+ }
+
+ parent = pathFactory.create("/a/b/c/e[2]");
+ location2 = new Location(parent, children[5].getUuid());
+ children2 = new Location[] {new Location(pathFactory.create(parent,
"f1"), UUID.randomUUID()),
+ new Location(pathFactory.create(parent, "f2"), UUID.randomUUID()),
+ new Location(pathFactory.create(parent, "f3"), UUID.randomUUID()),
+ new Location(pathFactory.create(parent, "f4"), UUID.randomUUID()),
+ new Location(pathFactory.create(parent, name("g"), 1),
UUID.randomUUID()),
+ new Location(pathFactory.create(parent, name("g"), 2),
UUID.randomUUID()),
+ new Location(pathFactory.create(parent, name("g"), 3),
UUID.randomUUID()),
+ new Location(pathFactory.create(parent, name("g"), 4),
UUID.randomUUID())};
+ childrenList2 = new LinkedList<Location>();
+ for (Location loc : children2) {
+ childrenList2.add(loc);
+ }
+ }
+
+ protected Path path( String name ) {
+ return pathFactory.create(name);
+ }
+
+ protected Name name( String name ) {
+ return nameFactory.create(name);
+ }
+
+ @Test
+ public void shouldNotFindLocationForPathWhenEmpty() {
+ assertThat(cache.getLocationFor(location.getPath()), is(nullValue()));
+ }
+
+ @Test
+ public void shouldNotFindLocationForNullPath() {
+ assertThat(cache.getLocationFor(null), is(nullValue()));
+ }
+
+ @Test
+ public void shouldFindLocationForPathAfterAdding() {
+ assertThat(cache.getLocationFor(location.getPath()), is(nullValue()));
+ cache.addNewNode(location);
+ assertThat(cache.getLocationFor(location.getPath()),
is(sameInstance(location)));
+ }
+
+ @Test
+ public void shouldNotFindChildrenForPathEvenAfterLocationForSamePathIsAdded() {
+ cache.addNewNode(location);
+ assertThat(cache.getLocationFor(location.getPath()),
is(sameInstance(location)));
+ assertThat(cache.getAllChildren(location.getPath()), is(nullValue()));
+ }
+
+ @Test
+ public void shouldNotFindChildrenForPathWhenEmpty() {
+ assertThat(cache.getAllChildren(location.getPath()), is(nullValue()));
+ }
+
+ @Test
+ public void shouldNotFindChildrenForNullPath() {
+ assertThat(cache.getAllChildren(null), is(nullValue()));
+ }
+
+ @Test
+ public void shouldFindChildrenForPathAfterChildrenAreSet() {
+ assertThat(cache.getAllChildren(location.getPath()), is(nullValue()));
+ cache.setAllChildren(location.getPath(), childrenList);
+ assertThat(cache.getAllChildren(location.getPath()),
is(sameInstance(childrenList)));
+ }
+
+ @Test
+ public void shouldRemoveChildrenForPathIfSuppliedListIsNull() {
+ assertThat(cache.getAllChildren(location.getPath()), is(nullValue()));
+ cache.setAllChildren(location.getPath(), childrenList);
+ assertThat(cache.getAllChildren(location.getPath()),
is(sameInstance(childrenList)));
+ cache.setAllChildren(location.getPath(), null);
+ assertThat(cache.getAllChildren(location.getPath()), is(nullValue()));
+ }
+
+ @Test
+ public void shouldSetEmptyChildrenForPathIfSuppliedListIsEmpty() {
+ assertThat(cache.getAllChildren(location.getPath()), is(nullValue()));
+ LinkedList<Location> emptyList = new LinkedList<Location>();
+ cache.setAllChildren(location.getPath(), emptyList);
+ assertThat(cache.getAllChildren(location.getPath()),
is(sameInstance(emptyList)));
+ }
+
+ @Test
+ public void shouldUpdateCacheWhenNodeIsMoved() {
+ // The cache knows about the children of "/a/b/c" and
"/a/b/c/e[2]".
+ // This test moves "/a/b/c/e[2]" into "/a/b/c/d3"
+ Location oldLocation = location2;
+ Location newLocation = new
Location(pathFactory.create("/a/b/c/d3/e[1]"));
+ assertThat(oldLocation.getPath().getString(namespaces),
is("/a/b/c/e[2]"));
+ assertThat(newLocation.getPath().getString(namespaces),
is("/a/b/c/d3/e[1]"));
+ cache.addNewNode(location);
+ cache.addNewNode(location2);
+ for (Location loc : children)
+ cache.addNewNode(loc);
+ for (Location loc : children2)
+ cache.addNewNode(loc);
+ cache.addNewNode(location);
+ cache.addNewNode(location2);
+ cache.setAllChildren(location.getPath(), childrenList);
+ cache.setAllChildren(location2.getPath(), childrenList2);
+
+ // Assert the information before the move ...
+ assertThat(cache.getAllChildren(location.getPath()), hasItems(children));
+ assertThat(cache.getAllChildren(location2.getPath()), hasItems(children2));
+ assertThat(cache.getAllChildren(oldLocation.getPath()), hasItems(children2));
+ assertThat(cache.getAllChildren(newLocation.getPath()), is(nullValue()));
+ assertThat(cache.getAllChildren(children[0].getPath()), is(nullValue()));
+ assertThat(cache.getAllChildren(children[1].getPath()), is(nullValue()));
+ assertThat(cache.getAllChildren(children[2].getPath()), is(nullValue()));
+ assertThat(cache.getAllChildren(children[3].getPath()), is(nullValue()));
+ assertThat(cache.getAllChildren(children[4].getPath()), is(nullValue()));
+ assertThat(cache.getAllChildren(children[5].getPath()), hasItems(children2));
+ assertThat(cache.getAllChildren(children[6].getPath()), is(nullValue()));
+ assertThat(cache.getAllChildren(children[7].getPath()), is(nullValue()));
+ assertThat(cache.getAllChildren(children2[0].getPath()), is(nullValue()));
+ assertThat(cache.getAllChildren(children2[1].getPath()), is(nullValue()));
+ assertThat(cache.getAllChildren(children2[2].getPath()), is(nullValue()));
+ assertThat(cache.getAllChildren(children2[3].getPath()), is(nullValue()));
+ assertThat(cache.getAllChildren(children2[4].getPath()), is(nullValue()));
+ assertThat(cache.getAllChildren(children2[5].getPath()), is(nullValue()));
+ assertThat(cache.getAllChildren(children2[6].getPath()), is(nullValue()));
+ assertThat(cache.getAllChildren(children2[7].getPath()), is(nullValue()));
+ assertThat(cache.getLocationFor(location.getPath()), is(location));
+ assertThat(cache.getLocationFor(location2.getPath()), is(location2));
+ assertThat(cache.getLocationFor(oldLocation.getPath()), is(oldLocation));
+ assertThat(cache.getLocationFor(newLocation.getPath()), is(nullValue()));
+ assertThat(cache.getLocationFor(children[0].getPath()), is(children[0]));
+ assertThat(cache.getLocationFor(children[1].getPath()), is(children[1]));
+ assertThat(cache.getLocationFor(children[2].getPath()), is(children[2]));
+ assertThat(cache.getLocationFor(children[3].getPath()), is(children[3]));
+ assertThat(cache.getLocationFor(children[4].getPath()), is(children[4]));
+ assertThat(cache.getLocationFor(children[5].getPath()), is(children[5]));
+ assertThat(cache.getLocationFor(children[6].getPath()), is(children[6]));
+ assertThat(cache.getLocationFor(children[7].getPath()), is(children[7]));
+ assertThat(cache.getLocationFor(children2[0].getPath()), is(children2[0]));
+ assertThat(cache.getLocationFor(children2[1].getPath()), is(children2[1]));
+ assertThat(cache.getLocationFor(children2[2].getPath()), is(children2[2]));
+ assertThat(cache.getLocationFor(children2[3].getPath()), is(children2[3]));
+ assertThat(cache.getLocationFor(children2[4].getPath()), is(children2[4]));
+ assertThat(cache.getLocationFor(children2[5].getPath()), is(children2[5]));
+ assertThat(cache.getLocationFor(children2[6].getPath()), is(children2[6]));
+ assertThat(cache.getLocationFor(children2[7].getPath()), is(children2[7]));
+
+ System.out.println("Before:");
+ System.out.println(cache.getString(namespaces));
+
+ // Move the branch (without a known index) ...
+ assertThat(cache.moveNode(oldLocation, -1, newLocation), is(true));
+
+ System.out.println("After moving " +
oldLocation.getPath().getString(namespaces) + " to "
+ + newLocation.getPath().getString(namespaces));
+ System.out.println(cache.getString(namespaces));
+
+ // Check the cache content, which should no longer have any content below the old
and new locations ...
+ LinkedList<Location> afterRemoval =
cache.getAllChildren(location.getPath());
+ assertThat(afterRemoval.get(0), is(children[0]));
+ assertThat(afterRemoval.get(1), is(children[1]));
+ assertThat(afterRemoval.get(2), is(children[2]));
+ assertThat(afterRemoval.get(3), is(children[3]));
+ assertThat(afterRemoval.get(4), is(children[4]));
+ assertThat(afterRemoval.get(5),
is(children[6].with(path("/a/b/c/e[2]"))));
+ assertThat(afterRemoval.get(6),
is(children[7].with(path("/a/b/c/e[3]"))));
+
+ assertThat(cache.getAllChildren(location2.getPath()), is(nullValue())); // old
location
+ assertThat(cache.getAllChildren(oldLocation.getPath()), is(nullValue())); // old
location
+ assertThat(cache.getAllChildren(newLocation.getPath()), is(nullValue())); // all
children removed
+
+ assertThat(cache.getAllChildren(children[0].getPath()), is(nullValue()));
+ assertThat(cache.getAllChildren(children[1].getPath()), is(nullValue()));
+ assertThat(cache.getAllChildren(children[2].getPath()), is(nullValue()));
+ assertThat(cache.getAllChildren(children[3].getPath()), is(nullValue()));
+ assertThat(cache.getAllChildren(children[4].getPath()), is(nullValue()));
+ assertThat(cache.getAllChildren(children[5].getPath()), is(nullValue()));
+ assertThat(cache.getAllChildren(children[6].getPath()), is(nullValue()));
+ assertThat(cache.getAllChildren(children2[1].getPath()), is(nullValue()));
+ assertThat(cache.getAllChildren(children2[2].getPath()), is(nullValue()));
+ assertThat(cache.getAllChildren(children2[3].getPath()), is(nullValue()));
+ assertThat(cache.getAllChildren(children2[4].getPath()), is(nullValue()));
+ assertThat(cache.getAllChildren(children2[5].getPath()), is(nullValue()));
+ assertThat(cache.getAllChildren(children2[6].getPath()), is(nullValue()));
+ assertThat(cache.getAllChildren(children2[7].getPath()), is(nullValue()));
+ assertThat(cache.getLocationFor(location.getPath()), is(location));
+ // location 2 was moved, so it's been replaced by the next SNS (children 6
with SNS index of 2) ...
+ assertThat(cache.getLocationFor(location2.getPath()),
is(children[6].with(path("/a/b/c/e[2]"))));
+ assertThat(cache.getLocationFor(oldLocation.getPath()),
is(children[6].with(path("/a/b/c/e[2]"))));
+ assertThat(cache.getLocationFor(newLocation.getPath()), is(nullValue()));
+ assertThat(cache.getLocationFor(children[0].getPath()), is(children[0]));
+ assertThat(cache.getLocationFor(children[1].getPath()), is(children[1]));
+ assertThat(cache.getLocationFor(children[2].getPath()), is(children[2]));
+ assertThat(cache.getLocationFor(children[3].getPath()), is(children[3]));
+ assertThat(cache.getLocationFor(children[4].getPath()), is(children[4]));
+ // children[6] replaced children[5]'s path, and [7] replaced [6]
+ assertThat(cache.getLocationFor(children[5].getPath()),
is(children[6].with(path("/a/b/c/e[2]"))));
+ assertThat(cache.getLocationFor(children[6].getPath()),
is(children[7].with(path("/a/b/c/e[3]"))));
+ assertThat(cache.getLocationFor(children[7].getPath()), is(nullValue()));
+ // The following nodes were moved, but as children they were removed from the
cache
+ // rather than having a non-last-segment in their paths updated.
+ assertThat(cache.getLocationFor(children2[0].getPath()), is(nullValue()));
+ assertThat(cache.getLocationFor(children2[1].getPath()), is(nullValue()));
+ assertThat(cache.getLocationFor(children2[2].getPath()), is(nullValue()));
+ assertThat(cache.getLocationFor(children2[3].getPath()), is(nullValue()));
+ assertThat(cache.getLocationFor(children2[4].getPath()), is(nullValue()));
+ assertThat(cache.getLocationFor(children2[5].getPath()), is(nullValue()));
+ assertThat(cache.getLocationFor(children2[6].getPath()), is(nullValue()));
+ assertThat(cache.getLocationFor(children2[7].getPath()), is(nullValue()));
+ }
+
+ @Test
+ public void shouldUpdateCacheWhenNodeIsRemoved() {
+ // The cache knows about the children of "/a/b/c" and
"/a/b/c/e[2]".
+ // This test removes "/a/b/c/e[2]"
+ Location oldLocation = location2;
+ Location newLocation = new
Location(pathFactory.create("/a/b/c/d3/e[1]"));
+ assertThat(oldLocation.getPath().getString(namespaces),
is("/a/b/c/e[2]"));
+ assertThat(newLocation.getPath().getString(namespaces),
is("/a/b/c/d3/e[1]"));
+ cache.addNewNode(location);
+ cache.addNewNode(location2);
+ for (Location loc : children)
+ cache.addNewNode(loc);
+ for (Location loc : children2)
+ cache.addNewNode(loc);
+ cache.addNewNode(location);
+ cache.addNewNode(location2);
+ cache.setAllChildren(location.getPath(), childrenList);
+ cache.setAllChildren(location2.getPath(), childrenList2);
+
+ // Assert the information before the move ...
+ assertThat(cache.getAllChildren(location.getPath()), hasItems(children));
+ assertThat(cache.getAllChildren(location2.getPath()), hasItems(children2));
+ assertThat(cache.getAllChildren(oldLocation.getPath()), hasItems(children2));
+ assertThat(cache.getAllChildren(newLocation.getPath()), is(nullValue()));
+ assertThat(cache.getAllChildren(children[0].getPath()), is(nullValue()));
+ assertThat(cache.getAllChildren(children[1].getPath()), is(nullValue()));
+ assertThat(cache.getAllChildren(children[2].getPath()), is(nullValue()));
+ assertThat(cache.getAllChildren(children[3].getPath()), is(nullValue()));
+ assertThat(cache.getAllChildren(children[4].getPath()), is(nullValue()));
+ assertThat(cache.getAllChildren(children[5].getPath()), hasItems(children2));
+ assertThat(cache.getAllChildren(children[6].getPath()), is(nullValue()));
+ assertThat(cache.getAllChildren(children[7].getPath()), is(nullValue()));
+ assertThat(cache.getAllChildren(children2[0].getPath()), is(nullValue()));
+ assertThat(cache.getAllChildren(children2[1].getPath()), is(nullValue()));
+ assertThat(cache.getAllChildren(children2[2].getPath()), is(nullValue()));
+ assertThat(cache.getAllChildren(children2[3].getPath()), is(nullValue()));
+ assertThat(cache.getAllChildren(children2[4].getPath()), is(nullValue()));
+ assertThat(cache.getAllChildren(children2[5].getPath()), is(nullValue()));
+ assertThat(cache.getAllChildren(children2[6].getPath()), is(nullValue()));
+ assertThat(cache.getAllChildren(children2[7].getPath()), is(nullValue()));
+ assertThat(cache.getLocationFor(location.getPath()), is(location));
+ assertThat(cache.getLocationFor(location2.getPath()), is(location2));
+ assertThat(cache.getLocationFor(oldLocation.getPath()), is(oldLocation));
+ assertThat(cache.getLocationFor(newLocation.getPath()), is(nullValue()));
+ assertThat(cache.getLocationFor(children[0].getPath()), is(children[0]));
+ assertThat(cache.getLocationFor(children[1].getPath()), is(children[1]));
+ assertThat(cache.getLocationFor(children[2].getPath()), is(children[2]));
+ assertThat(cache.getLocationFor(children[3].getPath()), is(children[3]));
+ assertThat(cache.getLocationFor(children[4].getPath()), is(children[4]));
+ assertThat(cache.getLocationFor(children[5].getPath()), is(children[5]));
+ assertThat(cache.getLocationFor(children[6].getPath()), is(children[6]));
+ assertThat(cache.getLocationFor(children[7].getPath()), is(children[7]));
+ assertThat(cache.getLocationFor(children2[0].getPath()), is(children2[0]));
+ assertThat(cache.getLocationFor(children2[1].getPath()), is(children2[1]));
+ assertThat(cache.getLocationFor(children2[2].getPath()), is(children2[2]));
+ assertThat(cache.getLocationFor(children2[3].getPath()), is(children2[3]));
+ assertThat(cache.getLocationFor(children2[4].getPath()), is(children2[4]));
+ assertThat(cache.getLocationFor(children2[5].getPath()), is(children2[5]));
+ assertThat(cache.getLocationFor(children2[6].getPath()), is(children2[6]));
+ assertThat(cache.getLocationFor(children2[7].getPath()), is(children2[7]));
+
+ System.out.println("Before:");
+ System.out.println(cache.getString(namespaces));
+
+ // Create the locations that in the branch to be removed ...
+ List<Location> locationsToRemove = new LinkedList<Location>();
+ locationsToRemove.add(location2);
+ for (Location childLocation : children2) {
+ locationsToRemove.add(childLocation);
+ }
+ locationsToRemove.add(new Location(pathFactory.create(children2[6].getPath(),
"m1")));
+ locationsToRemove.add(new Location(pathFactory.create(children2[6].getPath(),
"m2")));
+ locationsToRemove.add(new Location(pathFactory.create(children2[6].getPath(),
"m3")));
+
+ // Remove the branch ...
+ assertThat(cache.removeBranch(locationsToRemove), is(true));
+
+ System.out.println("After removing " +
locationsToRemove.get(0).getString(namespaces));
+ System.out.println(cache.getString(namespaces));
+
+ // Check the cache content, which should no longer have any content below the old
and new locations ...
+ LinkedList<Location> afterRemoval =
cache.getAllChildren(location.getPath());
+ assertThat(afterRemoval.get(0), is(children[0]));
+ assertThat(afterRemoval.get(1), is(children[1]));
+ assertThat(afterRemoval.get(2), is(children[2]));
+ assertThat(afterRemoval.get(3), is(children[3]));
+ assertThat(afterRemoval.get(4), is(children[4]));
+ assertThat(afterRemoval.get(5),
is(children[6].with(path("/a/b/c/e[2]"))));
+ assertThat(afterRemoval.get(6),
is(children[7].with(path("/a/b/c/e[3]"))));
+
+ assertThat(cache.getAllChildren(location2.getPath()), is(nullValue())); // old
location
+ assertThat(cache.getAllChildren(oldLocation.getPath()), is(nullValue())); // old
location
+ assertThat(cache.getAllChildren(newLocation.getPath()), is(nullValue())); // all
children removed
+
+ assertThat(cache.getAllChildren(children[0].getPath()), is(nullValue()));
+ assertThat(cache.getAllChildren(children[1].getPath()), is(nullValue()));
+ assertThat(cache.getAllChildren(children[2].getPath()), is(nullValue()));
+ assertThat(cache.getAllChildren(children[3].getPath()), is(nullValue()));
+ assertThat(cache.getAllChildren(children[4].getPath()), is(nullValue()));
+ assertThat(cache.getAllChildren(children[5].getPath()), is(nullValue()));
+ assertThat(cache.getAllChildren(children[6].getPath()), is(nullValue()));
+ assertThat(cache.getAllChildren(children2[1].getPath()), is(nullValue()));
+ assertThat(cache.getAllChildren(children2[2].getPath()), is(nullValue()));
+ assertThat(cache.getAllChildren(children2[3].getPath()), is(nullValue()));
+ assertThat(cache.getAllChildren(children2[4].getPath()), is(nullValue()));
+ assertThat(cache.getAllChildren(children2[5].getPath()), is(nullValue()));
+ assertThat(cache.getAllChildren(children2[6].getPath()), is(nullValue()));
+ assertThat(cache.getAllChildren(children2[7].getPath()), is(nullValue()));
+ assertThat(cache.getLocationFor(location.getPath()), is(location));
+ // location 2 was moved, so it's been replaced by the next SNS (children 6
with SNS index of 2) ...
+ assertThat(cache.getLocationFor(location2.getPath()),
is(children[6].with(path("/a/b/c/e[2]"))));
+ assertThat(cache.getLocationFor(oldLocation.getPath()),
is(children[6].with(path("/a/b/c/e[2]"))));
+ assertThat(cache.getLocationFor(newLocation.getPath()), is(nullValue()));
+ assertThat(cache.getLocationFor(children[0].getPath()), is(children[0]));
+ assertThat(cache.getLocationFor(children[1].getPath()), is(children[1]));
+ assertThat(cache.getLocationFor(children[2].getPath()), is(children[2]));
+ assertThat(cache.getLocationFor(children[3].getPath()), is(children[3]));
+ assertThat(cache.getLocationFor(children[4].getPath()), is(children[4]));
+ // children[6] replaced children[5]'s path, and [7] replaced [6]
+ assertThat(cache.getLocationFor(children[5].getPath()),
is(children[6].with(path("/a/b/c/e[2]"))));
+ assertThat(cache.getLocationFor(children[6].getPath()),
is(children[7].with(path("/a/b/c/e[3]"))));
+ assertThat(cache.getLocationFor(children[7].getPath()), is(nullValue()));
+ // The following nodes were moved, but as children they were removed from the
cache
+ // rather than having a non-last-segment in their paths updated.
+ assertThat(cache.getLocationFor(children2[0].getPath()), is(nullValue()));
+ assertThat(cache.getLocationFor(children2[1].getPath()), is(nullValue()));
+ assertThat(cache.getLocationFor(children2[2].getPath()), is(nullValue()));
+ assertThat(cache.getLocationFor(children2[3].getPath()), is(nullValue()));
+ assertThat(cache.getLocationFor(children2[4].getPath()), is(nullValue()));
+ assertThat(cache.getLocationFor(children2[5].getPath()), is(nullValue()));
+ assertThat(cache.getLocationFor(children2[6].getPath()), is(nullValue()));
+ assertThat(cache.getLocationFor(children2[7].getPath()), is(nullValue()));
+ }
+}
Modified: trunk/extensions/dna-connector-store-jpa/src/test/resources/log4j.properties
===================================================================
---
trunk/extensions/dna-connector-store-jpa/src/test/resources/log4j.properties 2008-12-10
02:27:52 UTC (rev 678)
+++
trunk/extensions/dna-connector-store-jpa/src/test/resources/log4j.properties 2008-12-11
17:37:40 UTC (rev 679)
@@ -14,6 +14,7 @@
# Hibernate
log4j.logger.org.hibernate=ERROR
log4j.logger.org.hibernate.hql=ERROR
+#log4j.logger.org.hibernate.tool.hbm2ddl=DEBUG
# C3P0
log4j.logger.com.mchange=ERROR