/*
* Copyright (C) 2009 eXo Platform SAS.
*
* 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.exoplatform.services.jcr.impl.core;
import org.exoplatform.services.jcr.JcrImplBaseTest;
import org.exoplatform.services.jcr.dataflow.ItemState;
import org.exoplatform.services.jcr.datamodel.IllegalNameException;
import org.exoplatform.services.jcr.datamodel.InternalQName;
import org.exoplatform.services.jcr.datamodel.ItemType;
import org.exoplatform.services.jcr.datamodel.NodeData;
import org.exoplatform.services.jcr.datamodel.QPath;
import org.exoplatform.services.jcr.datamodel.QPathEntry;
import org.exoplatform.services.jcr.impl.Constants;
import org.exoplatform.services.jcr.impl.dataflow.TransientNodeData;
import org.exoplatform.services.jcr.impl.dataflow.TransientPropertyData;
import org.exoplatform.services.jcr.impl.dataflow.TransientValueData;
import org.exoplatform.services.jcr.impl.dataflow.session.SessionChangesLog;
import java.util.ArrayList;
import java.util.List;
import javax.jcr.InvalidItemStateException;
import javax.jcr.ItemExistsException;
import javax.jcr.Node;
import javax.jcr.PathNotFoundException;
import javax.jcr.PropertyType;
import javax.jcr.RepositoryException;
import javax.jcr.lock.LockException;
import javax.jcr.nodetype.ConstraintViolationException;
import javax.jcr.version.VersionException;
/**
* Created by The eXo Platform SAS.
*
* @author <a href="mailto:geaz@users.sourceforge.net">Gennady Azarenkov</a>
* @version $Id: TestSessionDataManager.java 11907 2008-03-13 15:36:21Z ksm $
*/
public class TestSessionDataManager extends JcrImplBaseTest
{
private static String TEST_ROOT = "TestSessionDataManager";
private SessionDataManager modificationManager;
private NodeImpl testRoot;
@Override
public void setUp() throws Exception
{
super.setUp();
modificationManager = session.getTransientNodesManager();
NodeImpl root = (NodeImpl)session.getRootNode();
TransientNodeData data =
TransientNodeData.createNodeData(root.nodeData(), new InternalQName(null, TEST_ROOT), new InternalQName(
Constants.NS_NT_URI, "unstructured"));
testRoot = (NodeImpl)modificationManager.update(ItemState.createAddedState(data), false);
TransientPropertyData prop =
TransientPropertyData.createPropertyData(data, new InternalQName(Constants.NS_JCR_URI, "primaryType"),
PropertyType.NAME, false, new TransientValueData(new InternalQName(Constants.NS_NT_URI, "unstructured")));
PropertyImpl prop1 = (PropertyImpl)modificationManager.update(ItemState.createAddedState(prop), false);
assertEquals(2, modificationManager.getChangesLog().getSize());
modificationManager.commit(data.getQPath());
assertEquals(0, modificationManager.getChangesLog().getSize());
}
public void testItemReferencePool() throws Exception
{
SessionDataManager.ItemReferencePool pool = modificationManager.getItemsPool();
System.gc();
Thread.sleep(1000);
assertEquals(1, pool.size()); // contains root node only
NodeData parent = (NodeData)testRoot.getData();
TransientNodeData data =
TransientNodeData.createNodeData(parent, new InternalQName(null, "testItemReferencePool1"), new InternalQName(
Constants.NS_NT_URI, "unstructured"));
String uuid = data.getIdentifier();
assertEquals(1, pool.size());
NodeImpl node1 = (NodeImpl)modificationManager.update(ItemState.createAddedState(data), true);
assertEquals(2, pool.size());
assertEquals(uuid, node1.getInternalIdentifier());
assertTrue(pool.contains(uuid));
// return the same value
assertEquals(node1, pool.get(node1.getData()));
// add one more node
data =
TransientNodeData.createNodeData(parent, new InternalQName(null, "testItemReferencePool2"), new InternalQName(
Constants.NS_NT_URI, "unstructured"));
NodeImpl node2 = (NodeImpl)modificationManager.update(ItemState.createAddedState(data), true);
List<NodeImpl> nodes = new ArrayList<NodeImpl>();
nodes.add(node1);
nodes.add(node2);
List<NodeImpl> testNodes = getNodes(pool, nodes);
assertEquals(2, testNodes.size());
assertEquals(node1, testNodes.get(0));
assertEquals(node2, testNodes.get(1));
// ... add property
TransientPropertyData prop =
TransientPropertyData.createPropertyData(parent, new InternalQName(null, "testItemReferencePoolProp1"),
PropertyType.STRING, false);
PropertyImpl prop1 = (PropertyImpl)modificationManager.update(ItemState.createAddedState(prop), true);
List<PropertyImpl> props = new ArrayList<PropertyImpl>();
props.add(prop1);
List<PropertyImpl> testProps = getProperties(pool, props);
assertEquals(1, testProps.size());
assertEquals(prop1, testProps.get(0));
pool.remove(uuid);
// in case for GC
Thread.sleep(1000);
// 1 node and 1 prop
if (log.isDebugEnabled())
log.debug(" >>>>> >>>> > " + modificationManager.dump());
// /TestSessionDataManager/testItemReferencePoolProp1
// /TestSessionDataManager
// /TestSessionDataManager/testItemReferencePool2
assertEquals(3, pool.size());
}
private List<NodeImpl> getNodes(SessionDataManager.ItemReferencePool pool, List<NodeImpl> nodes)
throws RepositoryException
{
List<ItemImpl> items = (List<ItemImpl>)pool.getAll();
List<NodeImpl> children = new ArrayList<NodeImpl>();
for (NodeImpl node : nodes)
{
String id = node.getInternalIdentifier();
NodeImpl pooled = null;
for (ItemImpl item : items)
{
if (items.get(0).getData().getIdentifier().equals(id))
{
pooled = (NodeImpl)item;
break;
}
}
if (pooled == null)
{
children.add(node);
}
else
{
pooled.loadData(node.getData());
children.add(pooled);
}
}
return children;
}
private List<PropertyImpl> getProperties(SessionDataManager.ItemReferencePool pool, List<PropertyImpl> props)
throws RepositoryException
{
List<ItemImpl> items = (List<ItemImpl>)pool.getAll();
List<PropertyImpl> children = new ArrayList<PropertyImpl>();
for (PropertyImpl prop : props)
{
String id = prop.getInternalIdentifier();
PropertyImpl pooled = null;
for (ItemImpl item : items)
{
if (items.get(0).getData().getIdentifier().equals(id))
{
pooled = (PropertyImpl)item;
break;
}
}
if (pooled == null)
{
children.add(prop);
}
else
{
pooled.loadData(prop.getData());
children.add(pooled);
}
}
return children;
}
public void testSessionChangesLog() throws Exception
{
SessionChangesLog changesLog = modificationManager.getChangesLog();
assertEquals(0, changesLog.getAllStates().size());
NodeData parent = (NodeData)testRoot.getData();
TransientNodeData data =
TransientNodeData.createNodeData(parent, new InternalQName(null, "testSessionChangesLogN1"),
new InternalQName(Constants.NS_NT_URI, "unstructured"));
NodeImpl node1 = (NodeImpl)modificationManager.update(ItemState.createAddedState(data), true);
assertEquals(1, changesLog.getAllStates().size());
assertNotNull(changesLog.getItemState(node1.getInternalIdentifier()));
assertNotNull(changesLog.getItemState(node1.getInternalPath()));
assertTrue(changesLog.getItemState(node1.getInternalIdentifier()).isAdded());
// delete this node ... state should be DELETED
modificationManager.delete(data);
assertEquals(2, changesLog.getAllStates().size());
List<ItemState> lst = changesLog.getItemStates(data.getIdentifier());
assertEquals(2, lst.size());
assertTrue(changesLog.getItemState(data.getIdentifier()).isDeleted());
// add the same node ... state should be ADDED again
node1 = (NodeImpl)modificationManager.update(ItemState.createAddedState(data), true);
assertEquals(3, changesLog.getItemStates(data.getIdentifier()).size());
assertTrue(changesLog.getItemState(data.getIdentifier()).isAdded());
assertEquals(3, changesLog.getAllStates().size());
// ... add property to the node1
TransientPropertyData prop =
TransientPropertyData.createPropertyData((NodeData)node1.getData(), new InternalQName(null,
"testSessionChangesLogP1"), PropertyType.STRING, false, new TransientValueData(false));
PropertyImpl prop1 = (PropertyImpl)modificationManager.update(ItemState.createAddedState(prop), true);
assertTrue(changesLog.getItemState(node1.getInternalIdentifier()).isAdded());
assertTrue(changesLog.getItemState(prop.getIdentifier()).isAdded());
assertEquals(4, changesLog.getAllStates().size());
// // 4 changes: 3 for node1, and 1- for prop1
assertEquals(4, changesLog.getDescendantsChanges(node1.getInternalPath()).size());
}
public void testReadMethods() throws Exception
{
NodeData parent = (NodeData)testRoot.getData();
TransientNodeData someData =
TransientNodeData.createNodeData(parent, new InternalQName(null, "testReadMethodsN1"), new InternalQName(
Constants.NS_NT_URI, "unstructured"));
// add one more node
TransientNodeData data =
TransientNodeData.createNodeData(parent, new InternalQName(null, "testReadMethodsN2"), new InternalQName(
Constants.NS_NT_URI, "unstructured"));
NodeImpl node2 = (NodeImpl)modificationManager.update(ItemState.createAddedState(data), true);
// ... add property
TransientPropertyData prop =
TransientPropertyData.createPropertyData(parent, new InternalQName(null, "testReadMethodsP1"),
PropertyType.STRING, false, new TransientValueData(false));
PropertyImpl prop1 = (PropertyImpl)modificationManager.update(ItemState.createAddedState(prop), true);
assertNotNull(modificationManager.getItemData(data.getQPath()));
assertEquals(data.getIdentifier(), modificationManager.getItemData(data.getQPath()).getIdentifier());
assertEquals(node2, modificationManager.getItem(data.getQPath(), true));
assertEquals(prop.getIdentifier(), modificationManager.getItemData(prop.getIdentifier()).getIdentifier());
assertEquals(prop1, modificationManager.getItemByIdentifier(prop.getIdentifier(), true));
assertTrue(modificationManager.hasPendingChanges(data.getQPath()));
assertFalse(modificationManager.hasPendingChanges(someData.getQPath()));
assertTrue(modificationManager.isNew(prop.getIdentifier()));
assertFalse(modificationManager.isNew(parent.getIdentifier()));
assertFalse(modificationManager.isModified(prop));
modificationManager.update(ItemState.createUpdatedState(prop), true);
assertTrue(modificationManager.isModified(prop));
assertEquals(1, modificationManager.getChildNodesData(parent).size());
assertEquals(2, modificationManager.getChildPropertiesData(parent).size());
assertEquals(1, modificationManager.getChildNodesData(parent).size());
assertEquals(2, modificationManager.getChildPropertiesData(parent).size());
}
public void testCommitAndRefresh() throws Exception
{
NodeData parent = (NodeData)testRoot.getData();
TransientNodeData data1 =
TransientNodeData.createNodeData(parent, new InternalQName(null, "testCommitAndRefreshN1"), new InternalQName(
Constants.NS_NT_URI, "unstructured"));
NodeImpl node1 = (NodeImpl)modificationManager.update(ItemState.createAddedState(data1), true);
TransientPropertyData nt =
TransientPropertyData.createPropertyData(data1, new InternalQName(Constants.NS_JCR_URI, "primaryType"),
PropertyType.NAME, false, new TransientValueData(new InternalQName(Constants.NS_NT_URI, "unstructured")));
modificationManager.update(ItemState.createAddedState(nt), true);
assertEquals(1, modificationManager.getChildPropertiesData(data1).size());
modificationManager.commit(data1.getQPath());
// make sure changes are saved
assertEquals(0, modificationManager.getChangesLog().getSize());
assertNotNull(modificationManager.getItem(data1.getQPath(), true));
assertEquals(1, modificationManager.getChildPropertiesData(parent).size());
// ... add property
TransientPropertyData prop =
TransientPropertyData.createPropertyData(parent, new InternalQName(null, "testCommitAndRefreshP1"),
PropertyType.STRING, false, new TransientValueData("test"));
modificationManager.update(ItemState.createAddedState(prop), true);
assertEquals("test", ((PropertyImpl)modificationManager.getItem(prop.getQPath(), true)).getString());
}
@SuppressWarnings("deprecation")
public void testGetItem() throws RepositoryException, IllegalNameException
{
// get non-existent data by getItemData(NodeData parent, QPathEntry name)
assertNull(modificationManager.getItemData((NodeData)((NodeImpl)root).getData(), new QPathEntry("",
"testgetitemNode", 0), ItemType.NODE));
// get non-existent data by ItemData getItemData(QPath path)
assertNull(modificationManager.getItemData(QPath.makeChildPath(((NodeImpl)root).getData().getQPath(),
new InternalQName("", "testgetitemNode"))));
NodeImpl testNode = (NodeImpl)root.addNode("testgetitemNode");
// get data by getItemData(NodeData parent, QPathEntry name)
assertNotNull(modificationManager.getItemData((NodeData)((NodeImpl)root).getData(), new QPathEntry("",
"testgetitemNode", 0), ItemType.NODE));
// get data by ItemData getItemData(QPath path)
assertNotNull(modificationManager.getItemData(QPath.makeChildPath(((NodeImpl)root).getData().getQPath(),
new InternalQName("", "testgetitemNode"))));
}
public void testIsDeleted() throws ItemExistsException, PathNotFoundException, VersionException,
ConstraintViolationException, LockException, RepositoryException
{
NodeImpl testNode = (NodeImpl)root.addNode("testNode");
String identifier = testNode.getIdentifier();
QPath itemPath = testNode.getData().getQPath();
assertFalse(modificationManager.isDeleted(identifier));
assertFalse(modificationManager.isDeleted(itemPath));
testNode.remove();
assertTrue(modificationManager.isDeleted(identifier));
assertTrue(modificationManager.isDeleted(itemPath));
}
public void testGetACLWhenNodeIsRoot() throws RepositoryException
{
NodeImpl rootNode = (NodeImpl)root;
assertEquals(rootNode.getACL(), modificationManager.getACL(rootNode.getData().getQPath()));
}
public void testUpdateWhenStateIsDeleted() throws ItemExistsException, PathNotFoundException, VersionException,
ConstraintViolationException, LockException, RepositoryException
{
NodeImpl testNode = (NodeImpl)root.addNode("testNode");
ItemState state = ItemState.createDeletedState(testNode.getData());
try
{
modificationManager.update(state, false);
fail();
}
catch (RepositoryException e)
{
}
}
public void testUpdateStateWhenStateIsDeleted() throws ItemExistsException, PathNotFoundException, VersionException,
ConstraintViolationException, LockException, RepositoryException
{
NodeImpl testNode = (NodeImpl)root.addNode("testNode");
ItemState state = ItemState.createDeletedState(testNode.getData());
try
{
modificationManager.updateItemState(state);
fail();
}
catch (RepositoryException e)
{
}
}
public void testRefreshWhenNodeHasModifiedStatus() throws ItemExistsException, PathNotFoundException,
VersionException, ConstraintViolationException, LockException, RepositoryException
{
NodeImpl testNode = (NodeImpl)root.addNode("testNode");
try
{
modificationManager.refresh(testNode.getData());
fail();
}
catch (InvalidItemStateException e)
{
}
}
/*
* This test is testing problem described in JCR-1864.
* We add 2 node to the system node and we check lastOrderNum for system node.
* Last orderNum from method SessionDataManager.getLastOrderNumber must be equal orderNum from last added node.
*/
public void testGetLastOrderNumFromSystemNode() throws RepositoryException
{
SessionImpl session2 = (SessionImpl)repository.login(credentials, "ws1");
SessionDataManager dataManager = session2.getTransientNodesManager();
Node systemNode = session2.getRootNode().getNode("jcr:system");
systemNode.addNode("node1");
NodeImpl node2 = (NodeImpl)systemNode.addNode("node2");
session2.save();
int lastOrderNum = dataManager.getLastOrderNumber((NodeData)dataManager.getItemData(Constants.SYSTEM_UUID));
int orderNum = ((NodeData)dataManager.getItemData(node2.getIdentifier())).getOrderNumber();
assertEquals(lastOrderNum, orderNum);
}
}