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 fd7dd03230..be1665905d 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 @@ -44,12 +44,13 @@ CREATE TABLE alf_prop_serializable_value CREATE TABLE alf_prop_value ( id BIGINT NOT NULL AUTO_INCREMENT, + actual_type_id BIGINT NOT NULL, persisted_type TINYINT NOT NULL, long_value BIGINT NOT NULL, - INDEX idx_alf_prop_val (persisted_type, long_value), + INDEX idx_alf_prop_per (persisted_type, long_value), + INDEX idx_alf_prop_act (actual_type_id, long_value), PRIMARY KEY (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 472675533b..60ee445e37 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 @@ -35,7 +35,12 @@ + + + + + @@ -72,8 +77,8 @@ - insert into alf_prop_value (persisted_type, long_value) - values (#persistedType#, #longValue#) + insert into alf_prop_value (actual_type_id, persisted_type, long_value) + values (#actualTypeId#, #persistedType#, #longValue#) @@ -111,8 +116,8 @@ id = #id# - - select * from @@ -121,7 +126,7 @@ string_value = #stringValue# - + - + + + + + + + + + + + + + \ No newline at end of file diff --git a/source/java/org/alfresco/repo/domain/contentdata/AbstractContentDataDAOImpl.java b/source/java/org/alfresco/repo/domain/contentdata/AbstractContentDataDAOImpl.java index 1d5dd38808..6e3112182c 100644 --- a/source/java/org/alfresco/repo/domain/contentdata/AbstractContentDataDAOImpl.java +++ b/source/java/org/alfresco/repo/domain/contentdata/AbstractContentDataDAOImpl.java @@ -60,7 +60,6 @@ public abstract class AbstractContentDataDAOImpl implements ContentDataDAO * Content URL IDs to delete before final commit. */ private static final String KEY_PRE_COMMIT_CONTENT_URL_DELETIONS = "AbstractContentDataDAOImpl.PreCommitContentUrlDeletions"; - private static final Long CACHE_NULL_LONG = Long.MIN_VALUE; private static Log logger = LogFactory.getLog(AbstractContentDataDAOImpl.class); diff --git a/source/java/org/alfresco/repo/domain/propval/AbstractPropertyValueDAOImpl.java b/source/java/org/alfresco/repo/domain/propval/AbstractPropertyValueDAOImpl.java index 806a01331e..85bc926f11 100644 --- a/source/java/org/alfresco/repo/domain/propval/AbstractPropertyValueDAOImpl.java +++ b/source/java/org/alfresco/repo/domain/propval/AbstractPropertyValueDAOImpl.java @@ -29,7 +29,7 @@ import java.io.Serializable; import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.repo.cache.SimpleCache; import org.alfresco.repo.cache.lookup.EntityLookupCache; -import org.alfresco.repo.cache.lookup.EntityLookupCache.EntityLookupCallbackDAO; +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.util.Pair; @@ -205,7 +205,7 @@ public abstract class AbstractPropertyValueDAOImpl implements PropertyValueDAO /** * Callback for alf_prop_class DAO. */ - private class PropertyClassCallbackDAO implements EntityLookupCallbackDAO, String> + private class PropertyClassCallbackDAO extends EntityLookupCallbackDAOAdaptor, String> { private final Pair> convertEntityToPair(PropertyClassEntity entity) { @@ -288,7 +288,7 @@ public abstract class AbstractPropertyValueDAOImpl implements PropertyValueDAO /** * Callback for alf_prop_string_value DAO. */ - private class PropertyStringValueCallbackDAO implements EntityLookupCallbackDAO> + private class PropertyStringValueCallbackDAO extends EntityLookupCallbackDAOAdaptor> { private final Pair convertEntityToPair(PropertyStringValueEntity entity) { @@ -371,7 +371,7 @@ public abstract class AbstractPropertyValueDAOImpl implements PropertyValueDAO /** * Callback for alf_prop_double_value DAO. */ - private class PropertyDoubleValueCallbackDAO implements EntityLookupCallbackDAO + private class PropertyDoubleValueCallbackDAO extends EntityLookupCallbackDAOAdaptor { private final Pair convertEntityToPair(PropertyDoubleValueEntity entity) { @@ -446,7 +446,7 @@ public abstract class AbstractPropertyValueDAOImpl implements PropertyValueDAO /** * Callback for alf_prop_value DAO. */ - private class PropertyValueCallbackDAO implements EntityLookupCallbackDAO + private class PropertyValueCallbackDAO extends EntityLookupCallbackDAOAdaptor { private final Pair convertEntityToPair(PropertyValueEntity entity) { @@ -454,18 +454,23 @@ public abstract class AbstractPropertyValueDAOImpl implements PropertyValueDAO { return null; } - else - { - return entity.getEntityPair(); - } + Long entityId = entity.getId(); + Serializable entityValue = entity.getPersistedValue(); + + // Dig out the class to convert the value to i.e. the actual type of the value + Long actualTypeId = entity.getActualTypeId(); + Class actualType = getPropertyClassById(actualTypeId).getSecond(); + // Convert it + Serializable actualValue = (Serializable) converter.convert(actualType, entityValue); + // Done + return new Pair(entityId, actualValue); } public Serializable getValueKey(Serializable value) { - // Find out how it would be persisted - Pair persistedValuePair = converter.convertToPersistedType(value); + PersistedType persistedType = PropertyValueEntity.getPersistedTypeEnum(value); // We don't return keys for pure Serializable instances - if (persistedValuePair.getFirst().equals(PersistedType.SERIALIZABLE.getOrdinalNumber())) + if (persistedType == PersistedType.SERIALIZABLE) { // It will be Serialized, so no key return null; @@ -477,7 +482,7 @@ public abstract class AbstractPropertyValueDAOImpl implements PropertyValueDAO else { // We've dodged Serializable and String; everything else is OK as a key. - return persistedValuePair; + return value; } } @@ -495,14 +500,6 @@ public abstract class AbstractPropertyValueDAOImpl implements PropertyValueDAO public Pair findByValue(Serializable value) { -// // Find out how it would be persisted -// Pair persistedValuePair = converter.convertToPersistedType(value); -// // We don't do lookups for serializable values -// if (persistedValuePair.getFirst().equals(PersistedType.SERIALIZABLE.getOrdinalNumber())) -// { -// // It will be Serialized, so no we don't look it up -// return null; -// } PropertyValueEntity entity = findPropertyValueByValue(value); return convertEntityToPair(entity); } diff --git a/source/java/org/alfresco/repo/domain/propval/DefaultPropertyTypeConverter.java b/source/java/org/alfresco/repo/domain/propval/DefaultPropertyTypeConverter.java index 4674ee1d31..5c946314b0 100644 --- a/source/java/org/alfresco/repo/domain/propval/DefaultPropertyTypeConverter.java +++ b/source/java/org/alfresco/repo/domain/propval/DefaultPropertyTypeConverter.java @@ -24,30 +24,19 @@ */ package org.alfresco.repo.domain.propval; -import java.io.Serializable; - -import org.alfresco.error.AlfrescoRuntimeException; -import org.alfresco.repo.domain.propval.PropertyValueEntity.PersistedType; import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter; -import org.alfresco.service.cmr.repository.datatype.TypeConversionException; -import org.alfresco.util.Pair; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; /** * Default converter for handling data going to and from the persistence layer. - *

- * This implementation uses an explicit mapping for each Java class supported. If - * an unsupported class is found, then the value is just serialized. Conversions - * are done using the {@link DefaultTypeConverter}. + *

+ * Apart from converting between Boolean and Long values, + * the {@link DefaultTypeConverter} is used. * * @author Derek Hulley * @since 3.3 */ public class DefaultPropertyTypeConverter implements PropertyTypeConverter { - private static final Log logger = LogFactory.getLog(DefaultPropertyTypeConverter.class); - /** * Default constructor */ @@ -55,84 +44,8 @@ public class DefaultPropertyTypeConverter implements PropertyTypeConverter { } - /** - * {@inheritDoc} - *

- * This converter looks up a {@link PersistedType} using the class of the - * given value. null values are handled specially. If there is no match, then - * the {@link PersistedType#SERIALIZABLE} type is used. - */ - public Pair convertToPersistedType(Serializable value) + public T convert(Class targetClass, Object value) { - if (value == null) - { - return PropertyValueEntity.PERSISTED_TYPE_NULL; - } - // Look up the type in the class map - Class clazz = value.getClass(); - PersistedType type = PropertyValueEntity.persistedTypesByClass.get(clazz); - if (type == null) - { - return new Pair(PersistedType.SERIALIZABLE.getOrdinalNumber(), value); - } - else - { - // Convert the value - Class toClazz = type.getAssociatedClass(); - try - { - Serializable converted = (Serializable) DefaultTypeConverter.INSTANCE.convert(toClazz, value); - return new Pair(type.getOrdinalNumber(), converted); - } - catch (TypeConversionException e) - { - throw new AlfrescoRuntimeException( - "Failed to convert to persistable value: \n" + - " Value: " + value.getClass() + "\n" + - " Target type: " + type + "\n" + - " Target class: " + toClazz, - e); - } - } - } - - /** - * {@inheritDoc} - *

- * Looks up the {@link #persistedTypesByOrdinal persisted type} and uses the {@link DefaultTypeConverter} to - * convert back to an external value. - */ - public Serializable convertFromPersistedType(Short persistedType, Class actualType, Serializable persistedValue) - { - if (persistedValue == null) - { - throw new IllegalArgumentException("A persisted value can never be null"); - } - PersistedType type = PropertyValueEntity.persistedTypesByOrdinal.get(persistedType); - if (type == null) - { - // Not recognised! This is probably a data issue - logger.warn("Persisted type of '" + persistedType + "' not recognised."); - return persistedValue; - } - else if (type == PersistedType.SERIALIZABLE) - { - // No conversion necessary - return persistedValue; - } - // Convert the value - try - { - return (Serializable) DefaultTypeConverter.INSTANCE.convert(actualType, persistedValue); - } - catch (TypeConversionException e) - { - throw new AlfrescoRuntimeException( - "Failed to convert from persisted value: \n" + - " Value: " + persistedValue.getClass() + "\n" + - " Source type: " + type + "\n" + - " Target class: " + actualType, - e); - } + return DefaultTypeConverter.INSTANCE.convert(targetClass, value); } } diff --git a/source/java/org/alfresco/repo/domain/propval/PropertyTypeConverter.java b/source/java/org/alfresco/repo/domain/propval/PropertyTypeConverter.java index 293ff4ea1c..3c48ead8ad 100644 --- a/source/java/org/alfresco/repo/domain/propval/PropertyTypeConverter.java +++ b/source/java/org/alfresco/repo/domain/propval/PropertyTypeConverter.java @@ -24,12 +24,11 @@ */ package org.alfresco.repo.domain.propval; -import java.io.Serializable; - -import org.alfresco.util.Pair; - /** - * Interface for converters that + * Interface for converters that to translate between persisted values and external values. + *

+ * Implementations must be able to convert between values being stored and Long, Double, String - + * and back again. * * @author Derek Hulley * @since 3.3 @@ -37,19 +36,10 @@ import org.alfresco.util.Pair; public interface PropertyTypeConverter { /** - * Convert an external value into a persisted type and persistable value. + * Convert a value to a given type. * * @param value the value to convert * @return Returns the persisted type and value to persist */ - Pair convertToPersistedType(Serializable value); - - /** - * Convert a persisted type-value pair into an external value - * - * @param persistedType the type that the value was persisted as - * @param actualType the original Java type to convert to - * @param persistedValue the persisted value, which must be one of the {@link PersistedType} values - */ - Serializable convertFromPersistedType(Short persistedType, Class actualType, Serializable persistedValue); + T convert(Class targetClass, Object value); } diff --git a/source/java/org/alfresco/repo/domain/propval/PropertyValueDAOTest.java b/source/java/org/alfresco/repo/domain/propval/PropertyValueDAOTest.java index e4b8bde6d5..04cff6cd96 100644 --- a/source/java/org/alfresco/repo/domain/propval/PropertyValueDAOTest.java +++ b/source/java/org/alfresco/repo/domain/propval/PropertyValueDAOTest.java @@ -24,6 +24,8 @@ */ package org.alfresco.repo.domain.propval; +import java.io.Serializable; + import junit.framework.TestCase; import org.alfresco.repo.transaction.RetryingTransactionHelper; @@ -169,33 +171,6 @@ public class PropertyValueDAOTest extends TestCase assertNotSame("String IDs were not different", stringEntityPair.getFirst(), stringUpperEntityPair.getFirst()); } -// public void testPropertyNumericValue_Boolean() throws Exception -// { -// RetryingTransactionCallback> createValueCallback = new RetryingTransactionCallback>() -// { -// public Pair execute() throws Throwable -// { -// // Get the classes -// return propertyValueDAO.getOrCreatePropertyNumericValue(Boolean.TRUE); -// } -// }; -// final Pair entityPair = txnHelper.doInTransaction(createValueCallback, false); -// assertNotNull(entityPair); -// assertEquals(Boolean.TRUE, entityPair.getSecond()); -// -// RetryingTransactionCallback> getValueCallback = new RetryingTransactionCallback>() -// { -// public Pair execute() throws Throwable -// { -// // Get the classes -// return propertyValueDAO.getPropertyDoubleValue(Boolean.TRUE); -// } -// }; -// final Pair entityPairCheck = txnHelper.doInTransaction(getValueCallback, false); -// assertNotNull(entityPairCheck); -// assertEquals(entityPair, entityPairCheck); -// } -// // public void testPropertyNumericValue_Long() throws Exception // { // final Long longValue = Long.valueOf(Long.MAX_VALUE); @@ -251,4 +226,108 @@ public class PropertyValueDAOTest extends TestCase assertNotNull(entityPairCheck); assertEquals(entityPair, entityPairCheck); } + + /** + * Tests that the given value can be persisted and retrieved with the same resulting ID + */ + private void runPropertyValueTest(final Serializable value) throws Exception + { + // Create it (if it doesn't exist) + RetryingTransactionCallback> createValueCallback = new RetryingTransactionCallback>() + { + public Pair execute() throws Throwable + { + // Get the classes + return propertyValueDAO.getOrCreatePropertyValue(value); + } + }; + final Pair entityPair = txnHelper.doInTransaction(createValueCallback, false); + assertNotNull(entityPair); + assertEquals(value, entityPair.getSecond()); + + // Retrieve it by value + RetryingTransactionCallback> getValueCallback = new RetryingTransactionCallback>() + { + public Pair execute() throws Throwable + { + // Get the classes + return propertyValueDAO.getPropertyValue(value); + } + }; + final Pair entityPairCheck = txnHelper.doInTransaction(getValueCallback, false); + assertNotNull(entityPairCheck); + assertEquals(entityPair, entityPairCheck); + + // Retrieve it by ID + RetryingTransactionCallback> getByIdCallback = new RetryingTransactionCallback>() + { + public Pair execute() throws Throwable + { + // Get the classes + return propertyValueDAO.getPropertyValueById(entityPair.getFirst()); + } + }; + final Pair entityPairCheck2 = txnHelper.doInTransaction(getByIdCallback, false); + assertNotNull(entityPairCheck2); + assertEquals(entityPair, entityPairCheck2); + } + + public void testPropertyValue_Null() throws Exception + { + runPropertyValueTest(null); + } + + public void testPropertyValue_Boolean() throws Exception + { + runPropertyValueTest(Boolean.TRUE); + runPropertyValueTest(Boolean.FALSE); + } + + public void testPropertyValue_Short() throws Exception + { + for (short i = 0; i < 1000; i++) + { + runPropertyValueTest(new Short(i)); + } + } + + public void testPropertyValue_Integer() throws Exception + { + for (int i = 0; i < 1000; i++) + { + runPropertyValueTest(new Integer(i)); + } + } + + public void testPropertyValue_Long() throws Exception + { + for (long i = 0; i < 1000; i++) + { + runPropertyValueTest(new Long(i)); + } + } + + public void testPropertyValue_Float() throws Exception + { + for (long i = 0; i < 1000; i++) + { + runPropertyValueTest(new Float((float)i + 0.01F)); + } + } + + public void testPropertyValue_Double() throws Exception + { + for (long i = 0; i < 1000; i++) + { + runPropertyValueTest(new Double((double)i + 0.01D)); + } + } + + public void testPropertyValue_String() throws Exception + { + for (long i = 0; i < 1000; i++) + { + runPropertyValueTest(new String("Value-" + i + ".xyz")); + } + } } diff --git a/source/java/org/alfresco/repo/domain/propval/PropertyValueEntity.java b/source/java/org/alfresco/repo/domain/propval/PropertyValueEntity.java index e2168c12f7..553a317974 100644 --- a/source/java/org/alfresco/repo/domain/propval/PropertyValueEntity.java +++ b/source/java/org/alfresco/repo/domain/propval/PropertyValueEntity.java @@ -50,12 +50,11 @@ public class PropertyValueEntity public static final Long LONG_ZERO = new Long(0L); public static final Long LONG_ONE = new Long(1L); - public static final Short ORDINAL_NULL = new Short((short)0); - public static final Short ORDINAL_BOOLEAN = new Short((short)1); - public static final Short ORDINAL_LONG = new Short((short)2); - public static final Short ORDINAL_DOUBLE = new Short((short)3); - public static final Short ORDINAL_STRING = new Short((short)4); - public static final Short ORDINAL_SERIALIZABLE = new Short((short)5); + public static final Short ORDINAL_NULL = 0; + public static final Short ORDINAL_LONG = 1; + public static final Short ORDINAL_DOUBLE = 2; + public static final Short ORDINAL_STRING = 3; + public static final Short ORDINAL_SERIALIZABLE = 4; /** * Enumeration of persisted types for alf_prop_value.persisted_type. @@ -81,19 +80,6 @@ public class PropertyValueEntity throw new UnsupportedOperationException("NULL is a special case and has no associated class."); } }, - BOOLEAN - { - @Override - public Short getOrdinalNumber() - { - return ORDINAL_BOOLEAN; - } - @Override - public Class getAssociatedClass() - { - return Boolean.class; - } - }, LONG { @Override @@ -188,7 +174,7 @@ public class PropertyValueEntity persistedTypesByOrdinal = Collections.unmodifiableMap(mapOrdinal); // Create the map of class-type Map, PersistedType> mapClass = new HashMap, PersistedType>(29); - mapClass.put(Boolean.class, PersistedType.BOOLEAN); + mapClass.put(Boolean.class, PersistedType.LONG); mapClass.put(Short.class, PersistedType.LONG); mapClass.put(Integer.class, PersistedType.LONG); mapClass.put(Long.class, PersistedType.LONG); @@ -202,7 +188,9 @@ public class PropertyValueEntity private static final Log logger = LogFactory.getLog(PropertyValueEntity.class); private Long id; + private Long actualTypeId; private Short persistedType; + private PersistedType persistedTypeEnum; // Derived private Long longValue; private String stringValue; private Double doubleValue; @@ -217,7 +205,7 @@ public class PropertyValueEntity @Override public int hashCode() { - return (persistedType == null ? 0 : persistedType.intValue()) + (longValue == null ? 0 : longValue.intValue()); + return (actualTypeId == null ? 0 : actualTypeId.intValue()) + (longValue == null ? 0 : longValue.intValue()); } @Override @@ -230,7 +218,7 @@ public class PropertyValueEntity else if (obj != null && obj instanceof PropertyValueEntity) { PropertyValueEntity that = (PropertyValueEntity) obj; - return EqualsHelper.nullSafeEquals(this.persistedType, that.persistedType) && + return EqualsHelper.nullSafeEquals(this.actualTypeId, that.actualTypeId) && EqualsHelper.nullSafeEquals(this.longValue, that.longValue); } else @@ -245,76 +233,115 @@ public class PropertyValueEntity StringBuilder sb = new StringBuilder(512); sb.append("PropertyValueEntity") .append("[ ID=").append(id) - .append(", type=").append(persistedType) + .append(", actualTypeId=").append(actualTypeId) + .append(", persistedType=").append(persistedType) .append(", value=").append(longValue) .append("]"); return sb.toString(); } - /** - * @return Returns the ID-value pair - */ - public Pair getEntityPair() - { - Serializable value = getValue(); - return new Pair(id, value); - } - /** * Gets the value based on the persisted type. * Note that this is the value as persisted and not the original, client-required * value. * @return Returns the persisted value */ - public Serializable getValue() + public Serializable getPersistedValue() { - if (persistedType.equals(PersistedType.NULL.getOrdinalNumber())) + switch (persistedTypeEnum) { - return null; + 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"); } - else if (persistedType.equals(PersistedType.BOOLEAN.getOrdinalNumber())) - { - return (longValue.longValue() > 0 ? Boolean.TRUE : Boolean.FALSE); - } - else if (persistedType.equals(PersistedType.LONG.getOrdinalNumber())) + } + + /** + * Shortcut method to set the value. It will be converted as required and the necessary fields + * will be populated. + * + * @param value the value to persist (may be null) + * @param converter the converter that will perform and type conversion + * @return Returns the persisted type value + */ + public Serializable setValue(Serializable value, PropertyTypeConverter converter) + { + if (value == null) { + this.persistedType = ORDINAL_NULL; + this.persistedTypeEnum = PersistedType.NULL; + this.longValue = LONG_ZERO; return longValue; } - else if (persistedType.equals(PersistedType.DOUBLE.getOrdinalNumber())) - { - return doubleValue; - } - else if (persistedType.equals(PersistedType.STRING.getOrdinalNumber())) - { - return stringValue; - } - else if (persistedType.equals(PersistedType.SERIALIZABLE.getOrdinalNumber())) - { - return serializableValue; - } else { - logger.warn("Persisted type code not recognised: " + this.persistedType); - // Return any non-null value and hope it works - if (serializableValue != null) + Class valueClazz = value.getClass(); + persistedTypeEnum = persistedTypesByClass.get(valueClazz); + if (persistedTypeEnum == null) { - return serializableValue; + persistedTypeEnum = PersistedType.SERIALIZABLE; } - else if (doubleValue != null) + persistedType = persistedTypeEnum.getOrdinalNumber(); + // Get the class to persist as + switch (persistedTypeEnum) { - return doubleValue; - } - else if (stringValue != null) - { - return stringValue; - } - else - { - return longValue; + case LONG: + longValue = converter.convert(Long.class, value); + return longValue; + case DOUBLE: + doubleValue = converter.convert(Double.class, value); + return doubleValue; + case STRING: + stringValue = converter.convert(String.class, value); + return stringValue; + case SERIALIZABLE: + serializableValue = value; + return serializableValue; + default: + throw new IllegalStateException("Should not be able to get through switch"); } } } + /** + * Helper method to determine how the given value will be stored. + * + * @param value the value to check + * @return Returns the persisted type + */ + public static PersistedType getPersistedTypeEnum(Serializable value) + { + PersistedType persistedTypeEnum; + if (value == null) + { + persistedTypeEnum = PersistedType.NULL; + } + else + { + Class valueClazz = value.getClass(); + persistedTypeEnum = persistedTypesByClass.get(valueClazz); + if (persistedTypeEnum == null) + { + persistedTypeEnum = PersistedType.SERIALIZABLE; + } + } + return persistedTypeEnum; + } + + public PersistedType getPersistedTypeEnum() + { + return persistedTypeEnum; + } + public Long getId() { return id; @@ -325,6 +352,16 @@ public class PropertyValueEntity this.id = id; } + public Long getActualTypeId() + { + return actualTypeId; + } + + public void setActualTypeId(Long actualTypeId) + { + this.actualTypeId = actualTypeId; + } + public Short getPersistedType() { return persistedType; @@ -333,6 +370,12 @@ public class PropertyValueEntity public void setPersistedType(Short persistedType) { this.persistedType = persistedType; + this.persistedTypeEnum = persistedTypesByOrdinal.get(persistedType); + if (persistedTypeEnum == null) + { + logger.error("Persisted type '" + persistedType + "' is not recognised."); + this.persistedTypeEnum = PersistedType.LONG; + } } public Long getLongValue() 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 56eb2860a6..4552432558 100644 --- a/source/java/org/alfresco/repo/domain/propval/ibatis/PropertyValueDAOImpl.java +++ b/source/java/org/alfresco/repo/domain/propval/ibatis/PropertyValueDAOImpl.java @@ -47,12 +47,19 @@ public class PropertyValueDAOImpl extends AbstractPropertyValueDAOImpl private static final String SELECT_PROPERTY_CLASS_BY_ID = "select.PropertyClassByID"; private static final String SELECT_PROPERTY_CLASS_BY_NAME = "select.PropertyClassByName"; private static final String INSERT_PROPERTY_CLASS = "insert.PropertyClass"; + private static final String SELECT_PROPERTY_STRING_VALUE_BY_ID = "select.PropertyStringValueByID"; - private static final String SELECT_PROPERTY_STRING_VALUE_BY_STRING = "select.PropertyStringValueByString"; + private static final String SELECT_PROPERTY_STRING_VALUE_BY_VALUE = "select.PropertyStringValueByValue"; private static final String INSERT_PROPERTY_STRING_VALUE = "insert.PropertyStringValue"; + private static final String SELECT_PROPERTY_DOUBLE_VALUE_BY_ID = "select.PropertyDoubleValueByID"; private static final String SELECT_PROPERTY_DOUBLE_VALUE_BY_VALUE = "select.PropertyDoubleValueByValue"; private static final String INSERT_PROPERTY_DOUBLE_VALUE = "insert.PropertyDoubleValue"; + + private static final String SELECT_PROPERTY_VALUE_BY_ID = "select.PropertyValueById"; + private static final String SELECT_PROPERTY_VALUE_BY_LOCAL_VALUE = "select.PropertyValueByLocalValue"; + private static final String SELECT_PROPERTY_VALUE_BY_DOUBLE_VALUE = "select.PropertyValueByDoubleValue"; + private static final String SELECT_PROPERTY_VALUE_BY_STRING_VALUE = "select.PropertyValueByStringValue"; private static final String INSERT_PROPERTY_VALUE = "insert.PropertyValue"; private SqlMapClientTemplate template; @@ -124,9 +131,10 @@ public class PropertyValueDAOImpl extends AbstractPropertyValueDAOImpl PropertyStringValueEntity entity = new PropertyStringValueEntity(); entity.setStringValue(value); List results = (List) template.queryForList( - SELECT_PROPERTY_STRING_VALUE_BY_STRING, + SELECT_PROPERTY_STRING_VALUE_BY_VALUE, entity); - // There double be several matches, so find the first one that matches exactly + // There double be several matches (if the database is case-insensitive), so find the first + // value that matches exactly. for (PropertyStringValueEntity resultEntity : results) { if (value.equals(resultEntity.getStringValue())) @@ -175,17 +183,16 @@ public class PropertyValueDAOImpl extends AbstractPropertyValueDAOImpl List results = (List) template.queryForList( SELECT_PROPERTY_DOUBLE_VALUE_BY_VALUE, entity); - // There coult be several matches, so find the first one that matches exactly - for (PropertyDoubleValueEntity resultEntity : results) + // There coult be several matches, so take the first one + if (results.size() > 0) { - if (value.equals(resultEntity.getDoubleValue())) - { - // Found a match - return resultEntity; - } + return results.get(0); + } + else + { + // No match + return null; } - // No real match - return null; } @Override @@ -206,77 +213,136 @@ public class PropertyValueDAOImpl extends AbstractPropertyValueDAOImpl @Override protected PropertyValueEntity findPropertyValueById(Long id) { - // TODO: Full query pulling back all related values - return null; + PropertyValueEntity entity = new PropertyValueEntity(); + entity.setId(id); + entity = (PropertyValueEntity) template.queryForObject( + SELECT_PROPERTY_VALUE_BY_ID, + entity); + // Done + return entity; } + @SuppressWarnings("unchecked") @Override protected PropertyValueEntity findPropertyValueByValue(Serializable value) { - // TODO: Find out persisted type and perform relevant query - return null; + // Get the actual type ID + Class clazz = (value == null ? Object.class : value.getClass()); + Pair> clazzPair = getPropertyClass(clazz); + if (clazzPair == null) + { + // Shortcut: There are no properties of this type + return null; + } + Long actualTypeId = clazzPair.getFirst(); + + // Construct the search parameters + PropertyValueEntity queryEntity = new PropertyValueEntity(); + queryEntity.setValue(value, converter); + queryEntity.setActualTypeId(actualTypeId); + + // How would it be persisted? + PersistedType persistedType = queryEntity.getPersistedTypeEnum(); + + // Query based on the the persistable value type + String query = null; + boolean singleResult = true; // false if multiple query results are possible + + // Handle each persisted type individually + + switch (persistedType) + { + case NULL: + case LONG: + query = SELECT_PROPERTY_VALUE_BY_LOCAL_VALUE; + break; + case DOUBLE: + query = SELECT_PROPERTY_VALUE_BY_DOUBLE_VALUE; + break; + case STRING: + query = SELECT_PROPERTY_VALUE_BY_STRING_VALUE; + singleResult = false; + break; + case SERIALIZABLE: + // No query + break; + default: + throw new IllegalStateException("Unhandled PersistedType value: " + persistedType); + } + + // Now query + PropertyValueEntity result = null; + if (query != null) + { + if (singleResult) + { + result = (PropertyValueEntity) template.queryForObject(query, queryEntity); + } + else + { + Serializable queryValue = queryEntity.getPersistedValue(); + List results = (List) template.queryForList( + query, + queryEntity); + for (PropertyValueEntity row : results) + { + if (queryValue.equals(row.getPersistedValue())) + { + // We have a match + result = row; + break; + } + } + } + } + + // Done + return result; } @Override protected PropertyValueEntity createPropertyValue(Serializable value) { - // Find out how it would be persisted - Pair persistedValuePair = converter.convertToPersistedType(value); - Serializable persistedValue = persistedValuePair.getSecond(); - - PropertyValueEntity entity = new PropertyValueEntity(); - - PersistedType persistedType = PropertyValueEntity.persistedTypesByOrdinal.get(persistedValuePair.getFirst()); - entity.setPersistedType(persistedType.getOrdinalNumber()); - // Handle each persisted type individually - if (persistedType.equals(PersistedType.NULL.getOrdinalNumber())) + // Get the actual type ID + Class clazz = (value == null ? Object.class : value.getClass()); + Pair> clazzPair = getOrCreatePropertyClass(clazz); + Long actualTypeId = clazzPair.getFirst(); + + // Construct the insert entity + PropertyValueEntity insertEntity = new PropertyValueEntity(); + insertEntity.setValue(value, converter); + insertEntity.setActualTypeId(actualTypeId); + + // Persist the persisted value + switch (insertEntity.getPersistedTypeEnum()) { - entity.setLongValue(PropertyValueEntity.LONG_ZERO); - } - else if (persistedType.equals(PersistedType.BOOLEAN.getOrdinalNumber())) - { - Boolean booleanValue = (Boolean) persistedValue; - entity.setLongValue( - booleanValue.booleanValue() ? PropertyValueEntity.LONG_ONE : PropertyValueEntity.LONG_ZERO); - } - else if (persistedType.equals(PersistedType.LONG.getOrdinalNumber())) - { - Long longValue = (Long) persistedValue; - entity.setLongValue(longValue); - } - else if (persistedType.equals(PersistedType.DOUBLE.getOrdinalNumber())) - { - Double doubleValue = (Double) persistedValue; - // Look it up - Pair entityPair = getOrCreatePropertyDoubleValue(doubleValue); - entity.setLongValue(entityPair.getFirst()); - entity.setDoubleValue(doubleValue); - } - else if (persistedType.equals(PersistedType.STRING.getOrdinalNumber())) - { - String stringValue = (String) persistedValue; - // Look it up - Pair entityPair = getOrCreatePropertyStringValue(stringValue); - entity.setLongValue(entityPair.getFirst()); - entity.setStringValue(stringValue); - } - else if (persistedType.equals(PersistedType.SERIALIZABLE.getOrdinalNumber())) - { - throw new UnsupportedOperationException("Serializable not done, yet."); - } - else - { - throw new IllegalStateException( - "The persisted property is not valid: \n" + - " Raw Value: " + value + "\n" + - " Persisted Value: " + persistedValuePair + "\n" + - " Converter:" + converter.getClass()); + case DOUBLE: + Double doubleValue = insertEntity.getDoubleValue(); + Pair insertDoublePair = getOrCreatePropertyDoubleValue(doubleValue); + insertEntity.setLongValue(insertDoublePair.getFirst()); + break; + case STRING: + String stringValue = insertEntity.getStringValue(); + Pair insertStringPair = getOrCreatePropertyStringValue(stringValue); + insertEntity.setLongValue(insertStringPair.getFirst()); + break; + case SERIALIZABLE: + throw new UnsupportedOperationException("Serializable not supported, yet."); +// Pair insertSerializablePair = getOrCreatePropertySerializableValue(value); +// insertEntity.setLongValue(insertSerializablePair.getFirst()); +// break; + case NULL: + case LONG: + // Do nothing for these + break; + default: + throw new IllegalStateException("Unknown PersistedType enum: " + insertEntity.getPersistedTypeEnum()); } // Persist the entity - Long id = (Long) template.insert(INSERT_PROPERTY_VALUE, entity); - entity.setId(id); + Long id = (Long) template.insert(INSERT_PROPERTY_VALUE, insertEntity); + insertEntity.setId(id); // Done - return entity; + return insertEntity; } }