mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-08-07 17:49:17 +00:00
Node cache changes (step): properties and aspects are retrieved with the node's version
- Perform basic node version check when reading properties and aspects from DB - This is just the start. Next step is to change the key of the cache itself. - Includes fix for rev 31109: Use setNodeAclId() to set ACL IDs git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@31121 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -82,6 +82,7 @@
|
|||||||
<resultMap id="result_NodeAspects" type="NodeAspects" groupBy="nodeId"> -->
|
<resultMap id="result_NodeAspects" type="NodeAspects" groupBy="nodeId"> -->
|
||||||
<resultMap id="result_NodeAspects" type="NodeAspects">
|
<resultMap id="result_NodeAspects" type="NodeAspects">
|
||||||
<id property="nodeId" column="node_id" jdbcType="BIGINT" javaType="java.lang.Long"/>
|
<id property="nodeId" column="node_id" jdbcType="BIGINT" javaType="java.lang.Long"/>
|
||||||
|
<id property="nodeVersion" column="node_version" jdbcType="BIGINT" javaType="java.lang.Long"/>
|
||||||
<association property="aspectQNameIds" resultMap="alfresco.node.result_AspectQNameIds"/>
|
<association property="aspectQNameIds" resultMap="alfresco.node.result_AspectQNameIds"/>
|
||||||
<!--
|
<!--
|
||||||
<result property="aspectQNameIds" column="qname_id" jdbcType="BIGINT" javaType="java.lang.Long"/>
|
<result property="aspectQNameIds" column="qname_id" jdbcType="BIGINT" javaType="java.lang.Long"/>
|
||||||
@@ -89,6 +90,7 @@
|
|||||||
</resultMap>
|
</resultMap>
|
||||||
<resultMap id="result_NodeProperty" type="NodeProperty">
|
<resultMap id="result_NodeProperty" type="NodeProperty">
|
||||||
<result property="nodeId" column="node_id" jdbcType="BIGINT" javaType="java.lang.Long"/>
|
<result property="nodeId" column="node_id" jdbcType="BIGINT" javaType="java.lang.Long"/>
|
||||||
|
<result property="nodeVersion" column="node_version" jdbcType="BIGINT" javaType="java.lang.Long"/>
|
||||||
<result property="key.qnameId" column="qname_id" jdbcType="BIGINT" javaType="java.lang.Long"/>
|
<result property="key.qnameId" column="qname_id" jdbcType="BIGINT" javaType="java.lang.Long"/>
|
||||||
<result property="key.localeId" column="locale_id" jdbcType="BIGINT" javaType="java.lang.Long"/>
|
<result property="key.localeId" column="locale_id" jdbcType="BIGINT" javaType="java.lang.Long"/>
|
||||||
<result property="key.listIndex" column="list_index" jdbcType="INTEGER" javaType="java.lang.Integer"/>
|
<result property="key.listIndex" column="list_index" jdbcType="INTEGER" javaType="java.lang.Integer"/>
|
||||||
@@ -720,7 +722,8 @@
|
|||||||
|
|
||||||
<sql id="select_NodeProperty_Results">
|
<sql id="select_NodeProperty_Results">
|
||||||
select
|
select
|
||||||
prop.node_id as node_id,
|
node.id as node_id,
|
||||||
|
node.version as node_version,
|
||||||
prop.qname_id as qname_id,
|
prop.qname_id as qname_id,
|
||||||
prop.locale_id as locale_id,
|
prop.locale_id as locale_id,
|
||||||
prop.list_index as list_index,
|
prop.list_index as list_index,
|
||||||
@@ -737,7 +740,8 @@
|
|||||||
<select id="select_NodeProperties" parameterType="NodeProperty" resultMap="result_NodeProperty">
|
<select id="select_NodeProperties" parameterType="NodeProperty" resultMap="result_NodeProperty">
|
||||||
<include refid="alfresco.node.select_NodeProperty_Results"/>
|
<include refid="alfresco.node.select_NodeProperty_Results"/>
|
||||||
from
|
from
|
||||||
alf_node_properties prop
|
alf_node node
|
||||||
|
join alf_node_properties prop on (prop.node_id = node.id)
|
||||||
<where>
|
<where>
|
||||||
<if test="nodeId != null">prop.node_id = #{nodeId}</if>
|
<if test="nodeId != null">prop.node_id = #{nodeId}</if>
|
||||||
<if test="nodeIds != null">
|
<if test="nodeIds != null">
|
||||||
@@ -759,7 +763,8 @@
|
|||||||
<select id="select_PropertiesByTypes" parameterType="Ids" resultMap="result_NodeProperty">
|
<select id="select_PropertiesByTypes" parameterType="Ids" resultMap="result_NodeProperty">
|
||||||
<include refid="alfresco.node.select_NodeProperty_Results"/>
|
<include refid="alfresco.node.select_NodeProperty_Results"/>
|
||||||
from
|
from
|
||||||
alf_node_properties prop
|
alf_node node
|
||||||
|
join alf_node_properties prop on (prop.node_id = node.id)
|
||||||
<where>
|
<where>
|
||||||
qname_id in
|
qname_id in
|
||||||
<foreach item="item" index="index" collection="ids" open="(" separator="," close=")">
|
<foreach item="item" index="index" collection="ids" open="(" separator="," close=")">
|
||||||
@@ -770,14 +775,16 @@
|
|||||||
|
|
||||||
<sql id="select_NodeAspects_Results">
|
<sql id="select_NodeAspects_Results">
|
||||||
select
|
select
|
||||||
aspects.node_id as node_id,
|
node.id as node_id,
|
||||||
|
node.version as node_version,
|
||||||
aspects.qname_id as qname_id
|
aspects.qname_id as qname_id
|
||||||
</sql>
|
</sql>
|
||||||
|
|
||||||
<select id="select_NodeAspects" parameterType="Ids" resultMap="result_NodeAspects">
|
<select id="select_NodeAspects" parameterType="Ids" resultMap="result_NodeAspects">
|
||||||
<include refid="alfresco.node.select_NodeAspects_Results"/>
|
<include refid="alfresco.node.select_NodeAspects_Results"/>
|
||||||
from
|
from
|
||||||
alf_node_aspects aspects
|
alf_node node
|
||||||
|
join alf_node_aspects aspects on (aspects.node_id = node.id)
|
||||||
<where>
|
<where>
|
||||||
<if test="nodeId != null">aspects.node_id = #{nodeId}</if>
|
<if test="nodeId != null">aspects.node_id = #{nodeId}</if>
|
||||||
<if test="nodeIds != null">
|
<if test="nodeIds != null">
|
||||||
@@ -786,15 +793,6 @@
|
|||||||
#{item}
|
#{item}
|
||||||
</foreach>
|
</foreach>
|
||||||
</if>
|
</if>
|
||||||
<!--
|
|
||||||
<if test="key != null and key.qnameId">and qname_id = #{key.qnameId}</if>
|
|
||||||
<if test="qnameIds">
|
|
||||||
and qname_id in
|
|
||||||
<foreach item="item" index="index" collection="qnameIds" open="(" separator="," close=")">
|
|
||||||
#{item}
|
|
||||||
</foreach>
|
|
||||||
</if>
|
|
||||||
-->
|
|
||||||
</where>
|
</where>
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
@@ -562,6 +562,9 @@ public abstract class AbstractNodeDAOImpl implements NodeDAO, BatchingDAO
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Returns a new transaction or an existing one if already active
|
||||||
|
*/
|
||||||
private TransactionEntity getCurrentTransaction()
|
private TransactionEntity getCurrentTransaction()
|
||||||
{
|
{
|
||||||
TransactionEntity txn = AlfrescoTransactionSupport.getResource(KEY_TRANSACTION);
|
TransactionEntity txn = AlfrescoTransactionSupport.getResource(KEY_TRANSACTION);
|
||||||
@@ -1216,6 +1219,9 @@ public abstract class AbstractNodeDAOImpl implements NodeDAO, BatchingDAO
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Need the child node's name here in case it gets removed
|
||||||
|
final String childNodeName = (String) getNodeProperty(childNodeId, ContentModel.PROP_NAME);
|
||||||
|
|
||||||
// First attempt to move the node, which may rollback to a savepoint
|
// First attempt to move the node, which may rollback to a savepoint
|
||||||
Node newChildNode = childNode;
|
Node newChildNode = childNode;
|
||||||
// Store
|
// Store
|
||||||
@@ -1281,11 +1287,7 @@ public abstract class AbstractNodeDAOImpl implements NodeDAO, BatchingDAO
|
|||||||
// Because we are retrying in-transaction i.e. absorbing exceptions, we need a Savepoint
|
// Because we are retrying in-transaction i.e. absorbing exceptions, we need a Savepoint
|
||||||
Savepoint savepoint = controlDAO.createSavepoint("DuplicateChildNodeNameException");
|
Savepoint savepoint = controlDAO.createSavepoint("DuplicateChildNodeNameException");
|
||||||
// We use the child node's UUID if there is no cm:name
|
// We use the child node's UUID if there is no cm:name
|
||||||
String childNodeName = (String) getNodeProperty(childNodeId, ContentModel.PROP_NAME);
|
String childNodeNameToUse = childNodeName == null ? childNode.getUuid() : childNodeName;
|
||||||
if (childNodeName == null)
|
|
||||||
{
|
|
||||||
childNodeName = childNode.getUuid();
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -1294,7 +1296,7 @@ public abstract class AbstractNodeDAOImpl implements NodeDAO, BatchingDAO
|
|||||||
newParentNodeId,
|
newParentNodeId,
|
||||||
assocTypeQName,
|
assocTypeQName,
|
||||||
assocQName,
|
assocQName,
|
||||||
childNodeName);
|
childNodeNameToUse);
|
||||||
controlDAO.releaseSavepoint(savepoint);
|
controlDAO.releaseSavepoint(savepoint);
|
||||||
return updated;
|
return updated;
|
||||||
}
|
}
|
||||||
@@ -1565,7 +1567,7 @@ public abstract class AbstractNodeDAOImpl implements NodeDAO, BatchingDAO
|
|||||||
Long optionalOldSharedAlcIdInAdditionToNull,
|
Long optionalOldSharedAlcIdInAdditionToNull,
|
||||||
Long newSharedAclId)
|
Long newSharedAclId)
|
||||||
{
|
{
|
||||||
Long txnId = getCurrentTransactionId();
|
Long txnId = getCurrentTransaction().getId();
|
||||||
updatePrimaryChildrenSharedAclId(
|
updatePrimaryChildrenSharedAclId(
|
||||||
txnId,
|
txnId,
|
||||||
primaryParentNodeId,
|
primaryParentNodeId,
|
||||||
@@ -2101,6 +2103,7 @@ public abstract class AbstractNodeDAOImpl implements NodeDAO, BatchingDAO
|
|||||||
throw new DataIntegrityViolationException("Invalid node ID: " + nodeId);
|
throw new DataIntegrityViolationException("Invalid node ID: " + nodeId);
|
||||||
}
|
}
|
||||||
Map<QName, Serializable> cachedProperties = cacheEntry.getSecond();
|
Map<QName, Serializable> cachedProperties = cacheEntry.getSecond();
|
||||||
|
// Need to return a harmlessly mutable map
|
||||||
Map<QName, Serializable> properties = copyPropertiesAgainstModification(cachedProperties);
|
Map<QName, Serializable> properties = copyPropertiesAgainstModification(cachedProperties);
|
||||||
// Done
|
// Done
|
||||||
return properties;
|
return properties;
|
||||||
@@ -2153,7 +2156,27 @@ public abstract class AbstractNodeDAOImpl implements NodeDAO, BatchingDAO
|
|||||||
|
|
||||||
public Pair<Long, Map<QName, Serializable>> findByKey(Long nodeId)
|
public Pair<Long, Map<QName, Serializable>> findByKey(Long nodeId)
|
||||||
{
|
{
|
||||||
Map<NodePropertyKey, NodePropertyValue> propsRaw = selectNodeProperties(nodeId);
|
NodeVersionKey nodeVersionKey = getNodeNotNull(nodeId).getNodeVersionKey();
|
||||||
|
Map<NodeVersionKey, Map<NodePropertyKey, NodePropertyValue>> propsRawByNodeVersionKey = selectNodeProperties(nodeId);
|
||||||
|
// Check the node Txn ID for mismatch
|
||||||
|
Map<NodePropertyKey, NodePropertyValue> propsRaw = propsRawByNodeVersionKey.get(nodeVersionKey);
|
||||||
|
if (propsRaw == null)
|
||||||
|
{
|
||||||
|
// Didn't find a match. Is this because there are none?
|
||||||
|
if (propsRawByNodeVersionKey.size() == 0)
|
||||||
|
{
|
||||||
|
// This is OK. The node has no properties
|
||||||
|
propsRaw = Collections.emptyMap();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// We found properties associated with a different node ID and txn
|
||||||
|
invalidateNodeCaches(nodeId);
|
||||||
|
throw new DataIntegrityViolationException(
|
||||||
|
"Detected stale node entry: " + nodeVersionKey +
|
||||||
|
" (now " + propsRawByNodeVersionKey.keySet() + ")");
|
||||||
|
}
|
||||||
|
}
|
||||||
// Convert to public properties
|
// Convert to public properties
|
||||||
Map<QName, Serializable> props = nodePropertyHelper.convertToPublicProperties(propsRaw);
|
Map<QName, Serializable> props = nodePropertyHelper.convertToPublicProperties(propsRaw);
|
||||||
// Done
|
// Done
|
||||||
@@ -2351,9 +2374,27 @@ public abstract class AbstractNodeDAOImpl implements NodeDAO, BatchingDAO
|
|||||||
|
|
||||||
public Pair<Long, Set<QName>> findByKey(Long nodeId)
|
public Pair<Long, Set<QName>> findByKey(Long nodeId)
|
||||||
{
|
{
|
||||||
Set<Long> nodeAspectQNameIds = selectNodeAspectIds(nodeId);
|
NodeVersionKey nodeVersionKey = getNodeNotNull(nodeId).getNodeVersionKey();
|
||||||
// Convert to QNames
|
Set<Long> nodeIds = Collections.singleton(nodeId);
|
||||||
Set<QName> nodeAspectQNames = qnameDAO.convertIdsToQNames(nodeAspectQNameIds);
|
Map<NodeVersionKey, Set<QName>> nodeAspectQNameIdsByVersionKey = selectNodeAspects(nodeIds);
|
||||||
|
Set<QName> nodeAspectQNames = nodeAspectQNameIdsByVersionKey.get(nodeVersionKey);
|
||||||
|
if (nodeAspectQNames == null)
|
||||||
|
{
|
||||||
|
// Didn't find a match. Is this because there are none?
|
||||||
|
if (nodeAspectQNameIdsByVersionKey.size() == 0)
|
||||||
|
{
|
||||||
|
// This is OK. The node has no properties
|
||||||
|
nodeAspectQNames = Collections.emptySet();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// We found properties associated with a different node ID and txn
|
||||||
|
invalidateNodeCaches(nodeId);
|
||||||
|
throw new DataIntegrityViolationException(
|
||||||
|
"Detected stale node entry: " + nodeVersionKey +
|
||||||
|
" (now " + nodeAspectQNameIdsByVersionKey.keySet() + ")");
|
||||||
|
}
|
||||||
|
}
|
||||||
// Done
|
// Done
|
||||||
return new Pair<Long, Set<QName>>(nodeId, Collections.unmodifiableSet(nodeAspectQNames));
|
return new Pair<Long, Set<QName>>(nodeId, Collections.unmodifiableSet(nodeAspectQNames));
|
||||||
}
|
}
|
||||||
@@ -3619,9 +3660,11 @@ public abstract class AbstractNodeDAOImpl implements NodeDAO, BatchingDAO
|
|||||||
// Get the nodes
|
// Get the nodes
|
||||||
SortedSet<Long> aspectNodeIds = new TreeSet<Long>();
|
SortedSet<Long> aspectNodeIds = new TreeSet<Long>();
|
||||||
SortedSet<Long> propertiesNodeIds = new TreeSet<Long>();
|
SortedSet<Long> propertiesNodeIds = new TreeSet<Long>();
|
||||||
|
Map<Long, NodeVersionKey> nodeVersionKeysFromCache = new HashMap<Long, NodeVersionKey>(nodes.size()*2); // Keep for quick lookup
|
||||||
for (Node node : nodes)
|
for (Node node : nodes)
|
||||||
{
|
{
|
||||||
Long nodeId = node.getId();
|
Long nodeId = node.getId();
|
||||||
|
NodeVersionKey nodeVersionKey = node.getNodeVersionKey();
|
||||||
nodesCache.setValue(nodeId, node);
|
nodesCache.setValue(nodeId, node);
|
||||||
if (propertiesCache.getValue(nodeId) == null)
|
if (propertiesCache.getValue(nodeId) == null)
|
||||||
{
|
{
|
||||||
@@ -3631,6 +3674,7 @@ public abstract class AbstractNodeDAOImpl implements NodeDAO, BatchingDAO
|
|||||||
{
|
{
|
||||||
aspectNodeIds.add(nodeId);
|
aspectNodeIds.add(nodeId);
|
||||||
}
|
}
|
||||||
|
nodeVersionKeysFromCache.put(nodeId, nodeVersionKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(logger.isDebugEnabled())
|
if(logger.isDebugEnabled())
|
||||||
@@ -3639,14 +3683,13 @@ public abstract class AbstractNodeDAOImpl implements NodeDAO, BatchingDAO
|
|||||||
logger.debug("Pre-loaded " + propertiesNodeIds.size() + " aspects");
|
logger.debug("Pre-loaded " + propertiesNodeIds.size() + " aspects");
|
||||||
}
|
}
|
||||||
|
|
||||||
List<NodeAspectsEntity> nodeAspects = selectNodeAspects(aspectNodeIds);
|
Map<NodeVersionKey, Set<QName>> nodeAspects = selectNodeAspects(aspectNodeIds);
|
||||||
for (NodeAspectsEntity nodeAspect : nodeAspects)
|
for (Map.Entry<NodeVersionKey, Set<QName>> entry : nodeAspects.entrySet())
|
||||||
{
|
{
|
||||||
Long nodeId = nodeAspect.getNodeId();
|
NodeVersionKey nodeVersionKeyFromDb = entry.getKey();
|
||||||
List<Long> qnameIds = nodeAspect.getAspectQNameIds();
|
Long nodeId = nodeVersionKeyFromDb.getNodeId();
|
||||||
HashSet<Long> qnameIdsSet = new HashSet<Long>(qnameIds);
|
Set<QName> qnames = entry.getValue();
|
||||||
Set<QName> qnames = qnameDAO.convertIdsToQNames(qnameIdsSet);
|
setNodeAspectsCached(nodeId, qnames);
|
||||||
aspectsCache.setValue(nodeId, qnames);
|
|
||||||
aspectNodeIds.remove(nodeId);
|
aspectNodeIds.remove(nodeId);
|
||||||
}
|
}
|
||||||
// Cache the absence of aspects too!
|
// Cache the absence of aspects too!
|
||||||
@@ -3655,13 +3698,13 @@ public abstract class AbstractNodeDAOImpl implements NodeDAO, BatchingDAO
|
|||||||
aspectsCache.setValue(nodeId, Collections.<QName>emptySet());
|
aspectsCache.setValue(nodeId, Collections.<QName>emptySet());
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<Long, Map<NodePropertyKey, NodePropertyValue>> propsByNodeId = selectNodeProperties(propertiesNodeIds);
|
Map<NodeVersionKey, Map<NodePropertyKey, NodePropertyValue>> propsByNodeId = selectNodeProperties(propertiesNodeIds);
|
||||||
for (Map.Entry<Long, Map<NodePropertyKey, NodePropertyValue>> entry : propsByNodeId.entrySet())
|
for (Map.Entry<NodeVersionKey, Map<NodePropertyKey, NodePropertyValue>> entry : propsByNodeId.entrySet())
|
||||||
{
|
{
|
||||||
Long nodeId = entry.getKey();
|
Long nodeId = entry.getKey().getNodeId();
|
||||||
Map<NodePropertyKey, NodePropertyValue> propertyValues = entry.getValue();
|
Map<NodePropertyKey, NodePropertyValue> propertyValues = entry.getValue();
|
||||||
Map<QName, Serializable> props = nodePropertyHelper.convertToPublicProperties(propertyValues);
|
Map<QName, Serializable> props = nodePropertyHelper.convertToPublicProperties(propertyValues);
|
||||||
propertiesCache.setValue(nodeId, props);
|
setNodePropertiesCached(nodeId, props);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3847,14 +3890,13 @@ public abstract class AbstractNodeDAOImpl implements NodeDAO, BatchingDAO
|
|||||||
protected abstract NodeEntity selectNodeByNodeRef(NodeRef nodeRef, Boolean deleted);
|
protected abstract NodeEntity selectNodeByNodeRef(NodeRef nodeRef, Boolean deleted);
|
||||||
protected abstract List<Node> selectNodesByUuids(Long storeId, SortedSet<String> uuids);
|
protected abstract List<Node> selectNodesByUuids(Long storeId, SortedSet<String> uuids);
|
||||||
protected abstract List<Node> selectNodesByIds(SortedSet<Long> ids);
|
protected abstract List<Node> selectNodesByIds(SortedSet<Long> ids);
|
||||||
protected abstract Map<Long, Map<NodePropertyKey, NodePropertyValue>> selectNodeProperties(Set<Long> nodeIds);
|
protected abstract Map<NodeVersionKey, Map<NodePropertyKey, NodePropertyValue>> selectNodeProperties(Set<Long> nodeIds);
|
||||||
protected abstract List<NodeAspectsEntity> selectNodeAspects(Set<Long> nodeIds);
|
protected abstract Map<NodeVersionKey, Map<NodePropertyKey, NodePropertyValue>> selectNodeProperties(Long nodeId);
|
||||||
protected abstract Map<NodePropertyKey, NodePropertyValue> selectNodeProperties(Long nodeId);
|
protected abstract Map<NodeVersionKey, Map<NodePropertyKey, NodePropertyValue>> selectNodeProperties(Long nodeId, Set<Long> qnameIds);
|
||||||
protected abstract Map<NodePropertyKey, NodePropertyValue> selectNodeProperties(Long nodeId, Set<Long> qnameIds);
|
|
||||||
protected abstract int deleteNodeProperties(Long nodeId, Set<Long> qnameIds);
|
protected abstract int deleteNodeProperties(Long nodeId, Set<Long> qnameIds);
|
||||||
protected abstract int deleteNodeProperties(Long nodeId, List<NodePropertyKey> propKeys);
|
protected abstract int deleteNodeProperties(Long nodeId, List<NodePropertyKey> propKeys);
|
||||||
protected abstract void insertNodeProperties(Long nodeId, Map<NodePropertyKey, NodePropertyValue> persistableProps);
|
protected abstract void insertNodeProperties(Long nodeId, Map<NodePropertyKey, NodePropertyValue> persistableProps);
|
||||||
protected abstract Set<Long> selectNodeAspectIds(Long nodeId);
|
protected abstract Map<NodeVersionKey, Set<QName>> selectNodeAspects(Set<Long> nodeIds);
|
||||||
protected abstract void insertNodeAspect(Long nodeId, Long qnameId);
|
protected abstract void insertNodeAspect(Long nodeId, Long qnameId);
|
||||||
protected abstract int deleteNodeAspects(Long nodeId, Set<Long> qnameIds);
|
protected abstract int deleteNodeAspects(Long nodeId, Set<Long> qnameIds);
|
||||||
protected abstract void selectNodesWithAspects(
|
protected abstract void selectNodesWithAspects(
|
||||||
|
@@ -28,6 +28,11 @@ import org.alfresco.util.Pair;
|
|||||||
*/
|
*/
|
||||||
public interface Node extends NodeIdAndAclId
|
public interface Node extends NodeIdAndAclId
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* Helper method to get a key that includes the node and its current version number
|
||||||
|
*/
|
||||||
|
public NodeVersionKey getNodeVersionKey();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper method to force the instance to be read-only
|
* Helper method to force the instance to be read-only
|
||||||
*/
|
*/
|
||||||
|
@@ -29,6 +29,7 @@ import java.util.List;
|
|||||||
public class NodeAspectsEntity
|
public class NodeAspectsEntity
|
||||||
{
|
{
|
||||||
private Long nodeId;
|
private Long nodeId;
|
||||||
|
private Long nodeVersion;
|
||||||
private List<Long> aspectQNameIds;
|
private List<Long> aspectQNameIds;
|
||||||
|
|
||||||
/** Carries data for queries */
|
/** Carries data for queries */
|
||||||
@@ -47,6 +48,7 @@ public class NodeAspectsEntity
|
|||||||
StringBuilder sb = new StringBuilder(512);
|
StringBuilder sb = new StringBuilder(512);
|
||||||
sb.append("NodeAspectsEntity")
|
sb.append("NodeAspectsEntity")
|
||||||
.append(", nodeId=").append(nodeId)
|
.append(", nodeId=").append(nodeId)
|
||||||
|
.append(", nodeVersion=").append(nodeVersion)
|
||||||
.append(", aspects=").append(aspectQNameIds)
|
.append(", aspects=").append(aspectQNameIds)
|
||||||
.append("]");
|
.append("]");
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
@@ -62,6 +64,16 @@ public class NodeAspectsEntity
|
|||||||
this.nodeId = nodeId;
|
this.nodeId = nodeId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Long getNodeVersion()
|
||||||
|
{
|
||||||
|
return nodeVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNodeVersion(Long nodeVersion)
|
||||||
|
{
|
||||||
|
this.nodeVersion = nodeVersion;
|
||||||
|
}
|
||||||
|
|
||||||
public List<Long> getAspectQNameIds()
|
public List<Long> getAspectQNameIds()
|
||||||
{
|
{
|
||||||
return aspectQNameIds;
|
return aspectQNameIds;
|
||||||
|
@@ -105,6 +105,17 @@ public class NodeEntity implements Node, PermissionCheckValue
|
|||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
// TODO: Must cache the key
|
||||||
|
public NodeVersionKey getNodeVersionKey()
|
||||||
|
{
|
||||||
|
if (id == null || version == null)
|
||||||
|
{
|
||||||
|
throw new IllegalStateException("The NodeEntity has not be filled: " + this);
|
||||||
|
}
|
||||||
|
return new NodeVersionKey(id, version);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Lock the entity against further updates to prevent accidental modification
|
* Lock the entity against further updates to prevent accidental modification
|
||||||
*/
|
*/
|
||||||
@@ -125,8 +136,9 @@ public class NodeEntity implements Node, PermissionCheckValue
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void incrementVersion()
|
public synchronized void incrementVersion()
|
||||||
{
|
{
|
||||||
|
checkLock();
|
||||||
if (version >= Short.MAX_VALUE)
|
if (version >= Short.MAX_VALUE)
|
||||||
{
|
{
|
||||||
this.version = 0L;
|
this.version = 0L;
|
||||||
@@ -162,7 +174,7 @@ public class NodeEntity implements Node, PermissionCheckValue
|
|||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setId(Long id)
|
public synchronized void setId(Long id)
|
||||||
{
|
{
|
||||||
checkLock();
|
checkLock();
|
||||||
this.id = id;
|
this.id = id;
|
||||||
@@ -174,7 +186,7 @@ public class NodeEntity implements Node, PermissionCheckValue
|
|||||||
return version;
|
return version;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setVersion(Long version)
|
public synchronized void setVersion(Long version)
|
||||||
{
|
{
|
||||||
checkLock();
|
checkLock();
|
||||||
this.version = version;
|
this.version = version;
|
||||||
@@ -186,7 +198,7 @@ public class NodeEntity implements Node, PermissionCheckValue
|
|||||||
return store;
|
return store;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setStore(StoreEntity store)
|
public synchronized void setStore(StoreEntity store)
|
||||||
{
|
{
|
||||||
checkLock();
|
checkLock();
|
||||||
this.store = store;
|
this.store = store;
|
||||||
@@ -198,7 +210,7 @@ public class NodeEntity implements Node, PermissionCheckValue
|
|||||||
return uuid;
|
return uuid;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setUuid(String uuid)
|
public synchronized void setUuid(String uuid)
|
||||||
{
|
{
|
||||||
checkLock();
|
checkLock();
|
||||||
this.uuid = uuid;
|
this.uuid = uuid;
|
||||||
@@ -210,7 +222,7 @@ public class NodeEntity implements Node, PermissionCheckValue
|
|||||||
return typeQNameId;
|
return typeQNameId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setTypeQNameId(Long typeQNameId)
|
public synchronized void setTypeQNameId(Long typeQNameId)
|
||||||
{
|
{
|
||||||
checkLock();
|
checkLock();
|
||||||
this.typeQNameId = typeQNameId;
|
this.typeQNameId = typeQNameId;
|
||||||
@@ -222,7 +234,7 @@ public class NodeEntity implements Node, PermissionCheckValue
|
|||||||
return localeId;
|
return localeId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setLocaleId(Long localeId)
|
public synchronized void setLocaleId(Long localeId)
|
||||||
{
|
{
|
||||||
this.localeId = localeId;
|
this.localeId = localeId;
|
||||||
}
|
}
|
||||||
@@ -233,7 +245,7 @@ public class NodeEntity implements Node, PermissionCheckValue
|
|||||||
return aclId;
|
return aclId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setAclId(Long aclId)
|
public synchronized void setAclId(Long aclId)
|
||||||
{
|
{
|
||||||
checkLock();
|
checkLock();
|
||||||
this.aclId = aclId;
|
this.aclId = aclId;
|
||||||
@@ -245,7 +257,7 @@ public class NodeEntity implements Node, PermissionCheckValue
|
|||||||
return deleted;
|
return deleted;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setDeleted(Boolean deleted)
|
public synchronized void setDeleted(Boolean deleted)
|
||||||
{
|
{
|
||||||
checkLock();
|
checkLock();
|
||||||
this.deleted = deleted;
|
this.deleted = deleted;
|
||||||
@@ -257,7 +269,7 @@ public class NodeEntity implements Node, PermissionCheckValue
|
|||||||
return transaction;
|
return transaction;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setTransaction(TransactionEntity transaction)
|
public synchronized void setTransaction(TransactionEntity transaction)
|
||||||
{
|
{
|
||||||
checkLock();
|
checkLock();
|
||||||
this.transaction = transaction;
|
this.transaction = transaction;
|
||||||
@@ -269,7 +281,7 @@ public class NodeEntity implements Node, PermissionCheckValue
|
|||||||
return auditableProperties;
|
return auditableProperties;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setAuditableProperties(AuditablePropertiesEntity auditableProperties)
|
public synchronized void setAuditableProperties(AuditablePropertiesEntity auditableProperties)
|
||||||
{
|
{
|
||||||
checkLock();
|
checkLock();
|
||||||
this.auditableProperties = auditableProperties;
|
this.auditableProperties = auditableProperties;
|
||||||
|
@@ -29,6 +29,7 @@ import java.util.List;
|
|||||||
public class NodePropertyEntity
|
public class NodePropertyEntity
|
||||||
{
|
{
|
||||||
private Long nodeId;
|
private Long nodeId;
|
||||||
|
private Long nodeVersion;
|
||||||
private NodePropertyKey key;
|
private NodePropertyKey key;
|
||||||
private NodePropertyValue value;
|
private NodePropertyValue value;
|
||||||
/** Carries data for queries and updates */
|
/** Carries data for queries and updates */
|
||||||
@@ -46,7 +47,7 @@ public class NodePropertyEntity
|
|||||||
@Override
|
@Override
|
||||||
public String toString()
|
public String toString()
|
||||||
{
|
{
|
||||||
return "NodePropertyEntity [node=" + nodeId + ", key=" + key + ", value=" + value + "]";
|
return "NodePropertyEntity [node=" + nodeId + ", nodeVersion=" + nodeVersion + ", key=" + key + ", value=" + value + "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
public Long getNodeId()
|
public Long getNodeId()
|
||||||
@@ -59,6 +60,16 @@ public class NodePropertyEntity
|
|||||||
this.nodeId = nodeId;
|
this.nodeId = nodeId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Long getNodeVersion()
|
||||||
|
{
|
||||||
|
return nodeVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNodeVersion(Long nodeVersion)
|
||||||
|
{
|
||||||
|
this.nodeVersion = nodeVersion;
|
||||||
|
}
|
||||||
|
|
||||||
public NodePropertyKey getKey()
|
public NodePropertyKey getKey()
|
||||||
{
|
{
|
||||||
return key;
|
return key;
|
||||||
|
@@ -0,0 +1,89 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2005-2010 Alfresco Software Limited.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
* As a special exception to the terms and conditions of version 2.0 of
|
||||||
|
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||||
|
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||||
|
* FLOSS exception. You should have recieved a copy of the text describing
|
||||||
|
* the FLOSS exception, and it is also available here:
|
||||||
|
* http://www.alfresco.com/legal/licensing"
|
||||||
|
*/
|
||||||
|
package org.alfresco.repo.domain.node;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Key for caches that need to be bound implicitly to the current version of a node.
|
||||||
|
*
|
||||||
|
* @author Derek Hulley
|
||||||
|
* @since 4.0
|
||||||
|
*/
|
||||||
|
public class NodeVersionKey implements Serializable
|
||||||
|
{
|
||||||
|
private static final long serialVersionUID = 2241045540959490539L;
|
||||||
|
|
||||||
|
private final Long nodeId;
|
||||||
|
private final Long version;
|
||||||
|
|
||||||
|
public NodeVersionKey(Long nodeId, Long version)
|
||||||
|
{
|
||||||
|
this.nodeId = nodeId;
|
||||||
|
this.version = version;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object other)
|
||||||
|
{
|
||||||
|
if (this == other)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!(other instanceof NodeVersionKey))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
NodeVersionKey o = (NodeVersionKey)other;
|
||||||
|
return nodeId.equals(o.nodeId) && version.equals(o.version);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode()
|
||||||
|
{
|
||||||
|
return nodeId.hashCode() + version.hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
StringBuilder builder = new StringBuilder();
|
||||||
|
builder.append("NodeVersionKey ")
|
||||||
|
.append("[nodeId=").append(nodeId)
|
||||||
|
.append(", version=").append(version)
|
||||||
|
.append("]");
|
||||||
|
return builder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getNodeId()
|
||||||
|
{
|
||||||
|
return nodeId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getVersion()
|
||||||
|
{
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
}
|
@@ -42,6 +42,7 @@ import org.alfresco.repo.domain.node.NodePropertyEntity;
|
|||||||
import org.alfresco.repo.domain.node.NodePropertyKey;
|
import org.alfresco.repo.domain.node.NodePropertyKey;
|
||||||
import org.alfresco.repo.domain.node.NodePropertyValue;
|
import org.alfresco.repo.domain.node.NodePropertyValue;
|
||||||
import org.alfresco.repo.domain.node.NodeUpdateEntity;
|
import org.alfresco.repo.domain.node.NodeUpdateEntity;
|
||||||
|
import org.alfresco.repo.domain.node.NodeVersionKey;
|
||||||
import org.alfresco.repo.domain.node.PrimaryChildrenAclUpdateEntity;
|
import org.alfresco.repo.domain.node.PrimaryChildrenAclUpdateEntity;
|
||||||
import org.alfresco.repo.domain.node.ServerEntity;
|
import org.alfresco.repo.domain.node.ServerEntity;
|
||||||
import org.alfresco.repo.domain.node.StoreEntity;
|
import org.alfresco.repo.domain.node.StoreEntity;
|
||||||
@@ -418,21 +419,23 @@ public class NodeDAOImpl extends AbstractNodeDAOImpl
|
|||||||
/**
|
/**
|
||||||
* Pull out the key-value pairs from the rows
|
* Pull out the key-value pairs from the rows
|
||||||
*/
|
*/
|
||||||
private Map<Long, Map<NodePropertyKey, NodePropertyValue>> makePersistentPropertiesMap(List<NodePropertyEntity> rows)
|
private Map<NodeVersionKey, Map<NodePropertyKey, NodePropertyValue>> makePersistentPropertiesMap(List<NodePropertyEntity> rows)
|
||||||
{
|
{
|
||||||
Map<Long, Map<NodePropertyKey, NodePropertyValue>> results = new HashMap<Long, Map<NodePropertyKey, NodePropertyValue>>(3);
|
Map<NodeVersionKey, Map<NodePropertyKey, NodePropertyValue>> results = new HashMap<NodeVersionKey, Map<NodePropertyKey, NodePropertyValue>>(3);
|
||||||
for (NodePropertyEntity row : rows)
|
for (NodePropertyEntity row : rows)
|
||||||
{
|
{
|
||||||
Long nodeId = row.getNodeId();
|
Long nodeId = row.getNodeId();
|
||||||
if (nodeId == null)
|
Long nodeVersion = row.getNodeVersion();
|
||||||
|
if (nodeId == null || nodeVersion == null)
|
||||||
{
|
{
|
||||||
throw new RuntimeException("Expect results with a Node ID: " + row);
|
throw new RuntimeException("Expect results with a Node and Version: " + row);
|
||||||
}
|
}
|
||||||
Map<NodePropertyKey, NodePropertyValue> props = results.get(nodeId);
|
NodeVersionKey nodeTxnKey = new NodeVersionKey(nodeId, nodeVersion);
|
||||||
|
Map<NodePropertyKey, NodePropertyValue> props = results.get(nodeTxnKey);
|
||||||
if (props == null)
|
if (props == null)
|
||||||
{
|
{
|
||||||
props = new HashMap<NodePropertyKey, NodePropertyValue>(17);
|
props = new HashMap<NodePropertyKey, NodePropertyValue>(17);
|
||||||
results.put(nodeId, props);
|
results.put(nodeTxnKey, props);
|
||||||
}
|
}
|
||||||
props.put(row.getKey(), row.getValue());
|
props.put(row.getKey(), row.getValue());
|
||||||
}
|
}
|
||||||
@@ -460,22 +463,7 @@ public class NodeDAOImpl extends AbstractNodeDAOImpl
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
protected List<NodeAspectsEntity> selectNodeAspects(Set<Long> nodeIds)
|
protected Map<NodeVersionKey, Map<NodePropertyKey, NodePropertyValue>> selectNodeProperties(Set<Long> nodeIds)
|
||||||
{
|
|
||||||
if (nodeIds.size() == 0)
|
|
||||||
{
|
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
|
||||||
NodeAspectsEntity aspects = new NodeAspectsEntity();
|
|
||||||
aspects.setNodeIds(new ArrayList<Long>(nodeIds));
|
|
||||||
|
|
||||||
List<NodeAspectsEntity> rows = (List<NodeAspectsEntity>) template.selectList(SELECT_NODE_ASPECTS, aspects);
|
|
||||||
return rows;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
protected Map<Long, Map<NodePropertyKey, NodePropertyValue>> selectNodeProperties(Set<Long> nodeIds)
|
|
||||||
{
|
{
|
||||||
if (nodeIds.size() == 0)
|
if (nodeIds.size() == 0)
|
||||||
{
|
{
|
||||||
@@ -488,13 +476,13 @@ public class NodeDAOImpl extends AbstractNodeDAOImpl
|
|||||||
return makePersistentPropertiesMap(rows);
|
return makePersistentPropertiesMap(rows);
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
protected Map<NodePropertyKey, NodePropertyValue> selectNodeProperties(Long nodeId)
|
protected Map<NodeVersionKey, Map<NodePropertyKey, NodePropertyValue>> selectNodeProperties(Long nodeId)
|
||||||
{
|
{
|
||||||
return selectNodeProperties(nodeId, Collections.<Long>emptySet());
|
return selectNodeProperties(nodeId, Collections.<Long>emptySet());
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
protected Map<NodePropertyKey, NodePropertyValue> selectNodeProperties(Long nodeId, Set<Long> qnameIds)
|
protected Map<NodeVersionKey, Map<NodePropertyKey, NodePropertyValue>> selectNodeProperties(Long nodeId, Set<Long> qnameIds)
|
||||||
{
|
{
|
||||||
NodePropertyEntity prop = new NodePropertyEntity();
|
NodePropertyEntity prop = new NodePropertyEntity();
|
||||||
// Node
|
// Node
|
||||||
@@ -514,16 +502,7 @@ public class NodeDAOImpl extends AbstractNodeDAOImpl
|
|||||||
}
|
}
|
||||||
|
|
||||||
List<NodePropertyEntity> rows = (List<NodePropertyEntity>) template.selectList(SELECT_NODE_PROPERTIES, prop);
|
List<NodePropertyEntity> rows = (List<NodePropertyEntity>) template.selectList(SELECT_NODE_PROPERTIES, prop);
|
||||||
Map<Long, Map<NodePropertyKey, NodePropertyValue>> results = makePersistentPropertiesMap(rows);
|
return makePersistentPropertiesMap(rows);
|
||||||
Map<NodePropertyKey, NodePropertyValue> props = results.get(nodeId);
|
|
||||||
if (props == null)
|
|
||||||
{
|
|
||||||
return Collections.emptyMap();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return props;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -601,19 +580,34 @@ public class NodeDAOImpl extends AbstractNodeDAOImpl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
@Override
|
@Override
|
||||||
protected Set<Long> selectNodeAspectIds(Long nodeId)
|
protected Map<NodeVersionKey, Set<QName>> selectNodeAspects(Set<Long> nodeIds)
|
||||||
{
|
{
|
||||||
Set<Long> aspectIds = new HashSet<Long>();
|
if (nodeIds.size() == 0)
|
||||||
Set<Long> nodeIds = new HashSet<Long>();
|
|
||||||
nodeIds.add(nodeId);
|
|
||||||
List<NodeAspectsEntity> nodeAspectEntities = selectNodeAspects(nodeIds);
|
|
||||||
if(nodeAspectEntities.size() > 0)
|
|
||||||
{
|
{
|
||||||
NodeAspectsEntity nodeAspects = nodeAspectEntities.get(0);
|
return Collections.emptyMap();
|
||||||
aspectIds.addAll(nodeAspects.getAspectQNameIds());
|
|
||||||
}
|
}
|
||||||
return aspectIds;
|
NodeAspectsEntity aspects = new NodeAspectsEntity();
|
||||||
|
aspects.setNodeIds(new ArrayList<Long>(nodeIds));
|
||||||
|
|
||||||
|
List<NodeAspectsEntity> rows = (List<NodeAspectsEntity>) template.selectList(SELECT_NODE_ASPECTS, aspects);
|
||||||
|
|
||||||
|
Map<NodeVersionKey, Set<QName>> results = new HashMap<NodeVersionKey, Set<QName>>(rows.size()*2);
|
||||||
|
for (NodeAspectsEntity nodeAspectsEntity : rows)
|
||||||
|
{
|
||||||
|
Long nodeId = nodeAspectsEntity.getNodeId();
|
||||||
|
Long nodeVersion = nodeAspectsEntity.getNodeVersion();
|
||||||
|
NodeVersionKey nodeVersionKey = new NodeVersionKey(nodeId, nodeVersion);
|
||||||
|
if (results.containsKey(nodeVersionKey))
|
||||||
|
{
|
||||||
|
throw new IllegalStateException("Found existing key while querying for node aspects: " + nodeIds);
|
||||||
|
}
|
||||||
|
Set<Long> aspectIds = new HashSet<Long>(nodeAspectsEntity.getAspectQNameIds());
|
||||||
|
Set<QName> aspectQNames = qnameDAO.convertIdsToQNames(aspectIds);
|
||||||
|
results.put(nodeVersionKey, aspectQNames);
|
||||||
|
}
|
||||||
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
Reference in New Issue
Block a user