Author: rhauch
Date: 2008-06-30 17:32:40 -0400 (Mon, 30 Jun 2008)
New Revision: 317
Added:
trunk/connectors/dna-connector-inmemory/
trunk/connectors/dna-connector-inmemory/.classpath
trunk/connectors/dna-connector-inmemory/.project
trunk/connectors/dna-connector-inmemory/pom.xml
trunk/connectors/dna-connector-inmemory/src/
trunk/connectors/dna-connector-inmemory/src/main/
trunk/connectors/dna-connector-inmemory/src/main/java/
trunk/connectors/dna-connector-inmemory/src/main/java/org/
trunk/connectors/dna-connector-inmemory/src/main/java/org/jboss/
trunk/connectors/dna-connector-inmemory/src/main/java/org/jboss/dna/
trunk/connectors/dna-connector-inmemory/src/main/java/org/jboss/dna/connector/
trunk/connectors/dna-connector-inmemory/src/main/java/org/jboss/dna/connector/inmemory/
trunk/connectors/dna-connector-inmemory/src/main/java/org/jboss/dna/connector/inmemory/InMemoryConnectorI18n.java
trunk/connectors/dna-connector-inmemory/src/main/java/org/jboss/dna/connector/inmemory/InMemoryRepository.java
trunk/connectors/dna-connector-inmemory/src/main/java/org/jboss/dna/connector/inmemory/InMemoryRepositoryConnection.java
trunk/connectors/dna-connector-inmemory/src/main/java/org/jboss/dna/connector/inmemory/InMemoryRepositorySource.java
trunk/connectors/dna-connector-inmemory/src/main/java/org/jboss/dna/connector/inmemory/Node.java
trunk/connectors/dna-connector-inmemory/src/main/resources/
trunk/connectors/dna-connector-inmemory/src/main/resources/org/
trunk/connectors/dna-connector-inmemory/src/main/resources/org/jboss/
trunk/connectors/dna-connector-inmemory/src/main/resources/org/jboss/dna/
trunk/connectors/dna-connector-inmemory/src/main/resources/org/jboss/dna/connector/
trunk/connectors/dna-connector-inmemory/src/main/resources/org/jboss/dna/connector/inmemory/
trunk/connectors/dna-connector-inmemory/src/main/resources/org/jboss/dna/connector/inmemory/InMemoryConnectorI18n.properties
trunk/connectors/dna-connector-inmemory/src/test/
trunk/connectors/dna-connector-inmemory/src/test/java/
trunk/connectors/dna-connector-inmemory/src/test/java/org/
trunk/connectors/dna-connector-inmemory/src/test/java/org/jboss/
trunk/connectors/dna-connector-inmemory/src/test/java/org/jboss/dna/
trunk/connectors/dna-connector-inmemory/src/test/java/org/jboss/dna/connector/
trunk/connectors/dna-connector-inmemory/src/test/java/org/jboss/dna/connector/inmemory/
trunk/connectors/dna-connector-inmemory/src/test/java/org/jboss/dna/connector/inmemory/InMemoryRepositoryTest.java
trunk/connectors/dna-connector-inmemory/src/test/resources/
Log:
DNA-167 Simple in-memory connector: Created a simple in-memory repository and connector
Property changes on: trunk/connectors/dna-connector-inmemory
___________________________________________________________________
Name: svn:ignore
+ target
Added: trunk/connectors/dna-connector-inmemory/.classpath
===================================================================
--- trunk/connectors/dna-connector-inmemory/.classpath (rev 0)
+++ trunk/connectors/dna-connector-inmemory/.classpath 2008-06-30 21:32:40 UTC (rev 317)
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src/main/java"/>
+ <classpathentry kind="src" path="src/main/resources"/>
+ <classpathentry kind="src" output="target/test-classes"
path="src/test/java"/>
+ <classpathentry kind="src" output="target/test-classes"
path="src/test/resources"/>
+ <classpathentry kind="con"
path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+ <classpathentry kind="con"
path="org.maven.ide.eclipse.MAVEN2_CLASSPATH_CONTAINER"/>
+ <classpathentry kind="output" path="target/classes"/>
+</classpath>
Added: trunk/connectors/dna-connector-inmemory/.project
===================================================================
--- trunk/connectors/dna-connector-inmemory/.project (rev 0)
+++ trunk/connectors/dna-connector-inmemory/.project 2008-06-30 21:32:40 UTC (rev 317)
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>dna-connector-inmemory</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.maven.ide.eclipse.maven2Builder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ <nature>org.maven.ide.eclipse.maven2Nature</nature>
+ </natures>
+</projectDescription>
Added: trunk/connectors/dna-connector-inmemory/pom.xml
===================================================================
--- trunk/connectors/dna-connector-inmemory/pom.xml (rev 0)
+++ trunk/connectors/dna-connector-inmemory/pom.xml 2008-06-30 21:32:40 UTC (rev 317)
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project
xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.jboss.dna</groupId>
+ <artifactId>dna</artifactId>
+ <version>0.2-SNAPSHOT</version>
+ <relativePath>../..</relativePath>
+ </parent>
+ <!-- The groupId and version values are inherited from parent -->
+ <artifactId>dna-connector-inmemory</artifactId>
+ <packaging>jar</packaging>
+ <name>JBoss DNA Connector to a simple in-memory repository</name>
+ <description>JBoss DNA Connector that accesses an in-memory
graph.</description>
+ <
url>http://labs.jboss.org/dna</url>
+
+ <properties>
+ <dna-version>0.2-SNAPSHOT</dna-version>
+ </properties>
+ <!--
+ Define the dependencies. Note that all version and scopes default to those
+ defined in the dependencyManagement section of the parent pom.
+ -->
+ <dependencies>
+ <!--
+ Common
+ -->
+ <dependency>
+ <groupId>org.jboss.dna</groupId>
+ <artifactId>dna-common</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.dna</groupId>
+ <artifactId>dna-spi</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.dna</groupId>
+ <artifactId>dna-common</artifactId>
+ <version>${dna-version}</version>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.dna</groupId>
+ <artifactId>dna-spi</artifactId>
+ <version>${dna-version}</version>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+ <!--
+ Testing (note the scope)
+ -->
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-all</artifactId>
+ </dependency>
+ <!--
+ Logging (require SLF4J API for compiling, but use Log4J and its SLF4J binding for
testing)
+ -->
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-log4j12</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>log4j</groupId>
+ <artifactId>log4j</artifactId>
+ </dependency>
+ <!--
+ Java Concurrency in Practice annotations
+ -->
+ <dependency>
+ <groupId>net.jcip</groupId>
+ <artifactId>jcip-annotations</artifactId>
+ </dependency>
+ </dependencies>
+ <reporting>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-report-plugin</artifactId>
+ </plugin>
+ </plugins>
+ </reporting>
+</project>
\ No newline at end of file
Added:
trunk/connectors/dna-connector-inmemory/src/main/java/org/jboss/dna/connector/inmemory/InMemoryConnectorI18n.java
===================================================================
---
trunk/connectors/dna-connector-inmemory/src/main/java/org/jboss/dna/connector/inmemory/InMemoryConnectorI18n.java
(rev 0)
+++
trunk/connectors/dna-connector-inmemory/src/main/java/org/jboss/dna/connector/inmemory/InMemoryConnectorI18n.java 2008-06-30
21:32:40 UTC (rev 317)
@@ -0,0 +1,55 @@
+/*
+ * 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.inmemory;
+
+import java.util.Locale;
+import java.util.Set;
+import org.jboss.dna.common.i18n.I18n;
+
+/**
+ * @author Randall Hauch
+ */
+public final class InMemoryConnectorI18n {
+
+ public static I18n connectorName;
+ public static I18n nodeDoesNotExist;
+
+ static {
+ try {
+ I18n.initialize(InMemoryConnectorI18n.class);
+ } catch (final Exception err) {
+ System.err.println(err);
+ }
+ }
+
+ public static Set<Locale> getLocalizationProblemLocales() {
+ return I18n.getLocalizationProblemLocales(InMemoryConnectorI18n.class);
+ }
+
+ public static Set<String> getLocalizationProblems() {
+ return I18n.getLocalizationProblems(InMemoryConnectorI18n.class);
+ }
+
+ public static Set<String> getLocalizationProblems( Locale locale ) {
+ return I18n.getLocalizationProblems(InMemoryConnectorI18n.class, locale);
+ }
+}
Added:
trunk/connectors/dna-connector-inmemory/src/main/java/org/jboss/dna/connector/inmemory/InMemoryRepository.java
===================================================================
---
trunk/connectors/dna-connector-inmemory/src/main/java/org/jboss/dna/connector/inmemory/InMemoryRepository.java
(rev 0)
+++
trunk/connectors/dna-connector-inmemory/src/main/java/org/jboss/dna/connector/inmemory/InMemoryRepository.java 2008-06-30
21:32:40 UTC (rev 317)
@@ -0,0 +1,266 @@
+/*
+ * 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.inmemory;
+
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+import net.jcip.annotations.NotThreadSafe;
+import org.jboss.dna.common.util.ArgCheck;
+import org.jboss.dna.spi.graph.Name;
+import org.jboss.dna.spi.graph.Path;
+import org.jboss.dna.spi.graph.connection.ExecutionEnvironment;
+
+/**
+ * @author Randall Hauch
+ */
+@NotThreadSafe
+public class InMemoryRepository {
+
+ protected final ReadWriteLock lock = new ReentrantReadWriteLock();
+ private final String name;
+ private final UUID rootNodeUuid;
+ private final Map<UUID, Node> nodesByUuid = new HashMap<UUID, Node>();
+
+ public InMemoryRepository( String name,
+ UUID rootNodeUUID ) {
+ ArgCheck.isNotNull(rootNodeUUID, "rootNodeUUID");
+ ArgCheck.isNotEmpty(name, "name");
+ this.name = name;
+ this.rootNodeUuid = rootNodeUUID;
+ // Create the root node ...
+ Node root = new Node(rootNodeUUID);
+ nodesByUuid.put(root.getUuid(), root);
+ }
+
+ /**
+ * @return lock
+ */
+ public ReadWriteLock getLock() {
+ return lock;
+ }
+
+ /**
+ * @return name
+ */
+ public String getName() {
+ return name;
+ }
+
+ public Node getRoot() {
+ return nodesByUuid.get(this.rootNodeUuid);
+ }
+
+ public Node getNode( UUID uuid ) {
+ assert uuid != null;
+ return nodesByUuid.get(uuid);
+ }
+
+ protected Map<UUID, Node> getNodesByUuid() {
+ return nodesByUuid;
+ }
+
+ public Node getNode( ExecutionEnvironment env,
+ String path ) {
+ assert env != null;
+ assert path != null;
+ return getNode(env.getValueFactories().getPathFactory().create(path));
+ }
+
+ /**
+ * Find a node with the given path.
+ *
+ * @param path the path to the node; may not be null
+ * @return the node with the path, or null if the node does not exist
+ */
+ public Node getNode( Path path ) {
+ assert path != null;
+ Node node = getRoot();
+ for (Path.Segment segment : path) {
+ Node desiredChild = null;
+ for (Node child : node.getChildren()) {
+ if (child == null) continue;
+ Path.Segment childName = child.getName();
+ if (childName == null) continue;
+ if (childName.equals(segment)) {
+ desiredChild = child;
+ break;
+ }
+ }
+ if (desiredChild != null) {
+ node = desiredChild;
+ } else {
+ return null;
+ }
+ }
+ return node;
+ }
+
+ protected UUID generateUuid() {
+ return UUID.randomUUID();
+ }
+
+ public void removeNode( ExecutionEnvironment env,
+ Node node ) {
+ assert env != null;
+ assert node != null;
+ assert getRoot().equals(node) != true;
+ Node parent = node.getParent();
+ assert parent != null;
+ parent.getChildren().remove(node);
+ correctSameNameSiblingIndexes(env, parent, node.getName().getName());
+ removeUuidReference(node);
+ }
+
+ protected void removeUuidReference( Node node ) {
+ nodesByUuid.remove(node.getUuid());
+ for (Node child : node.getChildren()) {
+ removeUuidReference(child);
+ }
+ }
+
+ /**
+ * Create a node at the supplied path. The parent of the new node must already
exist.
+ *
+ * @param env the environment; may not be null
+ * @param pathToNewNode the path to the new node; may not be null
+ * @return the new node (or root if the path specified the root)
+ */
+ public Node createNode( ExecutionEnvironment env,
+ String pathToNewNode ) {
+ assert env != null;
+ assert pathToNewNode != null;
+ Path path = env.getValueFactories().getPathFactory().create(pathToNewNode);
+ if (path.isRoot()) return getRoot();
+ Path parentPath = path.getAncestor();
+ Node parentNode = getNode(parentPath);
+ Name name = path.getLastSegment().getName();
+ return createNode(env, parentNode, name);
+ }
+
+ /**
+ * Create a new node with the supplied name, as a child of the supplied parent.
+ *
+ * @param env the execution environment
+ * @param parentNode the parent node; may not be null
+ * @param name the name; may not be null
+ * @return the new node
+ */
+ public Node createNode( ExecutionEnvironment env,
+ Node parentNode,
+ Name name ) {
+ assert env != null;
+ assert name != null;
+ if (parentNode == null) parentNode = getRoot();
+ Node node = new Node(generateUuid());
+ nodesByUuid.put(node.getUuid(), node);
+ node.setParent(parentNode);
+ Path.Segment newName =
env.getValueFactories().getPathFactory().createSegment(name);
+ node.setName(newName);
+ parentNode.getChildren().add(node);
+ correctSameNameSiblingIndexes(env, parentNode, name);
+ return node;
+ }
+
+ protected void correctSameNameSiblingIndexes( ExecutionEnvironment env,
+ Node parentNode,
+ Name name ) {
+ if (parentNode == null) return;
+ // Look for the highest existing index ...
+ List<Node> childrenWithSameNames = new LinkedList<Node>();
+ for (Node child : parentNode.getChildren()) {
+ if (child.getName().getName().equals(name))
childrenWithSameNames.add(child);
+ }
+ if (childrenWithSameNames.size() == 0) return;
+ if (childrenWithSameNames.size() == 1) {
+ Node childWithSameName = childrenWithSameNames.get(0);
+ Path.Segment newName =
env.getValueFactories().getPathFactory().createSegment(name, Path.NO_INDEX);
+ childWithSameName.setName(newName);
+ return;
+ }
+ int index = 1;
+ for (Node childWithSameName : childrenWithSameNames) {
+ Path.Segment segment = childWithSameName.getName();
+ if (segment.getIndex() != index) {
+ Path.Segment newName =
env.getValueFactories().getPathFactory().createSegment(name, index);
+ childWithSameName.setName(newName);
+ }
+ ++index;
+ }
+ }
+
+ /**
+ * Move the supplied node to the new parent. This method automatically removes the
node from its existing parent, and also
+ * correctly adjusts the {@link Path.Segment#getIndex() index} to be correct in the
new parent.
+ *
+ * @param env
+ * @param node the node to be moved; may not be the {@link #getRoot() root}
+ * @param newParent the new parent; may not be the {@link #getRoot() root}
+ */
+ public void moveNode( ExecutionEnvironment env,
+ Node node,
+ Node newParent ) {
+ assert env != null;
+ assert newParent != null;
+ assert node != null;
+ assert getRoot().equals(newParent) != true;
+ assert getRoot().equals(node) != true;
+ Node oldParent = node.getParent();
+ if (oldParent != null) {
+ if (oldParent.equals(newParent)) return;
+ boolean removed = oldParent.getChildren().remove(node);
+ assert removed == true;
+ node.setParent(null);
+ correctSameNameSiblingIndexes(env, oldParent, node.getName().getName());
+ }
+ node.setParent(newParent);
+ newParent.getChildren().add(node);
+ correctSameNameSiblingIndexes(env, newParent, node.getName().getName());
+ }
+
+ public int copyNode( ExecutionEnvironment env,
+ Node original,
+ Node newParent,
+ boolean recursive ) {
+ assert env != null;
+ assert original != null;
+ assert newParent != null;
+ // Get or create the new node ...
+ Node copy = createNode(env, newParent, original.getName().getName());
+
+ // Copy the properties ...
+ copy.getProperties().clear();
+ copy.getProperties().putAll(original.getProperties());
+ int numNodesCopied = 1;
+ if (recursive) {
+ // Loop over each child and call this method ...
+ for (Node child : original.getChildren()) {
+ numNodesCopied += copyNode(env, child, copy, true);
+ }
+ }
+ return numNodesCopied;
+ }
+}
Added:
trunk/connectors/dna-connector-inmemory/src/main/java/org/jboss/dna/connector/inmemory/InMemoryRepositoryConnection.java
===================================================================
---
trunk/connectors/dna-connector-inmemory/src/main/java/org/jboss/dna/connector/inmemory/InMemoryRepositoryConnection.java
(rev 0)
+++
trunk/connectors/dna-connector-inmemory/src/main/java/org/jboss/dna/connector/inmemory/InMemoryRepositoryConnection.java 2008-06-30
21:32:40 UTC (rev 317)
@@ -0,0 +1,267 @@
+/*
+ * 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.inmemory;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Lock;
+import javax.transaction.xa.XAResource;
+import org.jboss.dna.spi.cache.CachePolicy;
+import org.jboss.dna.spi.graph.InvalidPathException;
+import org.jboss.dna.spi.graph.Name;
+import org.jboss.dna.spi.graph.Path;
+import org.jboss.dna.spi.graph.Property;
+import org.jboss.dna.spi.graph.Path.Segment;
+import org.jboss.dna.spi.graph.commands.ActsAsUpdate;
+import org.jboss.dna.spi.graph.commands.ActsOnPath;
+import org.jboss.dna.spi.graph.commands.CompositeCommand;
+import org.jboss.dna.spi.graph.commands.CopyBranchCommand;
+import org.jboss.dna.spi.graph.commands.CopyNodeCommand;
+import org.jboss.dna.spi.graph.commands.CreateNodeCommand;
+import org.jboss.dna.spi.graph.commands.DeleteBranchCommand;
+import org.jboss.dna.spi.graph.commands.GetChildrenCommand;
+import org.jboss.dna.spi.graph.commands.GetPropertiesCommand;
+import org.jboss.dna.spi.graph.commands.GraphCommand;
+import org.jboss.dna.spi.graph.commands.MoveBranchCommand;
+import org.jboss.dna.spi.graph.commands.SetPropertiesCommand;
+import org.jboss.dna.spi.graph.connection.ExecutionEnvironment;
+import org.jboss.dna.spi.graph.connection.RepositoryConnection;
+import org.jboss.dna.spi.graph.connection.RepositorySourceListener;
+
+/**
+ * @author Randall Hauch
+ */
+public class InMemoryRepositoryConnection implements RepositoryConnection {
+
+ protected static final RepositorySourceListener NO_OP_LISTENER = new
RepositorySourceListener() {
+
+ /**
+ * {@inheritDoc}
+ */
+ public void notify( String sourceName,
+ Object... events ) {
+ // do nothing
+ }
+ };
+
+ private final InMemoryRepositorySource source;
+ private final InMemoryRepository content;
+ private RepositorySourceListener listener = NO_OP_LISTENER;
+
+ InMemoryRepositoryConnection( InMemoryRepositorySource source,
+ InMemoryRepository content ) {
+ assert source != null;
+ assert content != null;
+ this.source = source;
+ this.content = content;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getSourceName() {
+ return source.getName();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public CachePolicy getDefaultCachePolicy() {
+ return source.getDefaultCachePolicy();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public XAResource getXAResource() {
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean ping( long time,
+ TimeUnit unit ) {
+ this.content.getRoot();
+ return true;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setListener( RepositorySourceListener listener ) {
+ this.listener = listener != null ? listener : NO_OP_LISTENER;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void close() {
+ // do nothing
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void execute( ExecutionEnvironment env,
+ GraphCommand... commands ) {
+ // Do any commands update/write?
+ Lock lock = this.content.getLock().readLock();
+ for (GraphCommand command : commands) {
+ if (command instanceof ActsAsUpdate) {
+ lock = this.content.getLock().writeLock();
+ break;
+ }
+ }
+
+ try {
+ // Obtain the lock ...
+ lock.lock();
+ // Now execute the commands ...
+ for (GraphCommand command : commands) {
+ executeCommand(env, command);
+ }
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * @param env
+ * @param command
+ */
+ protected void executeCommand( ExecutionEnvironment env,
+ GraphCommand command ) {
+ // This node reference is available for any command that extends ActsOnPath ...
+ Node node = null;
+
+ if (command instanceof CompositeCommand) {
+ CompositeCommand theCommand = (CompositeCommand)command;
+ for (GraphCommand containedCommand : theCommand) {
+ executeCommand(env, containedCommand);
+ }
+ }
+
+ // First, process the commands that create a new node ...
+ if (command instanceof CreateNodeCommand) {
+ CreateNodeCommand theCommand = (CreateNodeCommand)command;
+ Path path = theCommand.getPath();
+ Path parent = path.getAncestor();
+ // Look up the parent node, which must exist ...
+ Node parentNode = content.getNode(parent);
+ node = content.createNode(env, parentNode, path.getLastSegment().getName());
+ // Now add the properties to the supplied node ...
+ for (Property property : theCommand.getProperties()) {
+ Name propName = property.getName();
+ if (property.size() == 0) {
+ node.getProperties().remove(propName);
+ continue;
+ }
+ node.getProperties().put(propName, property);
+ }
+ assert node != null;
+ }
+
+ // Otherwise, check whether the command is applies to a path; all the remaining
commands
+ // that do so expect the node to exist ...
+ else if (command instanceof ActsOnPath) {
+ ActsOnPath theCommand = (ActsOnPath)command;
+ Path path = theCommand.getPath();
+ // Look up the node with the supplied path ...
+ node = content.getNode(path);
+ if (node == null) throw new
InvalidPathException(InMemoryConnectorI18n.nodeDoesNotExist.text(path));
+ }
+
+ if (command instanceof GetChildrenCommand) {
+ GetChildrenCommand theCommand = (GetChildrenCommand)command;
+ assert command instanceof ActsOnPath;
+ assert node != null;
+ // Get the names of the children ...
+ List<Node> children = node.getChildren();
+ List<Segment> childSegments = new
ArrayList<Segment>(children.size());
+ for (Node child : children) {
+ childSegments.add(child.getName());
+ }
+ theCommand.setChildren(childSegments);
+
+ }
+ if (command instanceof GetPropertiesCommand) {
+ GetPropertiesCommand theCommand = (GetPropertiesCommand)command;
+ assert command instanceof ActsOnPath;
+ assert node != null;
+ for (Property property : node.getProperties().values()) {
+ theCommand.setProperty(property);
+ }
+ }
+ if (command instanceof SetPropertiesCommand) {
+ SetPropertiesCommand theCommand = (SetPropertiesCommand)command;
+ assert command instanceof ActsOnPath;
+ assert node != null;
+ // Now set (or remove) the properties to the supplied node ...
+ for (Property property : theCommand.getProperties()) {
+ Name propName = property.getName();
+ if (property.size() == 0) {
+ node.getProperties().remove(propName);
+ continue;
+ }
+ node.getProperties().put(propName, property);
+ }
+ }
+ if (command instanceof DeleteBranchCommand) {
+ assert command instanceof ActsOnPath;
+ assert node != null;
+ content.removeNode(env, node);
+ }
+ if (command instanceof CopyNodeCommand) {
+ CopyNodeCommand theCommand = (CopyNodeCommand)command;
+ boolean recursive = command instanceof CopyBranchCommand;
+ // Look up the new parent, which must exist ...
+ Path newPath = theCommand.getNewPath();
+ Node newParent = content.getNode(newPath.getAncestor());
+ if (newParent == null) {
+ throw new
InvalidPathException(InMemoryConnectorI18n.nodeDoesNotExist.text(newPath.getAncestor()));
+ }
+ content.copyNode(env, node, newParent, recursive);
+ }
+ if (command instanceof MoveBranchCommand) {
+ MoveBranchCommand theCommand = (MoveBranchCommand)command;
+ assert command instanceof ActsOnPath;
+ assert node != null;
+ // Look up the new parent, which must exist ...
+ Path newPath = theCommand.getNewPath();
+ Node newParent = content.getNode(newPath.getAncestor());
+ if (newParent == null) {
+ throw new
InvalidPathException(InMemoryConnectorI18n.nodeDoesNotExist.text(newPath.getAncestor()));
+ }
+ node.setParent(newParent);
+ }
+ }
+
+ /**
+ * @return listener
+ */
+ protected RepositorySourceListener getListener() {
+ return this.listener;
+ }
+
+}
Added:
trunk/connectors/dna-connector-inmemory/src/main/java/org/jboss/dna/connector/inmemory/InMemoryRepositorySource.java
===================================================================
---
trunk/connectors/dna-connector-inmemory/src/main/java/org/jboss/dna/connector/inmemory/InMemoryRepositorySource.java
(rev 0)
+++
trunk/connectors/dna-connector-inmemory/src/main/java/org/jboss/dna/connector/inmemory/InMemoryRepositorySource.java 2008-06-30
21:32:40 UTC (rev 317)
@@ -0,0 +1,277 @@
+/*
+ * 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.inmemory;
+
+import java.util.Collections;
+import java.util.Hashtable;
+import java.util.Set;
+import java.util.UUID;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+import javax.naming.RefAddr;
+import javax.naming.Reference;
+import javax.naming.StringRefAddr;
+import javax.naming.spi.ObjectFactory;
+import net.jcip.annotations.GuardedBy;
+import org.jboss.dna.common.util.ArgCheck;
+import org.jboss.dna.spi.cache.CachePolicy;
+import org.jboss.dna.spi.graph.connection.RepositoryConnection;
+import org.jboss.dna.spi.graph.connection.RepositorySource;
+
+/**
+ * @author Randall Hauch
+ */
+public class InMemoryRepositorySource implements RepositorySource, ObjectFactory {
+
+ /**
+ * The initial version is 1
+ */
+ private static final long serialVersionUID = 1L;
+
+ public static final String DEFAULT_UUID_PROPERTY_NAMESPACE =
"http://www.jboss.org/dna/connector/jbosscache";
+ public static final String DEFAULT_UUID_PROPERTY_NAME = "uuid";
+
+ private static final ConcurrentMap<String, InMemoryRepositorySource> sources =
new ConcurrentHashMap<String, InMemoryRepositorySource>();
+ private static final ReadWriteLock sourcesLock = new ReentrantReadWriteLock();
+
+ /**
+ * Get the names of the in-memory repository sources that are currently registered
+ *
+ * @return the unmodifiable set of names
+ */
+ public static Set<String> getSourceNames() {
+ Lock lock = sourcesLock.readLock();
+ try {
+ lock.lock();
+ return Collections.unmodifiableSet(sources.keySet());
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * Get the source with the supplied name.
+ *
+ * @param name the name
+ * @return the source, or null if there is no source with the supplied name
+ */
+ public static InMemoryRepositorySource getSource( String name ) {
+ Lock lock = sourcesLock.readLock();
+ try {
+ lock.lock();
+ return sources.get(name);
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ @GuardedBy( "sourcesLock" )
+ private String name;
+ @GuardedBy( "this" )
+ private String jndiName;
+ private final AtomicInteger retryLimit = new AtomicInteger(0);
+ private UUID rootNodeUuid = UUID.randomUUID();
+ private CachePolicy defaultCachePolicy;
+ private String configurationName;
+ private transient InMemoryRepository repository;
+
+ /**
+ * Create a repository source instance.
+ */
+ public InMemoryRepositorySource() {
+ }
+
+ /**
+ * Get the default cache policy for this source, or null if the global default cache
policy should be used
+ *
+ * @return the default cache policy, or null if this source has no explicit default
cache policy
+ */
+ public CachePolicy getDefaultCachePolicy() {
+ return defaultCachePolicy;
+ }
+
+ /**
+ * @param defaultCachePolicy Sets defaultCachePolicy to the specified value.
+ */
+ public void setDefaultCachePolicy( CachePolicy defaultCachePolicy ) {
+ this.defaultCachePolicy = defaultCachePolicy;
+ }
+
+ /**
+ * @return rootNodeUuid
+ */
+ public UUID getRootNodeUuid() {
+ return this.rootNodeUuid;
+ }
+
+ /**
+ * @param rootNodeUuid Sets rootNodeUuid to the specified value.
+ */
+ public void setRootNodeUuid( UUID rootNodeUuid ) {
+ this.rootNodeUuid = rootNodeUuid != null ? rootNodeUuid : UUID.randomUUID();
+ }
+
+ /**
+ * If you use this to set a JNDI name, this source will be bound to that name using
the default {@link InitialContext}. You
+ * can also do this manually if you have additional requirements.
+ *
+ * @param name the JNDI name
+ * @throws NamingException if there is a problem registering this object
+ * @see #getJndiName()
+ */
+ public void setJndiName( String name ) throws NamingException {
+ setJndiName(name, null);
+ }
+
+ /**
+ * Register this source in JNDI under the supplied name using the supplied context.
to set a JNDI name, this source will be
+ * bound to that name using the default {@link InitialContext}. You can also do this
manually if you have additional
+ * requirements.
+ *
+ * @param name the JNDI name, or null if this object is to no longer be registered
+ * @param context the JNDI context, or null if the {@link InitialContext} should be
used
+ * @throws NamingException if there is a problem registering this object
+ * @see #getJndiName()
+ */
+ public synchronized void setJndiName( String name,
+ Context context ) throws NamingException {
+ ArgCheck.isNotNull(name, "name");
+ if (context == null) context = new InitialContext();
+
+ // First register in JNDI under the new name ...
+ if (name != null) {
+ context.bind(name, this);
+ }
+ // Second, unregister from JNDI if there is already a name ...
+ if (jndiName != null && !jndiName.equals(name)) {
+ context.unbind(jndiName);
+ }
+ // Record the new name ...
+ this.jndiName = name;
+ }
+
+ /**
+ * Gets the JNDI name this source is bound to. Only valid if you used setJNDIName to
bind it.
+ *
+ * @return the JNDI name, or null if it is not bound in JNDI
+ * @see #setJndiName(String)
+ */
+ public synchronized String getJndiName() {
+ return jndiName;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getName() {
+ Lock lock = sourcesLock.readLock();
+ try {
+ lock.lock();
+ return this.name;
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * @param name Sets name to the specified value.
+ * @return true if the name was changed, or false if an existing instance already
exists with that name
+ */
+ public boolean setName( String name ) {
+ Lock lock = sourcesLock.writeLock();
+ try {
+ lock.lock();
+ // Determine if this name is allowed ...
+ if (sources.containsKey(name)) return false;
+
+ // Remove this object under its current name
+ if (this.name != null) {
+ sources.remove(this.name);
+ }
+ // Register this object under the new name
+ this.name = name;
+ sources.put(this.name, this);
+ return true;
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int getRetryLimit() {
+ return retryLimit.get();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setRetryLimit( int limit ) {
+ retryLimit.set(limit);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public synchronized RepositoryConnection getConnection() {
+ if (this.repository == null) {
+ repository = new InMemoryRepository(configurationName, this.rootNodeUuid);
+ }
+ return new InMemoryRepositoryConnection(this, this.repository);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Reference getReference() {
+ String className = getClass().getName();
+ String factoryClassName = className;
+ return new Reference(className, new
StringRefAddr("DnaConnectorInMemoryRepositorySource", getName()),
factoryClassName,
+ null);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Object getObjectInstance( Object obj,
+ javax.naming.Name name,
+ Context nameCtx,
+ Hashtable<?, ?> environment ) {
+ if (obj instanceof Reference) {
+ Reference ref = (Reference)obj;
+ if (ref.getClassName().equals(getClass().getName())) {
+ RefAddr addr =
ref.get("DnaConnectorInMemoryRepositorySource");
+ return InMemoryRepositorySource.getSource((String)addr.getContent());
+ }
+ }
+ return null;
+ }
+
+}
Added:
trunk/connectors/dna-connector-inmemory/src/main/java/org/jboss/dna/connector/inmemory/Node.java
===================================================================
---
trunk/connectors/dna-connector-inmemory/src/main/java/org/jboss/dna/connector/inmemory/Node.java
(rev 0)
+++
trunk/connectors/dna-connector-inmemory/src/main/java/org/jboss/dna/connector/inmemory/Node.java 2008-06-30
21:32:40 UTC (rev 317)
@@ -0,0 +1,169 @@
+/*
+ * 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.inmemory;
+
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import net.jcip.annotations.NotThreadSafe;
+import org.jboss.dna.spi.graph.Name;
+import org.jboss.dna.spi.graph.Path;
+import org.jboss.dna.spi.graph.Property;
+import org.jboss.dna.spi.graph.PropertyFactory;
+import org.jboss.dna.spi.graph.connection.ExecutionEnvironment;
+
+/**
+ * @author Randall Hauch
+ */
+@NotThreadSafe
+public class Node {
+
+ private final UUID uuid;
+ private Node parent;
+ private Path.Segment name;
+ private final Map<Name, Property> properties = new HashMap<Name,
Property>();
+ private final List<Node> children = new LinkedList<Node>();
+
+ public Node( UUID uuid ) {
+ assert uuid != null;
+ this.uuid = uuid;
+ }
+
+ /**
+ * @return uuid
+ */
+ public UUID getUuid() {
+ return uuid;
+ }
+
+ /**
+ * @return name
+ */
+ public Path.Segment getName() {
+ return name;
+ }
+
+ /**
+ * @param name Sets name to the specified value.
+ */
+ protected void setName( Path.Segment name ) {
+ this.name = name;
+ }
+
+ /**
+ * @return parent
+ */
+ public Node getParent() {
+ return parent;
+ }
+
+ /**
+ * @param parent Sets parent to the specified value.
+ */
+ protected void setParent( Node parent ) {
+ this.parent = parent;
+ }
+
+ /**
+ * @return children
+ */
+ protected List<Node> getChildren() {
+ return children;
+ }
+
+ /**
+ * @return properties
+ */
+ protected Map<Name, Property> getProperties() {
+ return properties;
+ }
+
+ public Node setProperty( Property property ) {
+ if (property != null) {
+ this.properties.put(property.getName(), property);
+ }
+ return this;
+ }
+
+ public Node setProperty( ExecutionEnvironment env,
+ String name,
+ Object... values ) {
+ PropertyFactory propertyFactory = env.getPropertyFactory();
+ Name propertyName = env.getValueFactories().getNameFactory().create(name);
+ return setProperty(propertyFactory.create(propertyName, values));
+ }
+
+ public Property getProperty( ExecutionEnvironment env,
+ String name ) {
+ Name propertyName = env.getValueFactories().getNameFactory().create(name);
+ return getProperty(propertyName);
+ }
+
+ public Property getProperty( Name name ) {
+ return this.properties.get(name);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ return uuid.hashCode();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals( Object obj ) {
+ if (obj == this) return true;
+ if (obj instanceof Node) {
+ Node that = (Node)obj;
+ if (!this.getUuid().equals(that.getUuid())) return false;
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ if (this.name == null) {
+ sb.append("");
+ } else {
+ sb.append(this.name);
+ }
+ sb.append(" (").append(uuid).append(")");
+ return sb.toString();
+ }
+}
Added:
trunk/connectors/dna-connector-inmemory/src/main/resources/org/jboss/dna/connector/inmemory/InMemoryConnectorI18n.properties
===================================================================
---
trunk/connectors/dna-connector-inmemory/src/main/resources/org/jboss/dna/connector/inmemory/InMemoryConnectorI18n.properties
(rev 0)
+++
trunk/connectors/dna-connector-inmemory/src/main/resources/org/jboss/dna/connector/inmemory/InMemoryConnectorI18n.properties 2008-06-30
21:32:40 UTC (rev 317)
@@ -0,0 +1,24 @@
+#
+# 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.
+#
+
+connectorName = In-Memory Connector
+nodeDoesNotExist = Could not find an existing node at {0}
\ No newline at end of file
Added:
trunk/connectors/dna-connector-inmemory/src/test/java/org/jboss/dna/connector/inmemory/InMemoryRepositoryTest.java
===================================================================
---
trunk/connectors/dna-connector-inmemory/src/test/java/org/jboss/dna/connector/inmemory/InMemoryRepositoryTest.java
(rev 0)
+++
trunk/connectors/dna-connector-inmemory/src/test/java/org/jboss/dna/connector/inmemory/InMemoryRepositoryTest.java 2008-06-30
21:32:40 UTC (rev 317)
@@ -0,0 +1,351 @@
+/*
+ * 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.inmemory;
+
+import static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.IsNull.notNullValue;
+import static org.hamcrest.core.IsNull.nullValue;
+import static org.hamcrest.core.IsSame.sameInstance;
+import static org.junit.Assert.assertThat;
+import static org.junit.matchers.JUnitMatchers.hasItems;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.stub;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.UUID;
+import org.jboss.dna.spi.graph.Name;
+import org.jboss.dna.spi.graph.NameFactory;
+import org.jboss.dna.spi.graph.PathFactory;
+import org.jboss.dna.spi.graph.Property;
+import org.jboss.dna.spi.graph.PropertyFactory;
+import org.jboss.dna.spi.graph.ValueFactories;
+import org.jboss.dna.spi.graph.ValueFactory;
+import org.jboss.dna.spi.graph.connection.ExecutionEnvironment;
+import org.jboss.dna.spi.graph.impl.BasicNamespaceRegistry;
+import org.jboss.dna.spi.graph.impl.BasicPropertyFactory;
+import org.jboss.dna.spi.graph.impl.StandardValueFactories;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.MockitoAnnotations;
+import org.mockito.MockitoAnnotations.Mock;
+
+/**
+ * @author Randall Hauch
+ */
+public class InMemoryRepositoryTest {
+
+ private InMemoryRepository repository;
+ private String name;
+ private UUID rootUuid;
+ private ValueFactories valueFactories;
+ private PathFactory pathFactory;
+ private NameFactory nameFactory;
+ private PropertyFactory propertyFactory;
+ @Mock
+ private ExecutionEnvironment env;
+
+ @Before
+ public void beforeEach() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ valueFactories = new StandardValueFactories(new BasicNamespaceRegistry());
+ pathFactory = valueFactories.getPathFactory();
+ nameFactory = valueFactories.getNameFactory();
+ propertyFactory = new BasicPropertyFactory(valueFactories);
+ name = "Test repository";
+ rootUuid = UUID.randomUUID();
+ repository = new InMemoryRepository(name, rootUuid);
+ stub(env.getValueFactories()).toReturn(valueFactories);
+ stub(env.getPropertyFactory()).toReturn(propertyFactory);
+ }
+
+ @Test( expected = IllegalArgumentException.class )
+ public void shouldNotAllowNullNameInConstructor() {
+ new InMemoryRepository(null, rootUuid);
+ }
+
+ @Test( expected = IllegalArgumentException.class )
+ public void shouldNotAllowBlankNameInConstructor() {
+ new InMemoryRepository(" \t ", rootUuid);
+ }
+
+ @Test
+ public void shouldHaveLock() {
+ assertThat(repository.getLock(), is(notNullValue()));
+ }
+
+ @Test
+ public void shouldHaveRootNodeAfterInstantiating() {
+ assertThat(repository.getRoot(), is(notNullValue()));
+ }
+
+ @Test
+ public void shouldHaveNameAfterInstantiating() {
+ assertThat(repository.getName(), is(name));
+ }
+
+ @Test
+ public void shouldHaveRootNodeWithRootUuid() {
+ assertThat(repository.getRoot().getUuid(), is(rootUuid));
+ }
+
+ @Test
+ public void shouldGenerateUuids() {
+ Set<UUID> uuids = new HashSet<UUID>();
+ for (int i = 0; i != 100; ++i) {
+ assertThat(uuids.add(repository.generateUuid()), is(true));
+ }
+ }
+
+ @Test( expected = AssertionError.class )
+ public void shouldNotAllowRootToBeRemoved() {
+ repository.removeNode(env, repository.getRoot());
+ }
+
+ @Test( expected = AssertionError.class )
+ public void shouldNotAllowRootToBeMoved() {
+ Node node = mock(Node.class);
+ repository.moveNode(env, repository.getRoot(), node);
+ }
+
+ @Test( expected = AssertionError.class )
+ public void shouldNotAllowNodeToBeMovedUsingNullEnvironment() {
+ Node node = mock(Node.class);
+ Node newParent = mock(Node.class);
+ repository.moveNode(null, node, newParent);
+ }
+
+ @Test( expected = AssertionError.class )
+ public void shouldNotAllowNullNodeToBeMoved() {
+ Node newParent = mock(Node.class);
+ repository.moveNode(env, null, newParent);
+ }
+
+ @Test( expected = AssertionError.class )
+ public void shouldNotAllowNodeToBeRemovedUsingNullEnvironment() {
+ Node node = mock(Node.class);
+ repository.removeNode(null, node);
+ }
+
+ @Test( expected = AssertionError.class )
+ public void shouldNotAllowNullNodeToBeRemoved() {
+ repository.removeNode(env, null);
+ }
+
+ @Test
+ public void shouldCreateNodesByPath() {
+ Name name_a = nameFactory.create("a");
+ Node node_a = repository.createNode(env, repository.getRoot(), name_a);
+ assertThat(node_a, is(notNullValue()));
+ assertThat(node_a.getParent(), is(repository.getRoot()));
+ assertThat(node_a.getName().getName(), is(name_a));
+ assertThat(node_a.getName().hasIndex(), is(false));
+
+ Name name_b = nameFactory.create("b");
+ Node node_b = repository.createNode(env, node_a, name_b);
+ assertThat(node_b, is(notNullValue()));
+ assertThat(node_b.getParent(), is(node_a));
+ assertThat(node_b.getName().getName(), is(name_b));
+ assertThat(node_b.getName().hasIndex(), is(false));
+
+ Name name_c = nameFactory.create("c");
+ Node node_c = repository.createNode(env, node_b, name_c);
+ assertThat(node_c, is(notNullValue()));
+ assertThat(node_c.getParent(), is(node_b));
+ assertThat(node_c.getName().getName(), is(name_c));
+ assertThat(node_c.getName().hasIndex(), is(false));
+
+ assertThat(repository.getNodesByUuid().size(), is(4));
+ assertThat(repository.getNode(pathFactory.create("/")),
is(sameInstance(repository.getRoot())));
+ assertThat(repository.getNode(pathFactory.create("/a")),
is(sameInstance(node_a)));
+ assertThat(repository.getNode(pathFactory.create("/a/b")),
is(sameInstance(node_b)));
+ assertThat(repository.getNode(pathFactory.create("/a/b/c")),
is(sameInstance(node_c)));
+ }
+
+ @Test
+ public void shouldNotFindNodesThatDoNotExist() {
+ Node node_a = repository.createNode(env, repository.getRoot(),
nameFactory.create("a"));
+ Node node_b = repository.createNode(env, node_a,
nameFactory.create("b"));
+ /*Node node_c =*/repository.createNode(env, node_b,
nameFactory.create("c"));
+
+ assertThat(repository.getNodesByUuid().size(), is(4));
+ assertThat(repository.getNode(pathFactory.create("/a[1]")),
is(nullValue()));
+ assertThat(repository.getNode(pathFactory.create("/d")),
is(nullValue()));
+ }
+
+ @Test
+ public void shouldCorrectlyManageIndexesOfSiblingsWithSameNames() {
+ Name name_a1 = nameFactory.create("a");
+ Node node_a1 = repository.createNode(env, repository.getRoot(), name_a1);
+ assertThat(node_a1, is(notNullValue()));
+ assertThat(node_a1.getParent(), is(repository.getRoot()));
+ assertThat(node_a1.getName().getName(), is(name_a1));
+ assertThat(node_a1.getName().hasIndex(), is(false));
+
+ Name name_a2 = nameFactory.create("a");
+ Node node_a2 = repository.createNode(env, repository.getRoot(), name_a2);
+ assertThat(node_a2, is(notNullValue()));
+ assertThat(node_a2.getParent(), is(repository.getRoot()));
+ assertThat(node_a2.getName().getName(), is(name_a2));
+ assertThat(node_a2.getName().hasIndex(), is(true));
+ assertThat(node_a2.getName().getIndex(), is(2));
+
+ // node 1 should now have an index ...
+ assertThat(node_a1.getName().getIndex(), is(1));
+
+ // Add another node without the same name ...
+ Name name_b = nameFactory.create("b");
+ Node node_b = repository.createNode(env, repository.getRoot(), name_b);
+ assertThat(node_b, is(notNullValue()));
+ assertThat(node_b.getParent(), is(repository.getRoot()));
+ assertThat(node_b.getName().getName(), is(name_b));
+ assertThat(node_b.getName().hasIndex(), is(false));
+
+ // Add a third node with the same name ...
+ Name name_a3 = nameFactory.create("a");
+ Node node_a3 = repository.createNode(env, repository.getRoot(), name_a3);
+ assertThat(node_a3, is(notNullValue()));
+ assertThat(node_a3.getParent(), is(repository.getRoot()));
+ assertThat(node_a3.getName().getName(), is(name_a3));
+ assertThat(node_a3.getName().hasIndex(), is(true));
+ assertThat(node_a3.getName().getIndex(), is(3));
+
+ // Check the number of children ...
+ assertThat(repository.getRoot().getChildren().size(), is(4));
+ assertThat(repository.getRoot().getChildren(), hasItems(node_a1, node_a2, node_b,
node_a3));
+ assertThat(repository.getNodesByUuid().size(), is(5));
+ assertThat(repository.getNode(pathFactory.create("/a[1]")),
is(sameInstance(node_a1)));
+ assertThat(repository.getNode(pathFactory.create("/a[2]")),
is(sameInstance(node_a2)));
+ assertThat(repository.getNode(pathFactory.create("/a[3]")),
is(sameInstance(node_a3)));
+ assertThat(repository.getNode(pathFactory.create("/b")),
is(sameInstance(node_b)));
+
+ // Removing a node with the same name will reduce the index ...
+ repository.removeNode(env, node_a2);
+ assertThat(repository.getRoot().getChildren().size(), is(3));
+ assertThat(repository.getRoot().getChildren(), hasItems(node_a1, node_b,
node_a3));
+ assertThat(node_a1.getName().getIndex(), is(1));
+ assertThat(node_b.getName().hasIndex(), is(false));
+ assertThat(node_a3.getName().getIndex(), is(2));
+
+ // Removing a node with the same name will reduce the index ...
+ repository.removeNode(env, node_a1);
+ assertThat(repository.getRoot().getChildren().size(), is(2));
+ assertThat(repository.getRoot().getChildren(), hasItems(node_b, node_a3));
+ assertThat(node_b.getName().hasIndex(), is(false));
+ assertThat(node_a3.getName().hasIndex(), is(false));
+ assertThat(repository.getNodesByUuid().size(), is(3));
+ }
+
+ @Test
+ public void shouldMoveNodes() {
+ Node root = repository.getRoot();
+ Node node_a = repository.createNode(env, root,
nameFactory.create("a"));
+ Node node_b = repository.createNode(env, node_a,
nameFactory.create("b"));
+ Node node_c = repository.createNode(env, node_b,
nameFactory.create("c"));
+ Node node_d = repository.createNode(env, root,
nameFactory.create("d"));
+ Node node_e = repository.createNode(env, node_d,
nameFactory.create("e"));
+ Node node_b2 = repository.createNode(env, node_d,
nameFactory.create("b"));
+
+ assertThat(repository.getNodesByUuid().size(), is(7));
+ assertThat(repository.getNode(pathFactory.create("/")),
is(sameInstance(repository.getRoot())));
+ assertThat(repository.getNode(pathFactory.create("/a")),
is(sameInstance(node_a)));
+ assertThat(repository.getNode(pathFactory.create("/a/b")),
is(sameInstance(node_b)));
+ assertThat(repository.getNode(pathFactory.create("/a/b/c")),
is(sameInstance(node_c)));
+ assertThat(repository.getNode(pathFactory.create("/d")),
is(sameInstance(node_d)));
+ assertThat(repository.getNode(pathFactory.create("/d/e")),
is(sameInstance(node_e)));
+ assertThat(repository.getNode(pathFactory.create("/d/b")),
is(sameInstance(node_b2)));
+
+ repository.moveNode(env, node_b, node_d);
+
+ assertThat(repository.getNode(pathFactory.create("/")),
is(sameInstance(repository.getRoot())));
+ assertThat(repository.getNode(pathFactory.create("/a")),
is(sameInstance(node_a)));
+ assertThat(repository.getNode(pathFactory.create("/d")),
is(sameInstance(node_d)));
+ assertThat(repository.getNode(pathFactory.create("/d/e")),
is(sameInstance(node_e)));
+ assertThat(repository.getNode(pathFactory.create("/d/b[1]")),
is(sameInstance(node_b2)));
+ assertThat(repository.getNode(pathFactory.create("/d/b[2]")),
is(sameInstance(node_b)));
+ assertThat(repository.getNode(pathFactory.create("/d/b[2]/c")),
is(sameInstance(node_c)));
+
+ repository.moveNode(env, node_b, node_e);
+
+ assertThat(repository.getNode(pathFactory.create("/")),
is(sameInstance(repository.getRoot())));
+ assertThat(repository.getNode(pathFactory.create("/a")),
is(sameInstance(node_a)));
+ assertThat(repository.getNode(pathFactory.create("/d")),
is(sameInstance(node_d)));
+ assertThat(repository.getNode(pathFactory.create("/d/e")),
is(sameInstance(node_e)));
+ assertThat(repository.getNode(pathFactory.create("/d/e/b")),
is(sameInstance(node_b)));
+ assertThat(repository.getNode(pathFactory.create("/d/e/b/c")),
is(sameInstance(node_c)));
+ assertThat(repository.getNode(pathFactory.create("/d/b")),
is(sameInstance(node_b2)));
+ }
+
+ @Test
+ public void shouldCopyNodes() {
+ Node root = repository.getRoot();
+ Node node_a = repository.createNode(env, root,
nameFactory.create("a"));
+ Node node_b = repository.createNode(env, node_a,
nameFactory.create("b"));
+ Node node_c = repository.createNode(env, node_b,
nameFactory.create("c"));
+ Node node_d = repository.createNode(env, root,
nameFactory.create("d"));
+ Node node_e = repository.createNode(env, node_d,
nameFactory.create("e"));
+ Node node_b2 = repository.createNode(env, node_d,
nameFactory.create("b"));
+
+ ValueFactory<String> stringFactory = valueFactories.getStringFactory();
+ Name propertyName = nameFactory.create("something");
+ Property property = propertyFactory.create(propertyName,
stringFactory.create("Worth the wait"));
+ node_b.getProperties().put(propertyName, property);
+
+ assertThat(repository.getNodesByUuid().size(), is(7));
+ assertThat(repository.getNode(pathFactory.create("/")),
is(sameInstance(repository.getRoot())));
+ assertThat(repository.getNode(pathFactory.create("/a")),
is(sameInstance(node_a)));
+ assertThat(repository.getNode(pathFactory.create("/a/b")),
is(sameInstance(node_b)));
+ assertThat(repository.getNode(pathFactory.create("/a/b/c")),
is(sameInstance(node_c)));
+ assertThat(repository.getNode(pathFactory.create("/d")),
is(sameInstance(node_d)));
+ assertThat(repository.getNode(pathFactory.create("/d/e")),
is(sameInstance(node_e)));
+ assertThat(repository.getNode(pathFactory.create("/d/b")),
is(sameInstance(node_b2)));
+
+
assertThat(repository.getNode(pathFactory.create("/a/b")).getProperties().get(propertyName),
is(property));
+
+ repository.copyNode(env, node_b, node_d, true);
+
+ assertThat(repository.getNodesByUuid().size(), is(9));
+ assertThat(repository.getNode(pathFactory.create("/")),
is(sameInstance(repository.getRoot())));
+ assertThat(repository.getNode(pathFactory.create("/a")),
is(sameInstance(node_a)));
+ assertThat(repository.getNode(pathFactory.create("/a/b")),
is(sameInstance(node_b)));
+ assertThat(repository.getNode(pathFactory.create("/a/b/c")),
is(sameInstance(node_c)));
+ assertThat(repository.getNode(pathFactory.create("/d")),
is(sameInstance(node_d)));
+ assertThat(repository.getNode(pathFactory.create("/d/e")),
is(sameInstance(node_e)));
+ assertThat(repository.getNode(pathFactory.create("/d/b[1]")),
is(sameInstance(node_b2)));
+ assertThat(repository.getNode(pathFactory.create("/d/b[2]")),
is(notNullValue()));
+ assertThat(repository.getNode(pathFactory.create("/d/b[2]/c")),
is(notNullValue()));
+
+
assertThat(repository.getNode(pathFactory.create("/a/b")).getProperties().get(propertyName),
is(property));
+
assertThat(repository.getNode(pathFactory.create("/d/b[2]")).getProperties().get(propertyName),
is(property));
+ }
+
+ @Test
+ public void shouldCreateRepositoryStructure() {
+ repository.createNode(env, "/a").setProperty(env, "name",
"value").setProperty(env, "desc", "Some description");
+ repository.createNode(env, "/a/b").setProperty(env, "name",
"value2").setProperty(env, "desc", "Some description 2");
+ assertThat(repository.getNode(env, "/a").getProperty(env,
"name").getValuesAsArray(), is(new Object[] {"value"}));
+ assertThat(repository.getNode(env, "/a").getProperty(env,
"desc").getValuesAsArray(),
+ is(new Object[] {"Some description"}));
+ assertThat(repository.getNode(env, "/a/b").getProperty(env,
"name").getValuesAsArray(), is(new Object[] {"value2"}));
+ assertThat(repository.getNode(env, "/a/b").getProperty(env,
"desc").getValuesAsArray(),
+ is(new Object[] {"Some description 2"}));
+ }
+}