From 5f8bfcae7ac91185d1c64639200e1496c145310c Mon Sep 17 00:00:00 2001 From: Derek Hulley Date: Fri, 14 Aug 2009 14:53:12 +0000 Subject: [PATCH] Support for searchable, arbitrarily-nested properties - TODO: ID-based caching for entities that can't be found by value (e.g. maps, serializable) - TODO: Serializable table - TODO: Dedicated tests for node properties (QName-Serializable maps with nested MLText) git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@15753 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- ...escoPostCreate-3.3-PropertyValueTables.sql | 10 + .../propval-common-SqlMap.xml | 18 ++ .../propval/AbstractPropertyValueDAOImpl.java | 228 +++++++++++++++++- .../propval/PropertyCollectionLinkEntity.java | 123 ++++++++++ .../repo/domain/propval/PropertyValueDAO.java | 50 +++- .../domain/propval/PropertyValueDAOTest.java | 68 ++++++ .../domain/propval/PropertyValueEntity.java | 57 ++++- .../propval/ibatis/PropertyValueDAOImpl.java | 63 +++++ .../repo/node/db/DbNodeServiceImpl.java | 3 +- 9 files changed, 600 insertions(+), 20 deletions(-) create mode 100644 source/java/org/alfresco/repo/domain/propval/PropertyCollectionLinkEntity.java diff --git a/config/alfresco/dbscripts/create/3.3/org.hibernate.dialect.MySQLInnoDBDialect/AlfrescoPostCreate-3.3-PropertyValueTables.sql b/config/alfresco/dbscripts/create/3.3/org.hibernate.dialect.MySQLInnoDBDialect/AlfrescoPostCreate-3.3-PropertyValueTables.sql index 38087d689d..666c2b70af 100644 --- a/config/alfresco/dbscripts/create/3.3/org.hibernate.dialect.MySQLInnoDBDialect/AlfrescoPostCreate-3.3-PropertyValueTables.sql +++ b/config/alfresco/dbscripts/create/3.3/org.hibernate.dialect.MySQLInnoDBDialect/AlfrescoPostCreate-3.3-PropertyValueTables.sql @@ -68,6 +68,16 @@ CREATE TABLE alf_prop_value PRIMARY KEY (id) ) ENGINE=InnoDB; +CREATE TABLE alf_prop_collection_link +( + root_coll_prop_id BIGINT NOT NULL, + curr_coll_prop_id BIGINT NOT NULL, + key_prop_id BIGINT NOT NULL, + value_prop_id BIGINT NOT NULL, + INDEX idx_alf_prop_coll_rev (value_prop_id, root_coll_prop_id), + PRIMARY KEY (root_coll_prop_id, curr_coll_prop_id, key_prop_id, value_prop_id) +) ENGINE=InnoDB; + -- -- Record script finish -- diff --git a/config/alfresco/ibatis/org.hibernate.dialect.Dialect/propval-common-SqlMap.xml b/config/alfresco/ibatis/org.hibernate.dialect.Dialect/propval-common-SqlMap.xml index e41f0ea880..ce1eb2cd89 100644 --- a/config/alfresco/ibatis/org.hibernate.dialect.Dialect/propval-common-SqlMap.xml +++ b/config/alfresco/ibatis/org.hibernate.dialect.Dialect/propval-common-SqlMap.xml @@ -15,6 +15,7 @@ + @@ -56,6 +57,12 @@ + + + + + + @@ -271,4 +278,15 @@ pv.id = #id# + + insert into alf_prop_collection_link + ( + root_coll_prop_id, curr_coll_prop_id, key_prop_id, value_prop_id + ) + values + ( + #rootCollectionPropId#, #currentCollectionPropId#, #keyPropId#, #valuePropId# + ) + + \ No newline at end of file diff --git a/source/java/org/alfresco/repo/domain/propval/AbstractPropertyValueDAOImpl.java b/source/java/org/alfresco/repo/domain/propval/AbstractPropertyValueDAOImpl.java index 43fd252edc..99a9c32731 100644 --- a/source/java/org/alfresco/repo/domain/propval/AbstractPropertyValueDAOImpl.java +++ b/source/java/org/alfresco/repo/domain/propval/AbstractPropertyValueDAOImpl.java @@ -25,7 +25,13 @@ package org.alfresco.repo.domain.propval; import java.io.Serializable; +import java.util.ArrayList; +import java.util.Collection; import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.repo.cache.SimpleCache; @@ -33,6 +39,7 @@ import org.alfresco.repo.cache.lookup.EntityLookupCache; import org.alfresco.repo.cache.lookup.EntityLookupCache.EntityLookupCallbackDAOAdaptor; import org.alfresco.repo.domain.CrcHelper; import org.alfresco.repo.domain.propval.PropertyValueEntity.PersistedType; +import org.alfresco.service.cmr.repository.MLText; import org.alfresco.util.Pair; /** @@ -489,7 +496,6 @@ public abstract class AbstractPropertyValueDAOImpl implements PropertyValueDAO return (Pair) entityPair; } - /** * Callback for alf_prop_double_value DAO. */ @@ -559,10 +565,60 @@ public abstract class AbstractPropertyValueDAOImpl implements PropertyValueDAO return entityPair; } + /** + * {@inheritDoc} + * @see #getOrCreatePropertyValueImpl(Serializable, int, int) + */ public Pair getOrCreatePropertyValue(Serializable value) { - Pair entityPair = propertyValueCache.getOrCreateByValue(value); - return (Pair) entityPair; + return getOrCreatePropertyValueImpl(value, null, Integer.MAX_VALUE, 0); + } + + /** + * {@inheritDoc} + * @see #getOrCreatePropertyValueImpl(Serializable, int, int) + */ + public Pair getOrCreatePropertyValue(Serializable value, int maxDepth) + { + return getOrCreatePropertyValueImpl(value, null, maxDepth, 0); + } + + @SuppressWarnings("unchecked") + private Pair getOrCreatePropertyValueImpl( + Serializable value, + Long rootId, + int maxDepth, + int currentDepth) + { + if (value != null && maxDepth > currentDepth && value instanceof Map) + { + // The default is to do a deep expansion + Long mapId = createPropertyMapImpl( + (Map)value, + rootId, + maxDepth, + currentDepth); + Pair entityPair = new Pair(mapId, value); + // TODO: Go through cache? + return entityPair; + } + else if (value != null && maxDepth > currentDepth && value instanceof Collection) + { + // The default is to do a deep expansion + Long collectionId = createPropertyCollectionImpl( + (Collection)value, + rootId, + maxDepth, + currentDepth); + Pair entityPair = new Pair(collectionId, value); + // TODO: Go through cache? + return entityPair; + } + else + { + Pair entityPair = propertyValueCache.getOrCreateByValue(value); + return (Pair) entityPair; + } } /** @@ -611,7 +667,11 @@ public abstract class AbstractPropertyValueDAOImpl implements PropertyValueDAO public Pair createValue(Serializable value) { PropertyValueEntity entity = createPropertyValue(value); - return convertEntityToPair(entity); + Long entityId = entity.getId(); + // Create the link entry for the property + createPropertyLink(entityId, entityId, 0L, entityId); + // Done + return new Pair(entity.getId(), value); } public Pair findByKey(Long key) @@ -622,6 +682,13 @@ public abstract class AbstractPropertyValueDAOImpl implements PropertyValueDAO public Pair findByValue(Serializable value) { + if (value != null) + { + if (value instanceof Map || value instanceof Collection) + { + throw new IllegalArgumentException("Should not be searching for Maps or Collections"); + } + } PropertyValueEntity entity = findPropertyValueByValue(value); return convertEntityToPair(entity); } @@ -630,4 +697,157 @@ public abstract class AbstractPropertyValueDAOImpl implements PropertyValueDAO protected abstract PropertyValueEntity findPropertyValueById(Long id); protected abstract PropertyValueEntity findPropertyValueByValue(Serializable value); protected abstract PropertyValueEntity createPropertyValue(Serializable value); + + //================================ + // Special handling of maps and collections + //================================ + + /** + * Recursive method to write a map out. If the root entity ID is null then the current + * map ID is used as the root. + * + * @param value the map to write + * @param rootId the root entity ID, which may be a map or a collection + * @return Returns the ID of the newly-written map + */ + private Long createPropertyMapImpl( + Map map, + Long rootId, + int maxDepth, + int currentDepth) + { + // Create the root of the map + Class clazz = null; + if (map instanceof MLText) + { + clazz = MLText.class; + } + else + { + clazz = HashMap.class; + } + Long entityId = createPropertyMapRoot(clazz); + // Use this as the root if this is the first entry into this method + if (rootId == null) + { + rootId = entityId; + } + + // Create the link entry for the root + createPropertyLink(rootId, entityId, 0L, entityId); + + // Now iterate over the entries and create properties for the keys and values + for (Map.Entry entry : map.entrySet()) + { + K key = entry.getKey(); + Long keyId = getOrCreatePropertyValue(key).getFirst(); + + V value = entry.getValue(); + // Callback with this level, incrementing the current depth + Pair valuePair = getOrCreatePropertyValueImpl( + (Serializable) value, + rootId, + maxDepth, + currentDepth + 1); + Long valueId = valuePair.getFirst(); + + // Now write the mapping entry + createPropertyLink(rootId, entityId, keyId, valueId); + } + + // Done + return entityId; + } + + /** + * Recursive method to write a collection out. If the root entity ID is null then the current + * collection ID is used as the root. + * + * @param value the collection to write + * @param rootId the root property ID + * @return Returns the ID of the newly-written collection + */ + private Long createPropertyCollectionImpl( + Collection collection, + Long rootId, + int maxDepth, + int currentDepth) + { + // Create the root of the collection + Class clazz = null; + if (collection instanceof Set) + { + clazz = HashSet.class; + } + else + { + clazz = ArrayList.class; + } + Long entityId = createPropertyCollectionRoot(clazz); + // Use this as the root if this is the first entry into this method + if (rootId == null) + { + rootId = entityId; + } + + // Create the link entry for the root + createPropertyLink(rootId, entityId, 0L, entityId); + + // Now iterate over the entries and create properties for the keys and values + long index = 0L; + for (V value : collection) + { + // Callback with this level, incrementing the current depth + Pair valuePair = getOrCreatePropertyValueImpl( + (Serializable) value, + rootId, + maxDepth, + currentDepth + 1); + Long valueId = valuePair.getFirst(); + // Now write the mapping entry + Long keyId = new Long(index); + createPropertyLink(rootId, entityId, keyId, valueId); + // Keep iterating + index++; + } + return entityId; + } + + /** + * Create a property value entry for maps. The class is assumed to + * be correct with a default constructor for later reconstruction. + *

