/*
* ModeShape (http://www.modeshape.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.modeshape.jcr;
import static org.hamcrest.core.Is.is;
import static org.hamcrest.core.IsInstanceOf.instanceOf;
import static org.hamcrest.core.IsNot.not;
import static org.hamcrest.core.IsNull.notNullValue;
import static org.hamcrest.core.IsNull.nullValue;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.when;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import javax.jcr.Binary;
import javax.jcr.ImportUUIDBehavior;
import javax.jcr.Item;
import javax.jcr.NamespaceException;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.PathNotFoundException;
import javax.jcr.Property;
import javax.jcr.PropertyIterator;
import javax.jcr.PropertyType;
import javax.jcr.ReferentialIntegrityException;
import javax.jcr.Repository;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.UnsupportedRepositoryOperationException;
import javax.jcr.Value;
import javax.jcr.ValueFactory;
import javax.jcr.nodetype.ConstraintViolationException;
import javax.jcr.nodetype.NodeDefinitionTemplate;
import javax.jcr.nodetype.NodeType;
import javax.jcr.nodetype.NodeTypeManager;
import javax.jcr.nodetype.NodeTypeTemplate;
import javax.jcr.observation.EventIterator;
import javax.jcr.observation.EventListener;
import javax.jcr.query.Query;
import javax.jcr.query.QueryManager;
import org.junit.Test;
import org.mockito.Mockito;
import org.modeshape.common.FixFor;
import org.modeshape.common.junit.SkipLongRunning;
import org.modeshape.common.statistic.Stopwatch;
import org.modeshape.jcr.api.AnonymousCredentials;
import org.modeshape.jcr.api.JcrTools;
import org.modeshape.jcr.api.Namespaced;
import org.modeshape.jcr.api.observation.Event;
import org.modeshape.jcr.value.Path;
public class JcrSessionTest extends SingleUseAbstractTest {
private static final String MULTI_LINE_VALUE = "Line\t1\nLine 2\rLine 3\r\nLine 4";
private static final String PUBLIC_DECODED_NAME = "a|b]c[d:e/f*g";
private static final String PUBLIC_ENCODED_NAME = "a" + '\uF07C' + 'b' + '\uF05D' + 'c' + '\uF05B' + 'd' + '\uF03A' + 'e'
+ '\uF02F' + 'f' + '\uF02A' + 'g';
protected void initializeData() throws Exception {
Node root = session.getRootNode();
Node a = root.addNode("a");
Node b = a.addNode("b");
Node c = b.addNode("c");
a.addMixin("mix:lockable");
a.setProperty("stringProperty", "value");
b.addMixin("mix:referenceable");
b.setProperty("booleanProperty", true);
c.setProperty("stringProperty", "value");
c.setProperty("multiLineProperty", MULTI_LINE_VALUE);
session.save();
}
@FixFor( "MODE-2283" )
@Test
public void shouldAllowRemovingAndRestoringPersistedReference() throws Exception {
Node referenceableNode = session.getRootNode().addNode("referenceable");
referenceableNode.addMixin(JcrMixLexicon.REFERENCEABLE.toString());
Value strongRefValue = session.getValueFactory().createValue(referenceableNode, false);
Node node1 = session.getRootNode().addNode("node1");
node1.setProperty("prop1", strongRefValue);
session.save();
// First remove the property ...
node1.setProperty("prop1", (Value)null);
// And then set the property to the same value that's persisted. Essentially, this session is trying to restore
// the reference that we just removed (transitively). The result should be no net changes in this session.
node1.setProperty("prop1", strongRefValue);
// Now save the changes (even though there should be none) ...
session.save();
PropertyIterator propertyIterator = referenceableNode.getReferences();
assertEquals(1, propertyIterator.getSize());
}
@FixFor( "MODE-2284" )
@Test
public void shouldRestoreBackreferencePropertiesAterImport() throws Exception {
Node referenceableNode = session.getRootNode().addNode("referenceable");
referenceableNode.addMixin(JcrMixLexicon.REFERENCEABLE.toString());
Value strongRefValue = session.getValueFactory().createValue(referenceableNode, false);
Node node1 = session.getRootNode().addNode("node1");
node1.setProperty("prop1", strongRefValue);
session.save();
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
session.exportSystemView("/referenceable", outputStream, false, false);
// Import node tree. This lose backreferences for all nodes in the imported tree
ByteArrayInputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
session.importXML("/referenceable", inputStream, ImportUUIDBehavior.IMPORT_UUID_COLLISION_REPLACE_EXISTING);
// Now save the changes
session.save();
PropertyIterator propertyIterator = referenceableNode.getReferences();
assertEquals(1, propertyIterator.getSize());
}
@Test
@FixFor( "MODE-1956" )
public void shouldDecodeNameWithUnicodeSubstitutionCharacters() {
assertThat(session.decode(PUBLIC_ENCODED_NAME), is(PUBLIC_DECODED_NAME));
}
@Test
@FixFor( "MODE-1956" )
public void shouldEncodeNameWithIllegalCharacters() {
assertThat(session.encode(PUBLIC_DECODED_NAME), is(PUBLIC_ENCODED_NAME));
}
@Test
public void shouldHaveRootNode() throws Exception {
JcrRootNode node = session.getRootNode();
assertThat(node, is(notNullValue()));
assertThat(node.getPath(), is("/"));
}
@Test
public void shouldHaveJcrSystemNodeUnderRoot() throws Exception {
JcrRootNode node = session.getRootNode();
Node system = node.getNode("jcr:system");
assertThat(system, is(notNullValue()));
assertThat(system.getPath(), is("/jcr:system"));
}
@Test
@SkipLongRunning
public void shouldAllowCreatingManyUnstructuredNodesWithSameNameSiblings() throws Exception {
JcrRootNode node = session.getRootNode();
int count = 10000;
long start1 = System.nanoTime();
for (int i = 0; i != count; ++i) {
node.addNode("childNode");
}
long millis = TimeUnit.MILLISECONDS.convert(Math.abs(System.nanoTime() - start1), TimeUnit.NANOSECONDS);
printMessage("Time to create " + count + " nodes under root: " + millis + " ms");
long start2 = System.nanoTime();
session.save();
millis = TimeUnit.MILLISECONDS.convert(Math.abs(System.nanoTime() - start2), TimeUnit.NANOSECONDS);
printMessage("Time to save " + count + " new nodes: " + millis + " ms");
millis = TimeUnit.MILLISECONDS.convert(Math.abs(System.nanoTime() - start1), TimeUnit.NANOSECONDS);
printMessage("Total time to create " + count + " new nodes and save: " + millis + " ms");
NodeIterator iter = node.getNodes("childNode");
assertThat(iter.getSize(), is((long)count));
while (iter.hasNext()) {
Node child = iter.nextNode();
assertThat(child.getPrimaryNodeType().getName(), is("nt:unstructured"));
}
// Now add another node ...
start1 = System.nanoTime();
node.addNode("oneMore");
session.save();
millis = TimeUnit.MILLISECONDS.convert(Math.abs(System.nanoTime() - start1), TimeUnit.NANOSECONDS);
printMessage("Time to create " + (count + 1) + "th node and save: " + millis + " ms");
}
@Test
public void shouldAllowCreatingNodeUnderUnsavedNode() throws Exception {
Node node = session.getRootNode().addNode("testNode");
node.addNode("childNode");
session.save();
}
@Test
public void shouldAllowCreatingManyUnstructuredNodesWithNoSameNameSiblings() throws Exception {
Stopwatch sw = new Stopwatch();
for (int i = 0; i != 15; ++i) {
// Each iteration adds another node under the root and creates the many nodes under that node ...
Node node = session.getRootNode().addNode("testNode");
session.save();
int count = 100;
if (i > 2) sw.start();
for (int j = 0; j != count; ++j) {
node.addNode("childNode" + j);
}
session.save();
if (i > 2) sw.stop();
// Now add another node ...
node.addNode("oneMore");
session.save();
session.getRootNode().getNode("testNode").remove();
session.save();
}
printMessage(sw.getDetailedStatistics().toString());
}
@Test
public void shouldAllowCreatingNodesTwoLevelsBelowRoot() throws Exception {
Node node = session.getRootNode().addNode("testNode");
session.save();
node.addNode("childNode");
session.save();
}
@Test
public void shouldAllowDeletingNodeWithNoChildren() throws Exception {
Node node = session.getRootNode().addNode("testNode");
session.save();
// session.getRootNode().getNodes();
// System.out.println("Root: " + session.getRootNode().getNodes().getSize() + " children");
node.remove();
session.save();
}
@Test
public void shouldAllowDeletingTransientNodeWithNoChildren() throws Exception {
Node node = session.getRootNode().addNode("testNode");
node.remove();
session.save();
}
@Test( expected = IllegalArgumentException.class )
public void shouldNotAllowAddLockToken() throws Exception {
session.addLockToken(null);
}
@Test( expected = IllegalArgumentException.class )
public void shouldNotAllowCheckPermissionWithNoPath() throws Exception {
session.checkPermission((String)null, "read");
}
@Test( expected = IllegalArgumentException.class )
public void shouldNotAllowCheckPermissionWithEmptyPath() throws Exception {
session.checkPermission("", "read");
}
@Test( expected = IllegalArgumentException.class )
public void shouldNotAllowCheckPermissionWithNoActions() throws Exception {
session.checkPermission("/", null);
}
@Test( expected = IllegalArgumentException.class )
public void shouldNotAllowCheckPermissionWithEmptyActions() throws Exception {
session.checkPermission("/", "");
}
@Test
public void shouldReturnNullValueForNullAttributeName() throws Exception {
assertThat(session.getAttribute(null), nullValue());
}
@Test
public void shouldReturnNullValueForEmptyOrBlankAttributeName() throws Exception {
assertThat(session.getAttribute(""), nullValue());
assertThat(session.getAttribute(" "), nullValue());
}
@Test
public void shouldReturnNullValueForNonExistantAttributeName() throws Exception {
assertThat(session.getAttribute("something else entirely"), nullValue());
}
@Test
public void shouldReturnPropertyAttributeValueGivenNameOfExistingAttribute() throws Exception {
session = repository.login(new AnonymousCredentials("attribute1", "value1"));
assertThat(session.getAttribute("attribute1"), is((Object)"value1"));
}
@Test
public void shouldProvideAttributeNames() throws Exception {
session = repository.login(new AnonymousCredentials("attribute1", "value1"));
String[] names = session.getAttributeNames();
assertThat(names, notNullValue());
assertThat(names.length, is(1));
assertThat(names[0], is("attribute1"));
}
@Test
public void shouldProvideEmptyAttributeNames() throws Exception {
session = repository.login(new AnonymousCredentials());
// Get get the attribute names (there should be none) ...
String[] names = session.getAttributeNames();
assertThat(names, notNullValue());
assertThat(names.length, is(0));
}
@Test
public void shouldProvideAccessToRepository() throws Exception {
assertThat(session.getRepository(), is((Repository)repository));
}
@Test
public void shouldProvideAccessToWorkspace() throws Exception {
assertThat(session.getWorkspace(), notNullValue());
}
@Test
public void shouldIndicateLiveBeforeLogout() throws Exception {
assertThat(session.isLive(), is(true));
}
@Test
public void shouldAllowLogout() throws Exception {
session.logout();
}
@Test
public void shouldIndicateNotLiveAfterLogout() throws Exception {
session.logout();
assertThat(session.isLive(), is(false));
}
@Test
public void shouldProvideUserId() throws Exception {
assertThat(session.getUserID(), notNullValue());
try {
assertThat(session.getUserID(), is("<anonymous>"));
} finally {
session.logout();
}
}
@SuppressWarnings( "deprecation" )
@Test
public void shouldProvideRootNode() throws Exception {
Node root = session.getRootNode();
assertThat(root, notNullValue());
String uuid = root.getIdentifier();
assertThat(root.isNodeType("mix:referenceable"), is(true));
assertThat(root.getUUID(), is(uuid));
assertThat(uuid, notNullValue());
}
@Test
public void shouldProvideChildrenByPath() throws Exception {
initializeData();
Item item = session.getItem("/a");
assertThat(item, instanceOf(Node.class));
item = session.getItem("/a/b");
assertThat(item, instanceOf(Node.class));
item = session.getItem("/a/b/booleanProperty");
assertThat(item, instanceOf(Property.class));
}
@Test
public void shouldGetItemByIdentifierPath() throws Exception {
initializeData();
// Look up the node by the identifier path ...
Item item = session.getItem(identifierPathFor("/a"));
assertThat(item, instanceOf(Node.class));
assertThat(item.getPath(), is("/a"));
item = session.getItem(identifierPathFor("/a/b"));
assertThat(item, instanceOf(Node.class));
assertThat(item.getPath(), is("/a/b"));
item = session.getItem(identifierPathFor("/"));
assertThat(item, instanceOf(Node.class));
assertThat(item.getPath(), is("/"));
}
@Test
public void shouldGetNodeByIdentifierPath() throws Exception {
initializeData();
// Look up the node by the identifier path ...
Node node = session.getNode(identifierPathFor("/a"));
assertThat(node.getPath(), is("/a"));
node = session.getNode(identifierPathFor("/a/b"));
assertThat(node.getPath(), is("/a/b"));
node = session.getNode(identifierPathFor("/"));
assertThat(node.getPath(), is("/"));
}
@Test
public void shouldCorrectlyDetermineIfItemExistsUsingPath() throws Exception {
initializeData();
assertThat(session.itemExists("/"), is(true));
assertThat(session.itemExists("/a"), is(true));
assertThat(session.itemExists("/a/b"), is(true));
}
@Test
public void shouldCorrectlyDetermineIfItemExistsUsingIdentifierPath() throws Exception {
initializeData();
assertThat(session.itemExists(identifierPathFor("/")), is(true));
assertThat(session.itemExists(identifierPathFor("/a")), is(true));
assertThat(session.itemExists(identifierPathFor("/a/b")), is(true));
}
@Test
public void shouldProvidePropertiesByPath() throws Exception {
initializeData();
Item item = session.getItem("/a/b/booleanProperty");
assertThat(item, instanceOf(Property.class));
Property property = session.getProperty("/a/b/booleanProperty");
assertThat(property, instanceOf(Property.class));
}
@Test
public void shouldProvideNodesByPath() throws Exception {
initializeData();
Node node = session.getNode("/a");
assertThat(node, instanceOf(Node.class));
node = session.getNode("/a/b");
}
@Test( expected = PathNotFoundException.class )
public void shouldNotReturnPropertyAsNode() throws Exception {
initializeData();
assertThat(session.nodeExists("/a/b/booleanProperty"), is(false));
session.getNode("/a/b/booleanProperty");
}
@Test( expected = PathNotFoundException.class )
public void shouldNotReturnNonExistantNode() throws Exception {
initializeData();
assertThat(session.nodeExists("/a/b/argleBargle"), is(false));
session.getNode("/a/b/argleBargle");
}
@Test
public void shoulReturnPropertyDoesExistAtPathForExistingProperty() throws Exception {
initializeData();
assertThat(session.propertyExists("/a/jcr:primaryType"), is(true));
assertThat(session.propertyExists("/a/jcr:mixinTypes"), is(true));
assertThat(session.propertyExists("/a/b/booleanProperty"), is(true));
assertThat(session.getProperty("/a/b/booleanProperty"), is(notNullValue()));
}
@Test
public void shoulReturnPropertyDoesNotExistAtPathForNode() throws Exception {
initializeData();
assertThat(session.propertyExists("/a/b"), is(false));
try {
assertThat(session.getProperty("/a/b"), is(notNullValue()));
fail("Expected an exception");
} catch (PathNotFoundException e) {
// expected
}
}
@Test
public void shouldReturnNoPropertyExistsWhenPathIncludesNonExistantNode() throws Exception {
initializeData();
assertThat(session.propertyExists("/a/foo/bar/non-existant"), is(false));
}
@Test( expected = PathNotFoundException.class )
public void shouldNotReturnNonExistantProperty() throws Exception {
initializeData();
try {
assertThat(session.propertyExists("/a/b/argleBargle"), is(false));
} catch (RepositoryException e) {
fail("Unexpected exception");
}
// This will throw a PathNotFoundException ...
session.getProperty("/a/b/argleBargle");
}
@SuppressWarnings( "deprecation" )
@Test
public void shouldProvideValueFactory() throws Exception {
InputStream stream = new ByteArrayInputStream("something".getBytes());
ValueFactory factory = session.getValueFactory();
Binary binary = factory.createBinary(new ByteArrayInputStream("something".getBytes()));
assertThat(factory, notNullValue());
assertThat(factory.createValue(false), notNullValue());
assertThat(factory.createValue(Calendar.getInstance()), notNullValue());
assertThat(factory.createValue(0.0), notNullValue());
assertThat(factory.createValue(binary), notNullValue());
assertThat(factory.createValue(stream), notNullValue());
assertThat(factory.createValue(0L), notNullValue());
Node node = session.getRootNode().addNode("testNode");
node.addMixin(JcrMixLexicon.REFERENCEABLE.toString());
assertThat(factory.createValue(node), notNullValue());
assertThat(factory.createValue(""), notNullValue());
assertThat(factory.createValue("", PropertyType.BINARY), notNullValue());
}
@SuppressWarnings( "deprecation" )
@Test( expected = RepositoryException.class )
public void shouldNotCreateValueForNonReferenceableNode() throws Exception {
ValueFactory factory = session.getValueFactory();
Node node = Mockito.mock(Node.class);
String uuid = UUID.randomUUID().toString();
when(node.getUUID()).thenReturn(uuid);
when(node.getIdentifier()).thenReturn(uuid);
when(node.isNodeType("mix:referenceable")).thenReturn(false);
factory.createValue(node);
}
@Test
public void shouldNotHavePendingChanges() throws Exception {
assertThat(session.hasPendingChanges(), is(false));
}
@Test
public void shouldProvideItemExists() throws Exception {
initializeData();
assertThat(session.itemExists("/a/b"), is(true));
assertThat(session.itemExists("/a/c"), is(false));
}
@Test( expected = IllegalArgumentException.class )
public void shouldNotAllowItemExistsWithNoPath() throws Exception {
session.itemExists(null);
}
@Test( expected = IllegalArgumentException.class )
public void shouldNotAllowItemExistsWithEmptyPath() throws Exception {
session.itemExists("");
}
@Test( expected = IllegalArgumentException.class )
public void shouldNotAllowNoNamespaceUri() throws Exception {
session.getNamespacePrefix(null);
}
@Test( expected = NamespaceException.class )
public void shouldNotProvidePrefixForUnknownUri() throws Exception {
session.getNamespacePrefix("bogus");
}
@Test
public void shouldProvideNamespacePrefix() throws Exception {
assertThat(session.getNamespacePrefix("http://www.modeshape.org/1.0"), is("mode"));
assertThat(session.getNamespacePrefix("http://www.jcp.org/jcr/1.0"), is("jcr"));
assertThat(session.getNamespacePrefix("http://www.jcp.org/jcr/mix/1.0"), is("mix"));
assertThat(session.getNamespacePrefix("http://www.jcp.org/jcr/nt/1.0"), is("nt"));
assertThat(session.getNamespacePrefix("http://www.jcp.org/jcr/sv/1.0"), is("sv"));
// assertThat(session.getNamespacePrefix("http://www.w3.org/XML/1998/namespace"), is("xml"));
}
@Test
public void shouldProvideNamespacePrefixes() throws Exception {
String[] prefixes = session.getNamespacePrefixes();
assertThat(prefixes, notNullValue());
assertThat(prefixes.length, is(not(0)));
}
@Test( expected = IllegalArgumentException.class )
public void shouldNotAllowNoNamespacePrefix() throws Exception {
session.getNamespaceURI(null);
}
@Test( expected = NamespaceException.class )
public void shouldNotProvideUriForUnknownPrefix() throws Exception {
session.getNamespaceURI("bogus");
}
@Test
public void shouldProvideNamespaceUri() throws Exception {
assertThat(session.getNamespaceURI("mode"), is("http://www.modeshape.org/1.0"));
assertThat(session.getNamespaceURI("jcr"), is("http://www.jcp.org/jcr/1.0"));
assertThat(session.getNamespaceURI("mix"), is("http://www.jcp.org/jcr/mix/1.0"));
assertThat(session.getNamespaceURI("nt"), is("http://www.jcp.org/jcr/nt/1.0"));
assertThat(session.getNamespaceURI("sv"), is("http://www.jcp.org/jcr/sv/1.0"));
// assertThat(session.getNamespaceURI("xml"), is("http://www.w3.org/XML/1998/namespace"));
}
/**
* ModeShape JCR implementation is supposed to have root type named {@link ModeShapeLexicon#ROOT}.
*
* @throws Exception if an error occurs during the test
*/
@Test
public void rootNodeShouldHaveProperType() throws Exception {
Node rootNode = session.getRootNode();
NodeType rootNodePrimaryType = rootNode.getPrimaryNodeType();
NodeType dnaRootType = session.nodeTypeManager().getNodeType(ModeShapeLexicon.ROOT);
assertThat(rootNodePrimaryType.getName(), is(dnaRootType.getName()));
}
/**
* ModeShape JCR implementation is supposed to have a referenceable root.
*
* @throws RepositoryException if an error occurs during the test
*/
@Test
public void rootNodeShouldBeReferenceable() throws RepositoryException {
Node rootNode = session.getRootNode();
assertTrue(rootNode.getPrimaryNodeType().isNodeType(JcrMixLexicon.REFERENCEABLE.getString(session.namespaces())));
}
@Test
public void shouldExportMultiLinePropertiesInSystemView() throws Exception {
initializeData();
OutputStream os = new ByteArrayOutputStream();
session.exportSystemView("/a/b/c", os, false, true);
String fileContents = os.toString();
assertTrue(fileContents.contains(MULTI_LINE_VALUE));
}
@Test
public void shouldUseJcrCardinalityPerPropertyDefinition() throws Exception {
initializeData();
// Verify that the node does exist in the source ...
Path pathToNode = session.context().getValueFactories().getPathFactory().create("/a/b");
Node carsNode = session.node(pathToNode);
String mixinTypesName = JcrLexicon.MIXIN_TYPES.getString(session.context().getNamespaceRegistry());
Property mixinTypes = carsNode.getProperty(mixinTypesName);
// Check that the JCR property is a MultiProperty - this call will throw an exception if the property is not.
mixinTypes.getValues();
}
/*
* Moved these three tests over from AbstractJcrNode as they require more extensive scaffolding that is already implemented in
* this test.
*/
@Test
public void shouldProvideIdentifierEvenIfNotReferenceable() throws Exception {
initializeData();
// The b node was not set up to be referenceable in this test, but does have a mixin type
Node node = session.getRootNode().getNode("a").getNode("b").getNode("c");
assertThat(node.getIdentifier(), is(notNullValue()));
}
@Test
public void shouldProvideIdentifierEvenIfNoMixinTypes() throws Exception {
initializeData();
// The b node was not set up to be referenceable in this test, but does have a mixin type
Node node = session.getRootNode().getNode("a").getNode("b").getNode("c");
assertThat(node.getIdentifier(), is(notNullValue()));
}
@SuppressWarnings( "deprecation" )
@Test( expected = UnsupportedRepositoryOperationException.class )
public void shouldNotProvideUuidIfNotReferenceable() throws Exception {
initializeData();
// The b node was not set up to be referenceable in this test, but does have a mixin type
Node node = session.getRootNode().getNode("a").getNode("b").getNode("c");
node.getUUID();
}
@SuppressWarnings( "deprecation" )
@Test( expected = UnsupportedRepositoryOperationException.class )
public void shouldNotProvideUuidIfNoMixinTypes() throws Exception {
initializeData();
// The c node was not set up to be referenceable in this test and has no mixin types
Node node = session.getRootNode().getNode("a").getNode("b").getNode("c");
node.getUUID();
}
@Test
public void shouldMoveToNewName() throws Exception {
initializeData();
session.move("/a/b/c", "/a/b/d");
session.getRootNode().getNode("a").getNode("b").getNode("d");
try {
session.getRootNode().getNode("a").getNode("b").getNode("c");
fail("Node still exists at /a/b/c after move");
} catch (PathNotFoundException e) {
// Expected
}
}
@Test
@FixFor( "MODE-1799" )
public void shouldMoveNodesUnderRoot() throws Exception {
initializeData();
session.getRootNode().addNode("d");
session.save();
session.move("/a", "/d");
session.save();
assertNotNull(session.getNode("/d"));
assertNotNull(session.getNode("/d/b"));
assertNotNull(session.getNode("/d/b/c"));
}
@Test
@FixFor( "MODE-2206" )
public void shouldMoveOverNodesRemovedInTheSameSession() throws Exception {
try {
// add 2 nodes under a parent that doesn't allow SNS
final Node root = session.getRootNode();
final Node parent = root.addNode("parent", "nt:folder");
parent.addNode("name1", "nt:folder");
parent.addNode("name2", "nt:folder");
session.save();
// overwrite 2 with 1
session.removeItem("/parent/name2");
assertFalse("Added node 2 doest not exist after remove", session.nodeExists("/parent/name2"));
assertTrue("Added node 1 still exists", session.nodeExists("/parent/name1"));
session.move("/parent/name1", "/parent/name2");
session.save();
assertTrue("Added node 2 doest not exist after move", session.nodeExists("/parent/name2"));
assertFalse("Added node 1 still exists", session.nodeExists("/parent/name1"));
} finally {
session.logout();
}
}
@Test
@FixFor( "MODE-2206" )
public void shouldMoveOverNodesRenamedInTheSameSession() throws Exception {
try {
// add 2 nodes under a parent that doesn't allow SNS
final Node root = session.getRootNode();
final Node parent = root.addNode("parent", "nt:folder");
parent.addNode("name1", "nt:folder");
parent.addNode("name2", "nt:folder");
session.save();
// rename 1 to 3
session.move("/parent/name1", "/parent/name3");
assertFalse(session.nodeExists("/parent/name1"));
assertTrue(session.nodeExists("/parent/name2"));
assertTrue(session.nodeExists("/parent/name3"));
//rename 2 to 1
session.move("/parent/name2", "/parent/name1");
session.save();
assertTrue(session.nodeExists("/parent/name1"));
assertFalse(session.nodeExists("/parent/name2"));
assertTrue(session.nodeExists("/parent/name3"));
} finally {
session.logout();
}
}
@SuppressWarnings( "unchecked" )
@FixFor( "MODE-1721" )
@Test
public void shouldMoveToNewNameWhenSnsAreNotAllowed() throws Exception {
initializeData();
// Define the node type that disallows SNS ...
NodeTypeManager ntMgr = session.getWorkspace().getNodeTypeManager();
NodeDefinitionTemplate childDefn = ntMgr.createNodeDefinitionTemplate();
childDefn.setSameNameSiblings(false);
childDefn.setRequiredPrimaryTypeNames(new String[] {"nt:unstructured"});
childDefn.setDefaultPrimaryTypeName("nt:unstructured");
NodeTypeTemplate nodeType = ntMgr.createNodeTypeTemplate();
nodeType.setName("noSnsChildren");
nodeType.getNodeDefinitionTemplates().add(childDefn);
NodeType newNodeType = ntMgr.registerNodeType(nodeType, false);
assertThat(newNodeType, is(notNullValue()));
Node parent = null;
try {
Node c = session.getNode("/a/b/c");
String parentName = "parent";
parent = c.addNode(parentName, nodeType.getName());
Node childA = parent.addNode("childA");
Node childB = parent.addNode("childB");
Node childC = parent.addNode("childC");
session.save();
assertThat(childA, is(notNullValue()));
assertThat(childB, is(notNullValue()));
assertThat(childC, is(notNullValue()));
String oldChildName = childC.getName(); // no SNS, so this is fine!
String newChildName = "childX";
session.move(childC.getPath(), parent.getPath() + "/" + newChildName);
// A node should exist at the new location ...
parent = session.getRootNode().getNode("a").getNode("b").getNode("c").getNode(parentName);
parent.getNode(newChildName);
try {
// But should not exist at the old location ...
parent.getNode(oldChildName);
fail("Node still exists at /a/b/c/parent/childC after move");
} catch (PathNotFoundException e) {
// Expected
}
} finally {
// Remove the parent (that uses the node type that we're about to remove) ...
if (parent != null) {
parent.remove();
session.save();
}
// Be sure to always unregister the node type ...
ntMgr.unregisterNodeType(nodeType.getName());
}
}
@FixFor( {"MODE-694", "MODE-1525"} )
@Test
public void shouldAddCreatedPropertyForHierarchyNodes() throws Exception {
Node folderNode = session.getRootNode().addNode("folderNode", "nt:folder");
assertThat(folderNode.hasProperty("jcr:created"), is(false));
Node fileNode = folderNode.addNode("fileNode", "nt:file");
Node resource = null;
try {
resource = fileNode.addNode("jcr:content");
fail("Should not be able to add this child without specifying the primary type, as there is no default");
} catch (ConstraintViolationException e) {
resource = fileNode.addNode("jcr:content", "nt:resource");
}
assertThat(fileNode.hasProperty("jcr:created"), is(false));
// Save the changes ...
try {
session.save();
fail("Should not be able to save this; 'jcr:content' is missing the mandatory 'jcr:data' property");
} catch (ConstraintViolationException e) {
Binary binary = session.getValueFactory().createBinary("Some binary value".getBytes());
resource.setProperty("jcr:data", binary);
session.save();
}
assertThat(folderNode.hasProperty("jcr:created"), is(true));
assertThat(fileNode.hasProperty("jcr:created"), is(true));
}
@Test
public void shouldHaveCapabilityToPerformValidAddNode() throws Exception {
assertTrue(session.hasCapability("addNode", session.getRootNode(), new String[] {"someNewNode"}));
assertTrue(session.hasCapability("addNode", session.getRootNode(), new String[] {"someNewNode", "nt:unstructured"}));
}
@Test
public void shouldNotHaveCapabilityToPerformInvalidAddNode() throws Exception {
assertTrue(!session.hasCapability("addNode", session.getRootNode(), new String[] {"someNewNode[2]"}));
assertTrue(!session.hasCapability("addNode", session.getRootNode(), new String[] {"someNewNode", "nt:invalidType"}));
}
@Test
public void shouldCheckReferentialIntegrityWhenRemovingNodes() throws Exception {
Node referenceableNode = session.getRootNode().addNode("referenceable");
referenceableNode.addMixin(JcrMixLexicon.REFERENCEABLE.toString());
Node node1 = session.getRootNode().addNode("node1");
JcrValueFactory valueFactory = session.getValueFactory();
node1.setProperty("ref1", valueFactory.createValue(referenceableNode, false));
node1.setProperty("ref2", valueFactory.createValue(referenceableNode, false));
node1.setProperty("wref1", valueFactory.createValue(referenceableNode, true));
node1.setProperty("wref2", valueFactory.createValue(referenceableNode, true));
session.save();
// there are 2 strong refs
referenceableNode.remove();
expectReferentialIntegrityException();
// remove the first strong ref
node1.setProperty("ref1", (Node)null);
referenceableNode.remove();
expectReferentialIntegrityException();
// remove the second strong ref (we should be able to remove the node now)
assertEquals(2, referenceableNode.getWeakReferences().getSize());
node1.setProperty("ref1", (Node)null);
node1.setProperty("ref2", (Node)null);
referenceableNode.remove();
session.save();
// check the node was actually deleted
assertFalse(session.getRootNode().hasNode("referenceable"));
}
@FixFor( "MODE-1685" )
@Test
public void shouldEnforceReferentialIntegrityWhenRemovingNodes() throws Exception {
JcrValueFactory valueFactory = session.getValueFactory();
Node targetNode = session.getRootNode().addNode("target");
targetNode.addMixin(JcrMixLexicon.REFERENCEABLE.toString());
Node parentNode = session.getRootNode().addNode("parent");
Node childNode = parentNode.addNode("child");
childNode.setProperty("ref1", valueFactory.createValue(targetNode, false));
session.save();
// Delete the target - there are references to this node, so we can't remove ...
try {
targetNode.remove();
session.save();
fail("Expected a referential integrity exception");
} catch (ReferentialIntegrityException e) {
// expected
}
}
@FixFor( "MODE-1685" )
@Test
public void shouldCheckReferentialIntegrityOfSubgraphWhenRemovingNodes() throws Exception {
JcrValueFactory valueFactory = session.getValueFactory();
Node targetNode = session.getRootNode().addNode("target");
targetNode.addMixin(JcrMixLexicon.REFERENCEABLE.toString());
Node parentNode = session.getRootNode().addNode("parent");
Node childNode = parentNode.addNode("child");
childNode.setProperty("ref1", valueFactory.createValue(targetNode, false));
session.save();
// Delete the parent (which will delete the child and the reference to the target ...
parentNode.remove();
session.save();
// Delete the target - there should be no references ...
targetNode.remove();
session.save();
}
@FixFor( "MODE-1685" )
@Test
public void shouldNotEnforceReferentialIntegrityOfWeakReferenceWhenRemovingNodes() throws Exception {
JcrValueFactory valueFactory = session.getValueFactory();
Node targetNode = session.getRootNode().addNode("target");
targetNode.addMixin(JcrMixLexicon.REFERENCEABLE.toString());
Node parentNode = session.getRootNode().addNode("parent");
Node childNode = parentNode.addNode("child");
childNode.setProperty("ref1", valueFactory.createValue(targetNode, true));
session.save();
// Delete the target - there should be no strong references, but the weak is okay and won't prevent removal ...
targetNode.remove();
session.save();
}
@Test
@FixFor( "MODE-1613" )
public void shouldMoveSNSAndNotCorruptThePathsOfRemainingSiblings() throws Exception {
startRepositoryWithConfiguration(getClass().getClassLoader().getResourceAsStream("config/simple-repo-config.json"));
// /testRoot/parent0/child
// /testRoot/parent0/child[2]
// /testRoot/parent0/child[3]
// /testRoot/parent1/child
// /testRoot/parent1/child[2]
// /testRoot/parent1/child[3]
// move /testRoot/parent0/child[1] to /testRoot/parent1.
createTreeWithSNS(2, 3);
String srcId = session.getNode("/testRoot/parent0/child[1]").getIdentifier();
String destId = session.getNode("/testRoot/parent1").getIdentifier();
moveSNSWhileCachingPaths(srcId, destId, "child");
}
@Test
@FixFor( "MODE-1623" )
public void shouldAutomaticallySetDefaultValueOnProperties() throws Exception {
// Start the repository and register some node types ...
ClassLoader cl = getClass().getClassLoader();
startRepositoryWithConfiguration(cl.getResourceAsStream("config/simple-repo-config.json"));
session.getWorkspace().getNodeTypeManager().registerNodeTypes(cl.getResource("cnd/notionalTypes.cnd"), true);
// Create a node using a type with property definitions that have default values ...
Node node1 = session.getRootNode().addNode("node1", "notion:typed");
// Before saving, the auto-created properties should be there ...
assertThat(node1.hasProperty("notion:booleanProperty"), is(false));
assertThat(node1.hasProperty("notion:booleanProperty2"), is(false));
assertThat(node1.hasProperty("notion:longProperty"), is(false));
assertThat(node1.hasProperty("notion:stringProperty"), is(false));
assertThat(node1.hasProperty("notion:booleanPropertyWithDefault"), is(false));
assertThat(node1.hasProperty("notion:stringPropertyWithDefault"), is(false));
assertThat(node1.hasProperty("notion:booleanAutoCreatedPropertyWithDefault"), is(true));
assertThat(node1.hasProperty("notion:stringAutoCreatedPropertyWithDefault"), is(true));
assertThat(node1.getProperty("notion:booleanAutoCreatedPropertyWithDefault").getBoolean(), is(true));
assertThat(node1.getProperty("notion:stringAutoCreatedPropertyWithDefault").getString(), is("default string value"));
// Save, and then check that the properties exist ...
session.save();
assertThat(node1.hasProperty("notion:booleanPropertyWithDefault"), is(false));
assertThat(node1.hasProperty("notion:stringPropertyWithDefault"), is(false));
assertThat(node1.hasProperty("notion:booleanAutoCreatedPropertyWithDefault"), is(true));
assertThat(node1.hasProperty("notion:stringAutoCreatedPropertyWithDefault"), is(true));
assertThat(node1.getProperty("notion:booleanAutoCreatedPropertyWithDefault").getBoolean(), is(true));
assertThat(node1.getProperty("notion:stringAutoCreatedPropertyWithDefault").getString(), is("default string value"));
}
@FixFor( "MODE-1767" )
@Test
public void shouldAutomaticallyAddMimeTypePropertyToNtResourceUponSave() throws Exception {
// Start the repository ...
ClassLoader cl = getClass().getClassLoader();
startRepositoryWithConfiguration(cl.getResourceAsStream("config/simple-repo-config.json"));
// Add a node under which we'll do our work ...
Node node1 = session.getRootNode().addNode("node1");
session.save();
// Upload a file
JcrTools tools = new JcrTools();
tools.uploadFile(session, "/node1/simple.json", getResourceFile("data/simple.json"));
Node fileNode = node1.getNode("simple.json");
Node contentNode = fileNode.getNode("jcr:content");
assertThat(contentNode.getPrimaryNodeType().getName(), is("nt:resource"));
assertThat(contentNode.hasProperty("jcr:mimeType"), is(false));
assertThat(contentNode.hasProperty("jcr:data"), is(true));
// Save the session, and verify that the "jcr:mimeType" property is added ...
session.save();
assertThat(contentNode.hasProperty("jcr:data"), is(true));
assertThat(contentNode.hasProperty("jcr:mimeType"), is(true));
assertThat(contentNode.getProperty("jcr:mimeType").getString(), is("application/json"));
}
@FixFor( "MODE-1767" )
@Test
public void shouldAutomaticallyAddMimeTypePropertyToNtResourceSubtypeUponSave() throws Exception {
// Start the repository ...
ClassLoader cl = getClass().getClassLoader();
startRepositoryWithConfiguration(cl.getResourceAsStream("config/simple-repo-config.json"));
// Register a new node type that is a subtype of 'nt:resource'
NodeTypeManager ntMgr = session.getWorkspace().getNodeTypeManager();
NodeTypeTemplate template = ntMgr.createNodeTypeTemplate();
template.setDeclaredSuperTypeNames(new String[] {"nt:resource"});
template.setName("customResourceType");
NodeType ntResourceSubtype = ntMgr.registerNodeType(template, false);
assertThat(ntResourceSubtype.getDeclaredSupertypes()[0].getName(), is("nt:resource"));
// Add a node under which we'll do our work ...
Node node1 = session.getRootNode().addNode("node1");
session.save();
// Upload a file
JcrTools tools = new JcrTools();
tools.uploadFile(session, "/node1/simple.json", getResourceFile("data/simple.json"));
Node fileNode = node1.getNode("simple.json");
Node contentNode = fileNode.getNode("jcr:content");
contentNode.setPrimaryType(ntResourceSubtype.getName());
assertThat(contentNode.getPrimaryNodeType().getName(), is(ntResourceSubtype.getName()));
assertThat(contentNode.hasProperty("jcr:mimeType"), is(false));
assertThat(contentNode.hasProperty("jcr:data"), is(true));
// Save the session, and verify that the "jcr:mimeType" property is added ...
session.save();
assertThat(contentNode.hasProperty("jcr:data"), is(true));
assertThat(contentNode.hasProperty("jcr:mimeType"), is(true));
assertThat(contentNode.getProperty("jcr:mimeType").getString(), is("application/json"));
}
@FixFor( "MODE-1767" )
@Test
public void shouldNotOverrideManuallyAddedMimeTypePropertyToNtResourceUponSave() throws Exception {
// Start the repository ...
ClassLoader cl = getClass().getClassLoader();
startRepositoryWithConfiguration(cl.getResourceAsStream("config/simple-repo-config.json"));
// Add a node under which we'll do our work ...
Node node1 = session.getRootNode().addNode("node1");
session.save();
// Upload a file
JcrTools tools = new JcrTools();
tools.uploadFile(session, "/node1/simple.json", getResourceFile("data/simple.json"));
Node fileNode = node1.getNode("simple.json");
Node contentNode = fileNode.getNode("jcr:content");
contentNode.setProperty("jcr:mimeType", "bogus");
assertThat(contentNode.getPrimaryNodeType().getName(), is("nt:resource"));
assertThat(contentNode.getProperty("jcr:mimeType").getString(), is("bogus"));
assertThat(contentNode.hasProperty("jcr:data"), is(true));
// Save the session, and verify that the "jcr:mimeType" property is added ...
session.save();
assertThat(contentNode.hasProperty("jcr:data"), is(true));
assertThat(contentNode.hasProperty("jcr:mimeType"), is(true));
assertThat(contentNode.getProperty("jcr:mimeType").getString(), is("bogus"));
}
@FixFor( "MODE-1767" )
@Test
public void shouldNotAddMimeTypePropertyUnderNtFileIfContentNodeIsNotNtResource() throws Exception {
// Start the repository ...
ClassLoader cl = getClass().getClassLoader();
startRepositoryWithConfiguration(cl.getResourceAsStream("config/simple-repo-config.json"));
// Add a node under which we'll do our work ...
Node node1 = session.getRootNode().addNode("node1");
session.save();
// Upload a file
JcrTools tools = new JcrTools();
tools.uploadFile(session, "/node1/simple.json", getResourceFile("data/simple.json"));
Node fileNode = node1.getNode("simple.json");
Node contentNode = fileNode.getNode("jcr:content");
assertThat(contentNode.getPrimaryNodeType().getName(), is("nt:resource"));
contentNode.setPrimaryType("nt:unstructured");
assertThat(contentNode.hasProperty("jcr:mimeType"), is(false));
assertThat(contentNode.hasProperty("jcr:data"), is(true));
// Save the session, and verify that the "jcr:mimeType" property is added ...
session.save();
assertThat(contentNode.hasProperty("jcr:mimeType"), is(false));
assertThat(contentNode.hasProperty("jcr:data"), is(true));
}
@FixFor( "MODE-1855" )
@Test
public void shouldGetLocalNameAndNamespaceUriFromRootNode() throws Exception {
assertLocalNameAndNamespace(session.getRootNode(), "", "");
}
@FixFor( "MODE-1855" )
@Test
public void shouldGetLocalNameAndNamespaceUriFromNodeAndPropertyObjects() throws Exception {
// Add a node under which we'll do our work ...
Node node1 = session.getRootNode().addNode("node1");
session.save();
assertLocalNameAndNamespace(node1, "node1", "");
// Add another SNS node under which we'll do our work ...
Node node1a = session.getRootNode().addNode("node1");
session.save();
assertThat(node1a.getIndex(), is(2));
assertLocalNameAndNamespace(node1a, "node1", ""); // no SNS index in local name!
// Upload a file
JcrTools tools = new JcrTools();
tools.uploadFile(session, "/node1/simple.json", getResourceFile("data/simple.json"));
Node fileNode = node1.getNode("simple.json");
Node contentNode = fileNode.getNode("jcr:content");
assertLocalNameAndNamespace(fileNode, "simple.json", "");
assertLocalNameAndNamespace(contentNode, "content", "jcr");
}
@FixFor( "MODE-1856" )
@Test
public void shouldNotIndexNoOpChanges() throws Exception {
// Add a node under which we'll do our work ...
Node node1 = session.getRootNode().addNode("node1");
session.save();
// Register the listener
PropertyListener listener = new PropertyListener();
session.getWorkspace().getObservationManager()
.addEventListener(listener, Event.PROPERTY_ADDED | Event.PROPERTY_CHANGED | Event.PROPERTY_REMOVED, null, // node1.getPath(),
true, null, null, false);
// Now, add a property and remove the property, then save ...
node1.setProperty("unchanged", "new value");
node1.getProperty("unchanged").remove();
session.save();
Thread.sleep(500L);
assertThat(listener.adds, is(0));
assertThat(listener.removes, is(0));
assertThat(listener.changes, is(0));
}
@Test
@FixFor( "MODE-1894" )
public void shouldReplaceOldPropertyValuesInIndexesWhenUpdating() throws Exception {
initializeData();
Node a = session.getNode("/a");
a.setProperty("stringProperty1", "value");
session.save();
Thread.sleep(200);
queryAndExpectResults("select * from [nt:unstructured] as node where node.stringProperty='value'", 2);
queryAndExpectResults("select * from [nt:unstructured] as node where node.stringProperty1='value'", 1);
a.setProperty("stringProperty", "value1");
session.save();
Thread.sleep(200);
queryAndExpectResults("select * from [nt:unstructured] as node where node.stringProperty='value'", 1);
queryAndExpectResults("select * from [nt:unstructured] as node where node.stringProperty1='value'", 1);
}
@Test
@FixFor( "MODE-1940" )
public void shouldIndexRenamedNodes() throws Exception {
initializeData();
// rename /a/b to /a/d
session.getWorkspace().move("/a/b", "/a/d");
Thread.sleep(200);
queryForAbsentLocalName("b");
queryForExistingLocaLName("d", "/a/d");
queryForExistingLocaLName("c", "/a/d/c");
}
@Test
@FixFor( "MODE-1940" )
public void shouldIndexMovedNodes() throws Exception {
initializeData();
// create /w/q
session.getNode("/").addNode("w").addNode("q");
session.save();
// move /a to /w/q
session.getWorkspace().move("/a", "/w/x");
Thread.sleep(200);
queryForAbsentLocalName("a");
queryForExistingLocaLName("x", "/w/x");
queryForExistingLocaLName("b", "/w/x/b");
queryForExistingLocaLName("c", "/w/x/b/c");
}
@Test
@FixFor( "MODE-2030" )
public void shouldIndexChildrenOfRenamedNode() throws Exception {
Node rootNode = session().getRootNode();
Node folder = rootNode.addNode("folder", "nt:folder");
Node file = folder.addNode("file", "nt:file");
Node contentNode = file.addNode("jcr:content", "nt:resource");
contentNode.setProperty("jcr:data", session().getValueFactory().createBinary("test".getBytes()));
session().save();
Thread.sleep(200);
queryAndExpectResults("SELECT * FROM [nt:file] WHERE [jcr:path] LIKE '/folder/%'", 1);
folder.getSession().move(folder.getPath(), "/folder_1");
folder.getSession().save();
Thread.sleep(200);
queryAndExpectResults("SELECT * FROM [nt:file] WHERE [jcr:path] LIKE '/folder_1/%'", 1);
}
@Test
@FixFor( "MODE-2030" )
public void shouldIndexChildrenOfMovedNode() throws Exception {
Node rootNode = session().getRootNode();
Node folder = rootNode.addNode("folder", "nt:folder");
Node file = folder.addNode("file", "nt:file");
Node contentNode = file.addNode("jcr:content", "nt:resource");
contentNode.setProperty("jcr:data", session().getValueFactory().createBinary("test".getBytes()));
String lastModifiedBy = "testCode";
contentNode.setProperty("jcr:lastModifiedBy", lastModifiedBy);
rootNode.addNode("folderA");
session().save();
Thread.sleep(200);
queryAndExpectResults("SELECT * FROM [nt:file] WHERE [jcr:path] LIKE '/folder/%'", 1);
queryAndExpectResults("SELECT * FROM [nt:file] WHERE [jcr:path] LIKE '/folderA/%'", 0);
queryAndExpectResults("SELECT * FROM [nt:resource] as r WHERE r.[jcr:lastModifiedBy]='" + lastModifiedBy + "'", 1);
folder.getSession().move(folder.getPath(), "/folderA/folderB");
folder.getSession().save();
Thread.sleep(200);
queryAndExpectResults("SELECT * FROM [nt:file] WHERE [jcr:path] LIKE '/folder/%'", 0);
queryAndExpectResults("SELECT * FROM [nt:file] WHERE [jcr:path] LIKE '/folderA/folderB/%'", 1);
queryAndExpectResults("SELECT * FROM [nt:resource] as r WHERE r.[jcr:lastModifiedBy]='" + lastModifiedBy + "'", 1);
}
@Test
@FixFor( "MODE-2029" )
public void shouldRetrieveNodesUsingIsChildNodeAfterMove() throws Exception {
Node rootNode = session().getRootNode();
rootNode.addNode("a").addNode("b").addNode("c");
rootNode.addNode("tmp");
session.save();
Thread.sleep(200);
queryAndExpectResults("SELECT * FROM [nt:unstructured] as node WHERE ISCHILDNODE (node, '/a/b')", 1);
session.getWorkspace().move("/a/b", "/tmp/b");
Thread.sleep(200);
queryAndExpectResults("SELECT * FROM [nt:unstructured] as node WHERE ISCHILDNODE (node, '/tmp/b')", 1);
queryAndExpectResults("SELECT * FROM [nt:unstructured] as node WHERE ISCHILDNODE (node, '/a/b')", 0);
}
@Test
@FixFor( "MODE-2281" )
public void shouldAllowUsingSystemNodeTypesInNonSystemArea() throws Exception {
try {
Node rootNode = session().getRootNode();
Node myVersionNode = rootNode.addNode("myVersion", "nt:version");
myVersionNode.addNode("frozen", "nt:frozenNode");
} catch (ConstraintViolationException e) {
if (!e.getMessage().contains("is protected")) {
// It's not the exception we expect ...
throw e;
}
}
}
private List<Node> queryAndExpectResults( String queryString,
int howMany ) throws RepositoryException {
QueryManager queryManager = session.getWorkspace().getQueryManager();
Query query = queryManager.createQuery(queryString, Query.JCR_SQL2);
NodeIterator nodes = query.execute().getNodes();
List<Node> result = new ArrayList<Node>();
while (nodes.hasNext()) {
result.add(nodes.nextNode());
}
assertEquals("Invalid nodes retrieved from query: " + result, howMany, result.size());
return result;
}
private void queryForAbsentLocalName( String localNodeName ) throws RepositoryException {
queryAndExpectResults("select n from [nt:unstructured] as n where localname(n)='" + localNodeName + "'", 0);
}
private void queryForExistingLocaLName( String localNodeName,
String expectedPath ) throws RepositoryException {
List<Node> nodes = queryAndExpectResults("select n from [nt:unstructured] as n where localname(n)='" + localNodeName
+ "'", 1);
Node node = nodes.get(0);
assertEquals(localNodeName, node.getName());
assertEquals(expectedPath, node.getPath());
}
protected static class PropertyListener implements EventListener {
protected int adds, removes, changes;
@Override
public void onEvent( EventIterator events ) {
System.out.println("CALLED");
while (events.hasNext()) {
javax.jcr.observation.Event event = events.nextEvent();
switch (event.getType()) {
case Event.PROPERTY_ADDED:
++adds;
break;
case Event.PROPERTY_CHANGED:
++changes;
break;
case Event.PROPERTY_REMOVED:
++removes;
break;
}
}
}
}
protected void assertLocalNameAndNamespace( Item item,
String expectedLocalName,
String namespacePrefix ) throws RepositoryException {
Namespaced nsed = (Namespaced)item;
assertThat(nsed.getLocalName(), is(expectedLocalName));
assertThat(nsed.getNamespaceURI(), is(session.getNamespaceURI(namespacePrefix)));
}
protected InputStream getResourceFile( String path ) {
return getClass().getClassLoader().getResourceAsStream(path);
}
/**
* Create a tree of nodes that have different name siblings at the leaves.
*
* @param parentsCount the number of nodes created under the root node
* @param snsCount the number of nodes created under each parent
* @throws Exception
*/
private void createTreeWithSNS( int parentsCount,
int snsCount ) throws Exception {
session = repository.login();
List<String> nodeIds = new ArrayList<String>();
Node testRoot = session.getRootNode().addNode("testRoot");
for (int i = 0; i < parentsCount; i++) {
nodeIds.add(testRoot.addNode("parent" + i).getIdentifier());
}
for (String parentId : nodeIds) {
Node parent = session.getNodeByIdentifier(parentId);
for (int c = 0; c < snsCount; c++) {
parent.addNode("child");
}
}
session.save();
}
private void moveSNSWhileCachingPaths( String srcId,
String destId,
String destNodeName ) throws Exception {
Node targetNode = session.getNodeByIdentifier(destId);
String targetNodePath = targetNode.getPath();
targetNode = session.getNode(targetNodePath);
Node sourceNode = session.getNodeByIdentifier(srcId);
String sourceNodePath = sourceNode.getPath();
sourceNode = session.getNode(sourceNodePath);
Node sourceParent = sourceNode.getParent();
// the next calls will load all the children (sns) and store them in the ws cache
loadChildrenByPaths(session, sourceParent);
loadChildrenByPaths(session, targetNode);
session.move(sourceNodePath, targetNodePath + "/" + destNodeName);
session.save();
// this will expose the problem of the cached paths
loadChildrenByPaths(session, sourceParent);
loadChildrenByPaths(session, targetNode);
}
private void loadChildrenByPaths( Session session,
Node parentNode ) throws Exception {
NodeIterator nodeIterator = parentNode.getNodes();
while (nodeIterator.hasNext()) {
Node childNode = nodeIterator.nextNode();
// this should load &cache the nodes (and their paths)
session.getNode(childNode.getPath());
}
}
private void expectReferentialIntegrityException() throws RepositoryException {
try {
session.save();
fail("Expected a referential integrity exception");
} catch (ReferentialIntegrityException e) {
// expected
session.refresh(false);
}
}
@SuppressWarnings( "deprecation" )
protected String identifierPathFor( String pathToNode ) throws Exception {
AbstractJcrNode node = session.getNode(pathToNode);
if (node.isNodeType("mix:referenceable")) {
// Make sure that the identifier matches the UUID ...
assertThat(node.getUUID(), is(node.getIdentifier()));
} else {
try {
node.getUUID();
fail("Should have thrown an UnsupportedRepositoryOperationException if the node " + pathToNode
+ " is not referenceable");
} catch (UnsupportedRepositoryOperationException e) {
// expected
}
}
return node.identifierPath();
}
}