Author: sergiykarpenko
Date: 2010-11-03 11:48:32 -0400 (Wed, 03 Nov 2010)
New Revision: 3389
Added:
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/datamodel/NullItemData.java
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/datamodel/NullPropertyData.java
Modified:
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/datamodel/NullNodeData.java
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/CacheableWorkspaceDataManager.java
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/VersionableWorkspaceDataManager.java
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/jbosscache/JBossCacheWorkspaceStorageCache.java
Log:
EXOJCR-998: NullItemData now stored in ITEMS, CHILD_NODES and CHILD_PROPS cache branches
Added:
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/datamodel/NullItemData.java
===================================================================
---
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/datamodel/NullItemData.java
(rev 0)
+++
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/datamodel/NullItemData.java 2010-11-03
15:48:32 UTC (rev 3389)
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2003-2010 eXo Platform SAS.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not,
see<http://www.gnu.org/licenses/>.
+ */
+package org.exoplatform.services.jcr.datamodel;
+
+import org.exoplatform.services.jcr.dataflow.ItemDataVisitor;
+
+import javax.jcr.RepositoryException;
+
+/**
+ * Created by The eXo Platform SAS.
+ *
+ * <br/>Date:
+ *
+ * @author <a href="karpenko.sergiy(a)gmail.com">Karpenko Sergiy</a>
+ * @version $Id: NullItemData.java 111 2008-11-11 11:11:11Z serg $
+ */
+public abstract class NullItemData implements ItemData
+{
+
+ public static final String NULL_ID = "_null_id";
+
+ private final String id;
+
+ private final String parentId;
+
+ private final QPath path;
+
+ public NullItemData(NodeData parentData, QPathEntry name)
+ {
+ this.parentId = parentData.getIdentifier();
+ this.path = QPath.makeChildPath(parentData.getQPath(), name);
+ this.id = NULL_ID;
+ }
+
+ /**
+ * This constructor must never be used for null nodes placed in cache. Only for
returned values.
+ *
+ * @param parentId
+ * @param name
+ */
+ public NullItemData(String parentId, QPathEntry name)
+ {
+ this.parentId = parentId;
+ this.path = null;
+ this.id = NULL_ID;
+ }
+
+ public NullItemData(String id)
+ {
+ this.parentId = null;
+ this.path = null;
+ this.id = id;
+ }
+
+ public void accept(ItemDataVisitor visitor) throws RepositoryException
+ {
+ }
+
+ public String getIdentifier()
+ {
+ return id;
+ }
+
+ public String getParentIdentifier()
+ {
+ return parentId;
+ }
+
+ public int getPersistedVersion()
+ {
+ return 0;
+ }
+
+ public QPath getQPath()
+ {
+ return path;
+ }
+
+}
Modified:
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/datamodel/NullNodeData.java
===================================================================
---
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/datamodel/NullNodeData.java 2010-11-03
13:50:10 UTC (rev 3388)
+++
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/datamodel/NullNodeData.java 2010-11-03
15:48:32 UTC (rev 3389)
@@ -19,10 +19,7 @@
package org.exoplatform.services.jcr.datamodel;
import org.exoplatform.services.jcr.access.AccessControlList;
-import org.exoplatform.services.jcr.dataflow.ItemDataVisitor;
-import javax.jcr.RepositoryException;
-
/**
* This class is used to represent <code>null</code> value, it is designed to
be used
* into the cache to represent missing value.
@@ -30,61 +27,41 @@
* @author <a href="anatoliy.bazko(a)exoplatform.org">Anatoliy
Bazko</a>
* @version $Id: NullNodeData.java 111 2010-11-11 11:11:11Z tolusha $
*/
-public class NullNodeData implements NodeData
+public class NullNodeData extends NullItemData implements NodeData
{
-
- private final String id;
-
- private final String parentId;
-
- private final QPath path;
-
public NullNodeData(NodeData parentData, QPathEntry name)
{
- this.parentId = parentData.getIdentifier();
- this.path = QPath.makeChildPath(parentData.getQPath(), name);
- this.id = parentId + "$" + name.asString();
+ super(parentData, name);
}
- public NullNodeData(String id)
- {
- this.parentId = null;
- this.path = new QPath(new QPathEntry[]{new QPathEntry(null, null, 0)});
- this.id = id;
- }
-
- /**
- * {@inheritDoc}
+ /**
+ * This constructor must never be used for null nodes placed in cache. Only for
returned values.
+ *
+ * @param parentId
+ * @param name
*/
- @Override
- public AccessControlList getACL()
+ public NullNodeData(String parentId, QPathEntry name)
{
- return null;
+ super(parentId, name);
}
- /**
- * {@inheritDoc}
- */
- @Override
- public InternalQName[] getMixinTypeNames()
+ public NullNodeData(String id)
{
- return null;
+ super(id);
}
/**
* {@inheritDoc}
*/
- @Override
- public int getOrderNumber()
+ public boolean isNode()
{
- return 0;
+ return true;
}
/**
* {@inheritDoc}
*/
- @Override
- public InternalQName getPrimaryTypeName()
+ public AccessControlList getACL()
{
return null;
}
@@ -92,54 +69,25 @@
/**
* {@inheritDoc}
*/
- @Override
- public void accept(ItemDataVisitor visitor) throws RepositoryException
+ public InternalQName[] getMixinTypeNames()
{
+ return null;
}
/**
* {@inheritDoc}
*/
- @Override
- public String getIdentifier()
+ public int getOrderNumber()
{
- return id;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public String getParentIdentifier()
- {
- return parentId;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public int getPersistedVersion()
- {
return 0;
}
/**
* {@inheritDoc}
*/
- @Override
- public QPath getQPath()
+ public InternalQName getPrimaryTypeName()
{
- return path;
+ return null;
}
- /**
- * {@inheritDoc}
- */
- @Override
- public boolean isNode()
- {
- return true;
- }
-
}
Added:
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/datamodel/NullPropertyData.java
===================================================================
---
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/datamodel/NullPropertyData.java
(rev 0)
+++
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/datamodel/NullPropertyData.java 2010-11-03
15:48:32 UTC (rev 3389)
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2003-2010 eXo Platform SAS.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not,
see<http://www.gnu.org/licenses/>.
+ */
+package org.exoplatform.services.jcr.datamodel;
+
+import java.util.List;
+
+/**
+ * Created by The eXo Platform SAS.
+ *
+ * <br/>Date:
+ *
+ * @author <a href="karpenko.sergiy(a)gmail.com">Karpenko Sergiy</a>
+ * @version $Id: NullPropertyData.java 111 2008-11-11 11:11:11Z serg $
+ */
+public class NullPropertyData extends NullItemData implements PropertyData
+{
+
+ public NullPropertyData(NodeData parentData, QPathEntry name)
+ {
+ super(parentData, name);
+ }
+
+ public NullPropertyData(String id)
+ {
+ super(id);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int getType()
+ {
+ return -1;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public List<ValueData> getValues()
+ {
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isMultiValued()
+ {
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isNode()
+ {
+ return false;
+ }
+
+}
Modified:
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/CacheableWorkspaceDataManager.java
===================================================================
---
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/CacheableWorkspaceDataManager.java 2010-11-03
13:50:10 UTC (rev 3388)
+++
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/CacheableWorkspaceDataManager.java 2010-11-03
15:48:32 UTC (rev 3389)
@@ -24,7 +24,9 @@
import org.exoplatform.services.jcr.datamodel.ItemData;
import org.exoplatform.services.jcr.datamodel.ItemType;
import org.exoplatform.services.jcr.datamodel.NodeData;
+import org.exoplatform.services.jcr.datamodel.NullItemData;
import org.exoplatform.services.jcr.datamodel.NullNodeData;
+import org.exoplatform.services.jcr.datamodel.NullPropertyData;
import org.exoplatform.services.jcr.datamodel.PropertyData;
import org.exoplatform.services.jcr.datamodel.QPathEntry;
import org.exoplatform.services.jcr.datamodel.ValueData;
@@ -447,22 +449,24 @@
{
data = getPersistedItemData(parentData, name, itemType);
}
- else if (!data.isNode())
- {
- fixPropertyValues((PropertyData)data);
- }
}
finally
{
request.done();
}
}
- else if (!data.isNode())
+
+ if (data instanceof NullItemData)
{
+ return null;
+ }
+
+ if (data != null && !data.isNode())
+ {
fixPropertyValues((PropertyData)data);
}
- return data instanceof NullNodeData ? null : data;
+ return data;
}
else
{
@@ -496,22 +500,24 @@
{
data = getPersistedItemData(identifier);
}
- else if (!data.isNode())
- {
- fixPropertyValues((PropertyData)data);
- }
}
finally
{
request.done();
}
}
- else if (!data.isNode())
+
+ if (data instanceof NullItemData)
{
+ return null;
+ }
+
+ if (data != null && !data.isNode())
+ {
fixPropertyValues((PropertyData)data);
}
- return data instanceof NullNodeData ? null : data;
+ return data;
}
else
{
@@ -794,7 +800,21 @@
ItemData data = super.getItemData(parentData, name, itemType);
if (cache.isEnabled())
{
- cache.put(data == null ? new NullNodeData(parentData, name) : data);
+ if (data == null)
+ {
+ if (itemType == ItemType.NODE || itemType == ItemType.UNKNOWN)
+ {
+ cache.put(new NullNodeData(parentData, name));
+ }
+ else
+ {
+ cache.put(new NullPropertyData(parentData, name));
+ }
+ }
+ else
+ {
+ cache.put(data);
+ }
}
return data;
}
@@ -817,6 +837,7 @@
}
else if (identifier != null)
{
+ // no matter does property or node expected - store NullNodeData
cache.put(new NullNodeData(identifier));
}
}
Modified:
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/VersionableWorkspaceDataManager.java
===================================================================
---
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/VersionableWorkspaceDataManager.java 2010-11-03
13:50:10 UTC (rev 3388)
+++
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/VersionableWorkspaceDataManager.java 2010-11-03
15:48:32 UTC (rev 3389)
@@ -28,7 +28,7 @@
import org.exoplatform.services.jcr.datamodel.ItemData;
import org.exoplatform.services.jcr.datamodel.ItemType;
import org.exoplatform.services.jcr.datamodel.NodeData;
-import org.exoplatform.services.jcr.datamodel.NullNodeData;
+import org.exoplatform.services.jcr.datamodel.NullItemData;
import org.exoplatform.services.jcr.datamodel.PropertyData;
import org.exoplatform.services.jcr.datamodel.QPath;
import org.exoplatform.services.jcr.datamodel.QPathEntry;
@@ -159,7 +159,7 @@
{
// from cache at first
ItemData cdata = persistentManager.getCachedItemData(identifier);
- if (cdata != null && !(cdata instanceof NullNodeData))
+ if (cdata != null && !(cdata instanceof NullItemData))
{
return super.getItemData(identifier);
}
@@ -168,7 +168,7 @@
{
// search in System cache for /jcr:system nodes only
cdata = versionDataManager.persistentManager.getCachedItemData(identifier);
- if (cdata != null && !(cdata instanceof NullNodeData))
+ if (cdata != null && !(cdata instanceof NullItemData))
{
if (isSystemDescendant(cdata.getQPath()))
{
@@ -187,7 +187,7 @@
{
return data;
}
-
+
else if (!this.equals(versionDataManager))
{
// try from version storage if not the same
Modified:
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/jbosscache/JBossCacheWorkspaceStorageCache.java
===================================================================
---
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/jbosscache/JBossCacheWorkspaceStorageCache.java 2010-11-03
13:50:10 UTC (rev 3388)
+++
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/jbosscache/JBossCacheWorkspaceStorageCache.java 2010-11-03
15:48:32 UTC (rev 3389)
@@ -30,6 +30,7 @@
import org.exoplatform.services.jcr.datamodel.ItemData;
import org.exoplatform.services.jcr.datamodel.ItemType;
import org.exoplatform.services.jcr.datamodel.NodeData;
+import org.exoplatform.services.jcr.datamodel.NullItemData;
import org.exoplatform.services.jcr.datamodel.NullNodeData;
import org.exoplatform.services.jcr.datamodel.PropertyData;
import org.exoplatform.services.jcr.datamodel.QPath;
@@ -62,6 +63,7 @@
import javax.jcr.PropertyType;
import javax.jcr.RepositoryException;
+import javax.transaction.Transaction;
import javax.transaction.TransactionManager;
/**
@@ -144,8 +146,6 @@
protected final Fqn<String> refRoot;
- protected final Fqn<String> nullItemsRoot;
-
protected final Fqn<String> childNodes;
protected final Fqn<String> childProps;
@@ -210,7 +210,7 @@
do
{
String itemId = (String)cache.get(makeChildFqn(root, parentId,
(String)childs.next()), ITEM_ID);
- if (itemId != null)
+ if (itemId != null && !itemId.equals(NullItemData.NULL_ID))
{
n = (T)cache.get(makeItemFqn(itemId), ITEM_DATA);
}
@@ -344,7 +344,6 @@
this.itemsRoot = Fqn.fromRelativeElements(rootFqn, ITEMS);
this.refRoot = Fqn.fromRelativeElements(rootFqn, REFERENCE);
- this.nullItemsRoot = Fqn.fromRelativeElements(rootFqn, NULL_ITEMS);
this.childNodes = Fqn.fromRelativeElements(rootFqn, CHILD_NODES);
this.childProps = Fqn.fromRelativeElements(rootFqn, CHILD_PROPS);
this.childNodesList = Fqn.fromRelativeElements(rootFqn, CHILD_NODES_LIST);
@@ -359,7 +358,6 @@
createResidentNode(childProps);
createResidentNode(childPropsList);
createResidentNode(itemsRoot);
- createResidentNode(nullItemsRoot);
}
/**
@@ -421,6 +419,13 @@
*/
public void put(ItemData item)
{
+ // There is different commit processing for NullNodeData and ordinary ItemData
+ if (item instanceof NullItemData)
+ {
+ putNullItem((NullItemData)item);
+ return;
+ }
+
boolean inTransaction = cache.isTransactionActive();
try
{
@@ -430,20 +435,13 @@
}
cache.setLocal(true);
- if (item instanceof NullNodeData)
+ if (item.isNode())
{
- putNullNode((NullNodeData)item);
+ putNode((NodeData)item, ModifyChildOption.NOT_MODIFY);
}
else
{
- if (item.isNode())
- {
- putNode((NodeData)item, ModifyChildOption.NOT_MODIFY);
- }
- else
- {
- putProperty((PropertyData)item, ModifyChildOption.NOT_MODIFY);
- }
+ putProperty((PropertyData)item, ModifyChildOption.NOT_MODIFY);
}
}
finally
@@ -490,6 +488,7 @@
// There was a problem with removing a list of samename siblings in on
transaction,
// so putItemInBufferedCache(..) and updateInBufferedCache(..) used
instead put(..) and update (..) methods.
ItemData prevItem = putItemInBufferedCache(state.getData());
+
if (prevItem != null && state.isNode())
{
// nodes reordered, if previous is null it's InvalidItemState
case
@@ -542,6 +541,7 @@
cache.setLocal(true);
// remove previous all (to be sure about consistency)
+ //TODO do we need remove node, while we can replace node?
cache.removeNode(makeChildListFqn(childNodesList, parent.getIdentifier()));
if (childs.size() > 0)
@@ -584,6 +584,7 @@
}
cache.setLocal(true);
// remove previous all (to be sure about consistency)
+ //TODO do we need remove node, while we can replace node?
cache.removeNode(makeChildListFqn(childPropsList, parent.getIdentifier()));
if (childs.size() > 0)
{
@@ -618,17 +619,6 @@
public void addChildPropertiesList(NodeData parent, List<PropertyData>
childProperties)
{
// TODO not implemented, will force read from DB
- // try
- // {
- // cache.beginTransaction();
- // cache.setLocal(true);
- //
- // }
- // finally
- // {
- // cache.setLocal(false);
- // cache.commitTransaction();
- // }
}
/**
@@ -645,24 +635,45 @@
public ItemData get(String parentId, QPathEntry name, ItemType itemType)
{
String itemId = null;
- if (itemType == ItemType.NODE || itemType == ItemType.UNKNOWN)
+
+ if (itemType == ItemType.UNKNOWN)
{
- // try as node first
+ // Try as node first.
itemId = (String)cache.get(makeChildFqn(childNodes, parentId, name), ITEM_ID);
+
+ if (itemId == null || itemId.equals(NullItemData.NULL_ID))
+ {
+ // node with such a name is not found or marked as not-exist, so check the
properties
+ String propId = (String)cache.get(makeChildFqn(childProps, parentId, name),
ITEM_ID);
+ if (propId != null)
+ {
+ itemId = propId;
+ }
+ }
}
-
- if (itemType == ItemType.PROPERTY || itemType == ItemType.UNKNOWN && itemId
== null)
+ else if (itemType == ItemType.NODE)
{
- // try as property
+ itemId = (String)cache.get(makeChildFqn(childNodes, parentId, name), ITEM_ID);
+ }
+ else
+ {
itemId = (String)cache.get(makeChildFqn(childProps, parentId, name), ITEM_ID);
}
if (itemId != null)
{
- return getFromCacheById(itemId);
+ if (itemId.equals(NullItemData.NULL_ID))
+ {
+ // this NullNodeData object will not be placed at cache, so we can use unsafe
constructor
+ return new NullNodeData(parentId, name);
+ }
+ else
+ {
+ return get(itemId);
+ }
}
- return (ItemData)cache.get(makeNullItemFqn(parentId + "$" +
name.getAsString(true)), ITEM_DATA);
+ return null;
}
/**
@@ -670,9 +681,7 @@
*/
public ItemData get(String id)
{
- ItemData data = getFromCacheById(id);
-
- return data != null ? data : (ItemData)cache.get(makeNullItemFqn(id), ITEM_DATA);
+ return getFromCacheById(id);
}
/**
@@ -680,6 +689,7 @@
*/
public List<NodeData> getChildNodes(final NodeData parent)
{
+ // empty Set<Object> marks that there is no child nodes
// get list of children uuids
final Set<Object> set =
(Set<Object>)cache.get(makeChildListFqn(childNodesList,
parent.getIdentifier()), ITEM_LIST);
@@ -690,7 +700,8 @@
for (Object child : set)
{
NodeData node = (NodeData)cache.get(makeItemFqn((String)child), ITEM_DATA);
- if (node == null)
+
+ if (node == null || node instanceof NullItemData)
{
return null;
}
@@ -915,17 +926,6 @@
}
/**
- * Make Item absolute Fqn, i.e. /$NULL_ITEMS/itemID.
- *
- * @param itemId String
- * @return Fqn
- */
- protected Fqn<String> makeNullItemFqn(String itemId)
- {
- return Fqn.fromRelativeElements(nullItemsRoot, itemId);
- }
-
- /**
* Make child Item absolute Fqn, i.e. /root/parentId/childName.
*
* @param root Fqn
@@ -968,6 +968,7 @@
*/
protected ItemData getFromCacheById(String id)
{
+ // NullNodeData with id may be stored as ordinary NodeData or PropertyData
return (ItemData)cache.get(makeItemFqn(id), ITEM_DATA);
}
@@ -1010,15 +1011,6 @@
*/
protected ItemData putNode(NodeData node, ModifyChildOption modifyListsOfChild)
{
-
- // remove possible NullNodeData from cache
- boolean local = cache.isLocal();
- cache.setLocal(true);
-
- removeNullNode(node);
-
- cache.setLocal(local);
-
// if not a root node
if (node.getParentIdentifier() != null)
{
@@ -1028,11 +1020,11 @@
if (modifyListsOfChild != ModifyChildOption.NOT_MODIFY)
{
- cache.addToList(makeChildListFqn(childNodesList, node.getParentIdentifier()),
ITEM_LIST,
- node.getIdentifier(), modifyListsOfChild ==
ModifyChildOption.FORCE_MODIFY);
+ cache.addToList(makeChildListFqn(childNodesList, node.getParentIdentifier()),
ITEM_LIST, node
+ .getIdentifier(), modifyListsOfChild == ModifyChildOption.FORCE_MODIFY);
}
+ }
- }
// add in ITEMS
return (ItemData)cache.put(makeItemFqn(node.getIdentifier()), ITEM_DATA, node);
}
@@ -1041,35 +1033,48 @@
* Internal put NullNode.
*
* @param node, NodeData, new data to put in the cache
- * @return ItemData, previous data or null
*/
- protected ItemData putNullNode(NullNodeData node)
+ protected void putNullItem(NullItemData node)
{
- return (ItemData)cache.put(makeNullItemFqn(node.getIdentifier()), ITEM_DATA,
node);
- }
+ boolean inTransaction = cache.isTransactionActive();
+ try
+ {
+ if (!inTransaction)
+ {
+ cache.beginTransaction();
+ }
+ cache.setLocal(true);
- /**
- * Removes NullNode from cache.
- *
- * @param item
- * that possible has corresponding NullNode in cache
- *
- */
- protected void removeNullNode(ItemData item)
- {
- Fqn<String> fqn = makeNullItemFqn(item.getIdentifier());
- if ((NullNodeData)cache.get(fqn, ITEM_DATA) != null)
+ if (node.getQPath() == null)
+ {
+ //put in $ITEMS
+ cache.put(makeItemFqn(node.getIdentifier()), ITEM_DATA, node);
+ }
+ else
+ {
+ if (node.isNode())
+ {
+ // put in $CHILD_NODES
+ cache.put(makeChildFqn(childNodes, node.getParentIdentifier(),
node.getQPath().getEntries()[node
+ .getQPath().getEntries().length - 1]), ITEM_ID, node.getIdentifier());
+ }
+ else
+ {
+ // put in $CHILD_PROPERTIES
+ cache.put(makeChildFqn(childProps, node.getParentIdentifier(),
node.getQPath().getEntries()[node
+ .getQPath().getEntries().length - 1]), ITEM_ID, node.getIdentifier());
+ }
+ }
+ }
+ finally
{
- cache.removeNode(fqn);
+ cache.setLocal(false);
+ if (!inTransaction)
+ {
+ dedicatedTxCommit();
+ }
}
- fqn =
- makeNullItemFqn(item.getParentIdentifier() + "$"
- + item.getQPath().getEntries()[item.getQPath().getEntries().length -
1].getAsString(true));
- if (cache.get(fqn, ITEM_DATA) != null)
- {
- cache.removeNode(fqn);
- }
}
protected ItemData putNodeInBufferedCache(NodeData node, ModifyChildOption
modifyListsOfChild)
@@ -1083,12 +1088,14 @@
if (modifyListsOfChild != ModifyChildOption.NOT_MODIFY)
{
- cache.addToList(makeChildListFqn(childNodesList, node.getParentIdentifier()),
ITEM_LIST,
- node.getIdentifier(), modifyListsOfChild ==
ModifyChildOption.FORCE_MODIFY);
+ cache.addToList(makeChildListFqn(childNodesList, node.getParentIdentifier()),
ITEM_LIST, node
+ .getIdentifier(), modifyListsOfChild == ModifyChildOption.FORCE_MODIFY);
}
}
// add in ITEMS
- return (ItemData)cache.putInBuffer(makeItemFqn(node.getIdentifier()), ITEM_DATA,
node);
+ // NullNodeData must never be returned inside internal cache operations.
+ ItemData returnedData =
(ItemData)cache.putInBuffer(makeItemFqn(node.getIdentifier()), ITEM_DATA, node);
+ return (returnedData instanceof NullItemData) ? null : returnedData;
}
/**
@@ -1099,15 +1106,6 @@
*/
protected PropertyData putProperty(PropertyData prop, ModifyChildOption
modifyListsOfChild)
{
-
- // remove possible NullNodeData from cache
- boolean local = cache.isLocal();
- cache.setLocal(true);
-
- removeNullNode(prop);
-
- cache.setLocal(local);
-
// add in CHILD_PROPS
cache.put(makeChildFqn(childProps, prop.getParentIdentifier(),
prop.getQPath().getEntries()[prop.getQPath()
.getEntries().length - 1]), ITEM_ID, prop.getIdentifier());
@@ -1118,8 +1116,6 @@
modifyListsOfChild == ModifyChildOption.FORCE_MODIFY);
}
- get(prop.getParentIdentifier(),
prop.getQPath().getEntries()[prop.getQPath().getEntries().length - 1]);
-
// add referenced property
if (modifyListsOfChild != ModifyChildOption.NOT_MODIFY && prop.getType() ==
PropertyType.REFERENCE)
{
@@ -1145,7 +1141,9 @@
}
// add in ITEMS
- return (PropertyData)cache.put(makeItemFqn(prop.getIdentifier()), ITEM_DATA,
prop);
+ // NullItemData must never be returned inside internal cache operations.
+ ItemData returnedData = (ItemData)cache.put(makeItemFqn(prop.getIdentifier()),
ITEM_DATA, prop);
+ return (returnedData instanceof NullItemData) ? null : (PropertyData)returnedData;
}
protected void removeItem(ItemData item)
@@ -1201,7 +1199,8 @@
protected void updateMixin(NodeData node)
{
NodeData prevData = (NodeData)cache.put(makeItemFqn(node.getIdentifier()),
ITEM_DATA, node);
- if (prevData != null)
+ // prevent update NullNodeData
+ if (prevData != null && !(prevData instanceof NullItemData))
{
// do update ACL if needed
if (prevData.getACL() == null || !prevData.getACL().equals(node.getACL()))
@@ -1255,10 +1254,12 @@
*/
protected void updateInBuffer(final NodeData node, final NodeData prevNode)
{
+ // I expect that NullNodeData will never update existing NodeData.
// get previously cached NodeData and using its name remove child on the parent
Fqn<String> prevFqn =
makeChildFqn(childNodes, node.getParentIdentifier(),
prevNode.getQPath().getEntries()[prevNode.getQPath()
.getEntries().length - 1]);
+
if (node.getIdentifier().equals(cache.getFromBuffer(prevFqn, ITEM_ID)))
{
// it's same-name siblings re-ordering, delete previous child
@@ -1268,6 +1269,7 @@
}
}
+ // node and prevNode are not NullNodeDatas
// update childs paths if index changed
int nodeIndex = node.getQPath().getEntries()[node.getQPath().getEntries().length -
1].getIndex();
int prevNodeIndex =
prevNode.getQPath().getEntries()[prevNode.getQPath().getEntries().length - 1].getIndex();
@@ -1301,9 +1303,9 @@
// check is this descendant of prevRootPath
QPath nodeQPath = data.getQPath();
- if (nodeQPath.isDescendantOf(prevRootPath))
+ // NullNodeData's qPath==null;
+ if (nodeQPath != null && nodeQPath.isDescendantOf(prevRootPath))
{
-
//make relative path
QPathEntry[] relativePath = null;
try
@@ -1467,4 +1469,44 @@
NOT_MODIFY, MODIFY, FORCE_MODIFY
}
+ /**
+ * Allows to commit the cache changes in a dedicated XA Tx in order to avoid
potential
+ * deadlocks
+ */
+ private void dedicatedTxCommit()
+ {
+ // Ensure that the commit is done in a dedicated tx to avoid deadlock due
+ // to global XA Tx
+ TransactionManager tm = getTransactionManager();
+ Transaction tx = null;
+ try
+ {
+ if (tm != null)
+ {
+ try
+ {
+ tx = tm.suspend();
+ }
+ catch (Exception e)
+ {
+ LOG.warn("Cannot suspend the current transaction", e);
+ }
+ }
+ cache.commitTransaction();
+ }
+ finally
+ {
+ if (tx != null)
+ {
+ try
+ {
+ tm.resume(tx);
+ }
+ catch (Exception e)
+ {
+ LOG.warn("Cannot resume the current transaction", e);
+ }
+ }
+ }
+ }
}