+ * This method must not create the associated link property. + * + * @param clazz The map instance that must be used for re-instantiation. + * This must be an instance derived from {@link Map} with a default constructor. + * @return Returns the newly-created property ID + */ + protected abstract Long createPropertyMapRoot(Class clazz); + + /** + * Create a property value entry for collections. The class is assumed to + * be correct with a default constructor for later reconstruction. + *

+ * This method must not create the associated link property. + * + * @param clazz The collection instance that must be used for re-instantiation. + * This must be an instance derived from {@link Collection} with a default constructor. + * @return Returns the newly-created property ID + */ + protected abstract Long createPropertyCollectionRoot(Class clazz); + + /** + * Create an entry for the map or collection link + * + * @param rootCollectionId the root (entry-point) map or collection ID + * @param currentCollectionId the current map or collection ID + * @param keyId the map key entity ID or collection position count + * @param valueId the ID of the entity storing the value (may be another map or collection) + */ + protected abstract void createPropertyLink( + Long rootCollectionId, + Long currentCollectionId, + Long keyId, + Long valueId); } diff --git a/source/java/org/alfresco/repo/domain/propval/PropertyCollectionLinkEntity.java b/source/java/org/alfresco/repo/domain/propval/PropertyCollectionLinkEntity.java new file mode 100644 index 0000000000..1f57a4ac0d --- /dev/null +++ b/source/java/org/alfresco/repo/domain/propval/PropertyCollectionLinkEntity.java @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2005-2009 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.propval; + +/** + * Entity bean for alf_prop_collections_link table. + * + * @author Derek Hulley + * @since 3.3 + */ +public class PropertyCollectionLinkEntity +{ + private long rootCollectionPropId; + private long currentCollectionPropId; + private long keyPropId; + private long valuePropId; + + public PropertyCollectionLinkEntity() + { + } + + @Override + public int hashCode() + { + return (int) rootCollectionPropId + (int) valuePropId; + } + + @Override + public boolean equals(Object obj) + { + if (this == obj) + { + return true; + } + else if (obj instanceof PropertyCollectionLinkEntity) + { + PropertyCollectionLinkEntity that = (PropertyCollectionLinkEntity) obj; + return + this.rootCollectionPropId == that.rootCollectionPropId && + this.currentCollectionPropId == that.currentCollectionPropId && + this.keyPropId == that.keyPropId && + this.valuePropId == that.valuePropId; + } + else + { + return false; + } + } + + @Override + public String toString() + { + StringBuilder sb = new StringBuilder(512); + sb.append("PropertyCollectionsLinkEntity") + .append("[ currentCollectionPropId=").append(currentCollectionPropId) + .append(", keyPropId=").append(keyPropId) + .append(", valuePropId=").append(valuePropId) + .append("]"); + return sb.toString(); + } + + public long getRootCollectionPropId() + { + return rootCollectionPropId; + } + + public void setRootCollectionPropId(long rootCollectionPropId) + { + this.rootCollectionPropId = rootCollectionPropId; + } + + public long getCurrentCollectionPropId() + { + return currentCollectionPropId; + } + + public void setCurrentCollectionPropId(long currentCollectionPropId) + { + this.currentCollectionPropId = currentCollectionPropId; + } + + public long getKeyPropId() + { + return keyPropId; + } + + public void setKeyPropId(long keyPropId) + { + this.keyPropId = keyPropId; + } + + public long getValuePropId() + { + return valuePropId; + } + + public void setValuePropId(long valuePropId) + { + this.valuePropId = valuePropId; + } +} diff --git a/source/java/org/alfresco/repo/domain/propval/PropertyValueDAO.java b/source/java/org/alfresco/repo/domain/propval/PropertyValueDAO.java index e64146b812..d0c0c41a28 100644 --- a/source/java/org/alfresco/repo/domain/propval/PropertyValueDAO.java +++ b/source/java/org/alfresco/repo/domain/propval/PropertyValueDAO.java @@ -26,7 +26,9 @@ package org.alfresco.repo.domain.propval; import java.io.Serializable; import java.util.Date; +import java.util.Map; +import org.alfresco.repo.action.evaluator.compare.PropertyValueComparator; import org.alfresco.util.Pair; /** @@ -37,6 +39,9 @@ import org.alfresco.util.Pair; */ public interface PropertyValueDAO { + //================================ + // 'alf_prop_class' accessors + //================================ /** * alf_prop_class accessor * @@ -56,6 +61,9 @@ public interface PropertyValueDAO */ Pair> getOrCreatePropertyClass(Class value); + //================================ + // 'alf_prop_date_value' accessors + //================================ /** * alf_prop_date_value accessor * @@ -75,6 +83,9 @@ public interface PropertyValueDAO */ Pair getOrCreatePropertyDateValue(Date value); + //================================ + // 'alf_prop_string_value' accessors + //================================ /** * alf_prop_string_value accessor * @@ -94,6 +105,9 @@ public interface PropertyValueDAO */ Pair getOrCreatePropertyStringValue(String value); + //================================ + // 'alf_prop_double_value' accessors + //================================ /** * alf_prop_double_value accessor * @@ -113,22 +127,52 @@ public interface PropertyValueDAO */ Pair getOrCreatePropertyDoubleValue(Double value); + //================================ + // 'alf_prop_value' accessors + //================================ /** - * alf_prop_value accessor + * alf_prop_value accessor: get a property based on the database ID * * @param id the ID (may not be null) */ Pair getPropertyValueById(Long id); /** - * alf_prop_value accessor + * alf_prop_value accessor: find a property based on the value * * @param value the value to find the ID for (may be null) */ Pair getPropertyValue(Serializable value); /** - * alf_prop_value accessor + * 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. + *

+ * All collections and maps will be opened up to any depth. To limit this behaviour, + * use {@link #getOrCreatePropertyValue(Serializable, int)}. * * @param value the value to find the ID for (may be null) */ Pair 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;