getOrCreatePropertyValue(Serializable value);
+ /**
+ * alf_prop_value accessor: find or create a property based on the value.
+ * Note: This method will not recurse into maps or collections. Use the
+ * dedicated methods if you want recursion; otherwise maps and collections will
+ * be serialized and probably stored as BLOB values.
+ *
+ * Max depth examples (there is no upper limit):
+ *
+ * - 0: don't expand the value if it's a map or collection
+ * - 1: open the value up if it is a map or collection but don't do any more
+ * - ...
+ * - 10: open up 10 levels of maps or collections
+ *
+ * All collections that are not opened up will be serialized unless there is a
+ * custom {@link PropertyTypeConverter converter} which can serialize it in an
+ * alternative format.
+ *
+ * @param value the value to find the ID for (may be null)
+ * @param maxDepth the maximum depth of collections and maps to iterate into
+ */
+ Pair getOrCreatePropertyValue(Serializable value, int maxDepth);
}
diff --git a/source/java/org/alfresco/repo/domain/propval/PropertyValueDAOTest.java b/source/java/org/alfresco/repo/domain/propval/PropertyValueDAOTest.java
index 323622fd9b..abe28a8d57 100644
--- a/source/java/org/alfresco/repo/domain/propval/PropertyValueDAOTest.java
+++ b/source/java/org/alfresco/repo/domain/propval/PropertyValueDAOTest.java
@@ -25,7 +25,10 @@
package org.alfresco.repo.domain.propval;
import java.io.Serializable;
+import java.util.ArrayList;
import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
import java.util.Random;
import junit.framework.TestCase;
@@ -344,6 +347,71 @@ public class PropertyValueDAOTest extends TestCase
}
}
+ public void testPropertyValue_MapOfStrings() throws Exception
+ {
+ final HashMap map = new HashMap(15);
+ for (int i = 0; i < 20; i++)
+ {
+ String key = "MAP-KEY-" + i;
+ String value = "MAP-VALUE-" + i;
+ map.put(key, value);
+ }
+ RetryingTransactionCallback createCallback = new RetryingTransactionCallback()
+ {
+ public Void execute() throws Throwable
+ {
+ propertyValueDAO.getOrCreatePropertyValue(map);
+ return null;
+ }
+ };
+ transactionService.getRetryingTransactionHelper().doInTransaction(createCallback);
+ }
+
+ public void testPropertyValue_MapOfMapOfStrings() throws Exception
+ {
+ final HashMap mapInner = new HashMap(15);
+ for (int i = 0; i < 20; i++)
+ {
+ String key = "INNERMAP-KEY-" + i;
+ String value = "INNERMAP-VALUE-" + i;
+ mapInner.put(key, value);
+ }
+ final HashMap> mapOuter = new HashMap>(37);
+ for (int i = 0; i < 2; i++)
+ {
+ String key = "OUTERMAP-KEY-" + i;
+ mapOuter.put(key, mapInner);
+ }
+ RetryingTransactionCallback createCallback = new RetryingTransactionCallback()
+ {
+ public Void execute() throws Throwable
+ {
+ propertyValueDAO.getOrCreatePropertyValue(mapOuter);
+ return null;
+ }
+ };
+ transactionService.getRetryingTransactionHelper().doInTransaction(createCallback);
+ }
+
+ public void testPropertyValue_CollectionOfStrings() throws Exception
+ {
+ final ArrayList list = new ArrayList(20);
+ for (int i = 0; i < 20; i++)
+ {
+ String value = "COLL-VALUE-" + i;
+ list.add(value);
+ }
+ RetryingTransactionCallback createCallback = new RetryingTransactionCallback()
+ {
+ public Void execute() throws Throwable
+ {
+ propertyValueDAO.getOrCreatePropertyValue(list);
+ return null;
+ }
+ };
+ transactionService.getRetryingTransactionHelper().doInTransaction(createCallback);
+ }
+
private void removeCaches()
{
((AbstractPropertyValueDAOImpl)propertyValueDAO).setPropertyClassCache(null);
diff --git a/source/java/org/alfresco/repo/domain/propval/PropertyValueEntity.java b/source/java/org/alfresco/repo/domain/propval/PropertyValueEntity.java
index 553a317974..7e19279a5d 100644
--- a/source/java/org/alfresco/repo/domain/propval/PropertyValueEntity.java
+++ b/source/java/org/alfresco/repo/domain/propval/PropertyValueEntity.java
@@ -25,6 +25,7 @@
package org.alfresco.repo.domain.propval;
import java.io.Serializable;
+import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
@@ -55,6 +56,8 @@ public class PropertyValueEntity
public static final Short ORDINAL_DOUBLE = 2;
public static final Short ORDINAL_STRING = 3;
public static final Short ORDINAL_SERIALIZABLE = 4;
+ public static final Short ORDINAL_MAP = 5;
+ public static final Short ORDINAL_COLLECTION = 6;
/**
* Enumeration of persisted types for alf_prop_value.persisted_type.
@@ -131,6 +134,32 @@ public class PropertyValueEntity
{
return Serializable.class;
}
+ },
+ MAP
+ {
+ @Override
+ public Short getOrdinalNumber()
+ {
+ return ORDINAL_MAP;
+ }
+ @Override
+ public Class> getAssociatedClass()
+ {
+ return Map.class;
+ }
+ },
+ COLLECTION
+ {
+ @Override
+ public Short getOrdinalNumber()
+ {
+ return ORDINAL_COLLECTION;
+ }
+ @Override
+ public Class> getAssociatedClass()
+ {
+ return Collection.class;
+ }
};
/**
@@ -182,6 +211,8 @@ public class PropertyValueEntity
mapClass.put(Double.class, PersistedType.DOUBLE);
mapClass.put(String.class, PersistedType.STRING);
mapClass.put(Date.class, PersistedType.LONG);
+ mapClass.put(Map.class, PersistedType.SERIALIZABLE); // Will be serialized if encountered
+ mapClass.put(Collection.class, PersistedType.SERIALIZABLE); // Will be serialized if encountered
persistedTypesByClass = Collections.unmodifiableMap(mapClass);
}
@@ -250,18 +281,20 @@ public class PropertyValueEntity
{
switch (persistedTypeEnum)
{
- case NULL:
- return null;
- case LONG:
- return longValue;
- case DOUBLE:
- return doubleValue;
- case STRING:
- return stringValue;
- case SERIALIZABLE:
- return serializableValue;
- default:
- throw new IllegalStateException("Should not be able to get through switch");
+ case MAP:
+ case COLLECTION:
+ case NULL:
+ return null;
+ case LONG:
+ return longValue;
+ case DOUBLE:
+ return doubleValue;
+ case STRING:
+ return stringValue;
+ case SERIALIZABLE:
+ return serializableValue;
+ default:
+ throw new IllegalStateException("Should not be able to get through switch");
}
}
diff --git a/source/java/org/alfresco/repo/domain/propval/ibatis/PropertyValueDAOImpl.java b/source/java/org/alfresco/repo/domain/propval/ibatis/PropertyValueDAOImpl.java
index 25f0a620af..6ce0825a19 100644
--- a/source/java/org/alfresco/repo/domain/propval/ibatis/PropertyValueDAOImpl.java
+++ b/source/java/org/alfresco/repo/domain/propval/ibatis/PropertyValueDAOImpl.java
@@ -25,11 +25,14 @@
package org.alfresco.repo.domain.propval.ibatis;
import java.io.Serializable;
+import java.util.Collection;
import java.util.Date;
import java.util.List;
+import java.util.Map;
import org.alfresco.repo.domain.propval.AbstractPropertyValueDAOImpl;
import org.alfresco.repo.domain.propval.PropertyClassEntity;
+import org.alfresco.repo.domain.propval.PropertyCollectionLinkEntity;
import org.alfresco.repo.domain.propval.PropertyDateValueEntity;
import org.alfresco.repo.domain.propval.PropertyDoubleValueEntity;
import org.alfresco.repo.domain.propval.PropertyStringValueEntity;
@@ -68,6 +71,8 @@ public class PropertyValueDAOImpl extends AbstractPropertyValueDAOImpl
private static final String SELECT_PROPERTY_VALUE_BY_STRING_VALUE = "select.PropertyValueByStringValue";
private static final String INSERT_PROPERTY_VALUE = "insert.PropertyValue";
+ private static final String INSERT_PROPERTY_COLLECTION_LINK = "insert.PropertyCollectionLink";
+
private SqlMapClientTemplate template;
public void setSqlMapClientTemplate(SqlMapClientTemplate sqlMapClientTemplate)
@@ -385,4 +390,62 @@ public class PropertyValueDAOImpl extends AbstractPropertyValueDAOImpl
// Done
return insertEntity;
}
+
+ @Override
+ protected Long createPropertyMapRoot(Class> clazz)
+ {
+ if (!Map.class.isAssignableFrom(clazz))
+ {
+ throw new IllegalArgumentException("Map root must be a Map instance");
+ }
+ final Pair> clazzPair = getOrCreatePropertyClass(clazz);
+ final Long actualTypeId = clazzPair.getFirst();
+
+ // Construct a property value to represent the collection
+ PropertyValueEntity insertEntity = new PropertyValueEntity();
+ // We have to set the persisted type manually
+ insertEntity.setPersistedType(PersistedType.MAP.getOrdinalNumber());
+ insertEntity.setLongValue(PropertyValueEntity.LONG_ZERO);
+ insertEntity.setActualTypeId(actualTypeId);
+ Long collectionId = (Long) template.insert(INSERT_PROPERTY_VALUE, insertEntity);
+ // Done
+ return collectionId;
+ }
+
+ @Override
+ protected Long createPropertyCollectionRoot(Class> clazz)
+ {
+ if (!Collection.class.isAssignableFrom(clazz))
+ {
+ throw new IllegalArgumentException("Collection root must be a Collection instance");
+ }
+ final Pair> clazzPair = getOrCreatePropertyClass(clazz);
+ final Long actualTypeId = clazzPair.getFirst();
+
+ // Construct a property value to represent the collection
+ PropertyValueEntity insertEntity = new PropertyValueEntity();
+ // We have to set the persisted type manually
+ insertEntity.setPersistedType(PersistedType.COLLECTION.getOrdinalNumber());
+ insertEntity.setLongValue(PropertyValueEntity.LONG_ZERO);
+ insertEntity.setActualTypeId(actualTypeId);
+ Long collectionId = (Long) template.insert(INSERT_PROPERTY_VALUE, insertEntity);
+ // Done
+ return collectionId;
+ }
+
+ @Override
+ protected void createPropertyLink(
+ Long rootCollectionId,
+ Long currentCollectionId,
+ Long keyId,
+ Long valueId)
+ {
+ PropertyCollectionLinkEntity insertEntity = new PropertyCollectionLinkEntity();
+ insertEntity.setRootCollectionPropId(rootCollectionId);
+ insertEntity.setCurrentCollectionPropId(currentCollectionId);
+ insertEntity.setKeyPropId(keyId);
+ insertEntity.setValuePropId(valueId);
+ template.insert(INSERT_PROPERTY_COLLECTION_LINK, insertEntity);
+ // Done
+ }
}
diff --git a/source/java/org/alfresco/repo/node/db/DbNodeServiceImpl.java b/source/java/org/alfresco/repo/node/db/DbNodeServiceImpl.java
index 52849d9ecc..d3123d4534 100644
--- a/source/java/org/alfresco/repo/node/db/DbNodeServiceImpl.java
+++ b/source/java/org/alfresco/repo/node/db/DbNodeServiceImpl.java
@@ -32,7 +32,6 @@ import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
-import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -94,6 +93,8 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl
private static Log loggerPaths = LogFactory.getLog(DbNodeServiceImpl.class.getName() + ".paths");
private NodeDaoService nodeDaoService;
+ /** A set of aspects, the presence of which indicate that nodes must not be archived */
+ private Set ignoreArchiveAspects;
private StoreArchiveMap storeArchiveMap;
private NodeService avmNodeService;
private NodeIndexer nodeIndexer;