diff --git a/config/alfresco/dao/dao-context.xml b/config/alfresco/dao/dao-context.xml index 3c1de69b01..bea7e028b5 100644 --- a/config/alfresco/dao/dao-context.xml +++ b/config/alfresco/dao/dao-context.xml @@ -45,7 +45,12 @@ + + + + + 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 b0f12d0cc7..fd7dd03230 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 @@ -13,8 +13,16 @@ CREATE TABLE alf_prop_class java_class_name VARCHAR(255) NOT NULL, java_class_name_short VARCHAR(32) NOT NULL, java_class_name_crc BIGINT NOT NULL, - UNIQUE INDEX idx_prop_class_crc (java_class_name_crc, java_class_name_short), - INDEX idx_prop_class_class (java_class_name), + UNIQUE INDEX idx_alf_prop_class_crc (java_class_name_crc, java_class_name_short), + INDEX idx_alf_prop_class_class (java_class_name), + PRIMARY KEY (id) +) ENGINE=InnoDB; + +CREATE TABLE alf_prop_double_value +( + id BIGINT NOT NULL AUTO_INCREMENT, + double_value DOUBLE NOT NULL, + INDEX idx_alf_prop_dbl_val (double_value), PRIMARY KEY (id) ) ENGINE=InnoDB; @@ -22,19 +30,25 @@ CREATE TABLE alf_prop_string_value ( id BIGINT NOT NULL AUTO_INCREMENT, string_value text NOT NULL, - INDEX idx_prop_str_val (string_value(64)), + INDEX idx_alf_prop_str_val (string_value(64)), PRIMARY KEY (id) ) ENGINE=InnoDB; ---CREATE TABLE alf_prop_string_value ---( --- id BIGINT NOT NULL AUTO_INCREMENT, --- string_value text NOT NULL, --- prop_class_id BIGINT NOT NULL, --- INDEX idx_prop_str_val (string_value(64)), --- CONSTRAINT fk_prop_str_classid FOREIGN KEY (prop_class_id) REFERENCES alf_prop_class (id), --- PRIMARY KEY (id) ---) ENGINE=InnoDB; +CREATE TABLE alf_prop_serializable_value +( + id BIGINT NOT NULL AUTO_INCREMENT, + serializable_value BLOB NOT NULL, + PRIMARY KEY (id) +) ENGINE=InnoDB; + +CREATE TABLE alf_prop_value +( + id BIGINT NOT NULL AUTO_INCREMENT, + persisted_type TINYINT NOT NULL, + long_value BIGINT NOT NULL, + INDEX idx_alf_prop_val (persisted_type, 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 314b20fd91..472675533b 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 @@ -12,6 +12,8 @@ + + @@ -27,6 +29,14 @@ + + + + + + + + @@ -56,6 +66,16 @@ values (#stringValue#) + + insert into alf_prop_double_value (double_value) + values (#doubleValue#) + + + + insert into alf_prop_value (persisted_type, long_value) + values (#persistedType#, #longValue#) + + @@ -101,4 +121,24 @@ string_value = #stringValue# + + + + + + \ No newline at end of file diff --git a/config/alfresco/ibatis/org.hibernate.dialect.MySQLInnoDBDialect/propval-insert-SqlMap.xml b/config/alfresco/ibatis/org.hibernate.dialect.MySQLInnoDBDialect/propval-insert-SqlMap.xml index d51a6afb57..5b66d393ef 100644 --- a/config/alfresco/ibatis/org.hibernate.dialect.MySQLInnoDBDialect/propval-insert-SqlMap.xml +++ b/config/alfresco/ibatis/org.hibernate.dialect.MySQLInnoDBDialect/propval-insert-SqlMap.xml @@ -20,4 +20,18 @@ + + + + KEY_COLUMN:GENERATED_KEY + + + + + + + KEY_COLUMN:GENERATED_KEY + + + \ No newline at end of file diff --git a/config/alfresco/ibatis/propval-SqlMapConfig.xml b/config/alfresco/ibatis/propval-SqlMapConfig.xml index 422e5800b9..a55ef2ee71 100644 --- a/config/alfresco/ibatis/propval-SqlMapConfig.xml +++ b/config/alfresco/ibatis/propval-SqlMapConfig.xml @@ -8,5 +8,5 @@ - + diff --git a/source/java/org/alfresco/repo/domain/propval/AbstractPropertyValueDAOImpl.java b/source/java/org/alfresco/repo/domain/propval/AbstractPropertyValueDAOImpl.java index 4cc26248cc..806a01331e 100644 --- a/source/java/org/alfresco/repo/domain/propval/AbstractPropertyValueDAOImpl.java +++ b/source/java/org/alfresco/repo/domain/propval/AbstractPropertyValueDAOImpl.java @@ -31,6 +31,7 @@ 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.domain.CrcHelper; +import org.alfresco.repo.domain.propval.PropertyValueEntity.PersistedType; import org.alfresco.util.Pair; /** @@ -46,9 +47,15 @@ public abstract class AbstractPropertyValueDAOImpl implements PropertyValueDAO { private static final String CACHE_REGION_PROPERTY_CLASS = "PropertyClass"; private static final String CACHE_REGION_PROPERTY_STRING_VALUE = "PropertyStringValue"; + private static final String CACHE_REGION_PROPERTY_DOUBLE_VALUE = "PropertyDoubleValue"; + private static final String CACHE_REGION_PROPERTY_VALUE = "PropertyValue"; + + protected PropertyTypeConverter converter; private final PropertyClassCallbackDAO propertyClassDaoCallback; private final PropertyStringValueCallbackDAO propertyStringValueCallback; + private final PropertyDoubleValueCallbackDAO propertyDoubleValueCallback; + private final PropertyValueCallbackDAO propertyValueCallback; /** * Cache for the property class:
* KEY: ID
@@ -63,6 +70,20 @@ public abstract class AbstractPropertyValueDAOImpl implements PropertyValueDAO * VALUE KEY: Short string-crc pair ({@link CrcHelper#getStringCrcPair(String, int, boolean, boolean)})
*/ private EntityLookupCache> propertyStringValueCache; + /** + * Cache for the property double value:
+ * KEY: ID
+ * VALUE: The Double instance
+ * VALUE KEY: The value itself
+ */ + private EntityLookupCache propertyDoubleValueCache; + /** + * Cache for the property value:
+ * KEY: ID
+ * VALUE: The Serializable instance
+ * VALUE KEY: A value key based on the persisted type
+ */ + private EntityLookupCache propertyValueCache; /** * Default constructor. @@ -74,11 +95,23 @@ public abstract class AbstractPropertyValueDAOImpl implements PropertyValueDAO { this.propertyClassDaoCallback = new PropertyClassCallbackDAO(); this.propertyStringValueCallback = new PropertyStringValueCallbackDAO(); + this.propertyDoubleValueCallback = new PropertyDoubleValueCallbackDAO(); + this.propertyValueCallback = new PropertyValueCallbackDAO(); this.propertyClassCache = new EntityLookupCache, String>(propertyClassDaoCallback); this.propertyStringValueCache = new EntityLookupCache>(propertyStringValueCallback); + this.propertyDoubleValueCache = new EntityLookupCache(propertyDoubleValueCallback); + this.propertyValueCache = new EntityLookupCache(propertyValueCallback); } - + + /** + * @param converter the converter that translates between external and persisted values + */ + public void setConverter(PropertyTypeConverter converter) + { + this.converter = converter; + } + /** * Set the cache to use for alf_prop_class lookups (optional). * @@ -105,12 +138,42 @@ public abstract class AbstractPropertyValueDAOImpl implements PropertyValueDAO propertyStringValueCallback); } + /** + * Set the cache to use for alf_prop_double_value lookups (optional). + * + * @param propertyDoubleValueCache the cache of IDs to property values + */ + public void setPropertyDoubleValueCache(SimpleCache propertyDoubleValueCache) + { + this.propertyDoubleValueCache = new EntityLookupCache( + propertyDoubleValueCache, + CACHE_REGION_PROPERTY_DOUBLE_VALUE, + propertyDoubleValueCallback); + } + + /** + * Set the cache to use for alf_prop_value lookups (optional). + * + * @param propertyValueCache the cache of IDs to property values + */ + public void setPropertyValueCache(SimpleCache propertyValueCache) + { + this.propertyValueCache = new EntityLookupCache( + propertyValueCache, + CACHE_REGION_PROPERTY_VALUE, + propertyValueCallback); + } + //================================ // 'alf_prop_class' accessors //================================ - public Pair> getPropertyClass(Long id) + public Pair> getPropertyClassById(Long id) { + if (id == null) + { + throw new IllegalArgumentException("Cannot look up entity by null ID."); + } Pair> entityPair = propertyClassCache.getByKey(id); if (entityPair == null) { @@ -121,12 +184,20 @@ public abstract class AbstractPropertyValueDAOImpl implements PropertyValueDAO public Pair> getPropertyClass(Class value) { + if (value == null) + { + throw new IllegalArgumentException("Property class cannot be null"); + } Pair> entityPair = propertyClassCache.getByValue(value); return entityPair; } public Pair> getOrCreatePropertyClass(Class value) { + if (value == null) + { + throw new IllegalArgumentException("Property class cannot be null"); + } Pair> entityPair = propertyClassCache.getOrCreateByValue(value); return entityPair; } @@ -136,15 +207,15 @@ public abstract class AbstractPropertyValueDAOImpl implements PropertyValueDAO */ private class PropertyClassCallbackDAO implements EntityLookupCallbackDAO, String> { - private final Pair> convertEntityToPair(PropertyClassEntity propertyClassEntity) + private final Pair> convertEntityToPair(PropertyClassEntity entity) { - if (propertyClassEntity == null) + if (entity == null) { return null; } else { - return propertyClassEntity.getEntityPair(); + return entity.getEntityPair(); } } @@ -180,24 +251,36 @@ public abstract class AbstractPropertyValueDAOImpl implements PropertyValueDAO // 'alf_prop_string_value' accessors //================================ - public Pair getPropertyStringValue(Long id) + public Pair getPropertyStringValueById(Long id) { + if (id == null) + { + throw new IllegalArgumentException("Cannot look up entity by null ID."); + } Pair entityPair = propertyStringValueCache.getByKey(id); if (entityPair == null) { - throw new AlfrescoRuntimeException("No property class exists for ID " + id); + throw new AlfrescoRuntimeException("No property string value exists for ID " + id); } return entityPair; } public Pair getPropertyStringValue(String value) { + if (value == null) + { + throw new IllegalArgumentException("Persisted string values cannot be null"); + } Pair entityPair = propertyStringValueCache.getByValue(value); return entityPair; } public Pair getOrCreatePropertyStringValue(String value) { + if (value == null) + { + throw new IllegalArgumentException("Persisted string values cannot be null"); + } Pair entityPair = propertyStringValueCache.getOrCreateByValue(value); return entityPair; } @@ -207,15 +290,15 @@ public abstract class AbstractPropertyValueDAOImpl implements PropertyValueDAO */ private class PropertyStringValueCallbackDAO implements EntityLookupCallbackDAO> { - private final Pair convertEntityToPair(PropertyStringValueEntity propertyStringValueEntity) + private final Pair convertEntityToPair(PropertyStringValueEntity entity) { - if (propertyStringValueEntity == null) + if (entity == null) { return null; } else { - return propertyStringValueEntity.getEntityPair(); + return entity.getEntityPair(); } } @@ -247,4 +330,185 @@ public abstract class AbstractPropertyValueDAOImpl implements PropertyValueDAO protected abstract PropertyStringValueEntity findStringValueByValue(String value); protected abstract PropertyStringValueEntity createStringValue(String value); + //================================ + // 'alf_prop_double_value' accessors + //================================ + + public Pair getPropertyDoubleValueById(Long id) + { + if (id == null) + { + throw new IllegalArgumentException("Cannot look up entity by null ID."); + } + Pair entityPair = propertyDoubleValueCache.getByKey(id); + if (entityPair == null) + { + throw new AlfrescoRuntimeException("No property double value exists for ID " + id); + } + return entityPair; + } + + public Pair getPropertyDoubleValue(Double value) + { + if (value == null) + { + throw new IllegalArgumentException("Persisted double values cannot be null"); + } + Pair entityPair = propertyDoubleValueCache.getByValue(value); + return entityPair; + } + + public Pair getOrCreatePropertyDoubleValue(Double value) + { + if (value == null) + { + throw new IllegalArgumentException("Persisted double values cannot be null"); + } + Pair entityPair = propertyDoubleValueCache.getOrCreateByValue(value); + return (Pair) entityPair; + } + + /** + * Callback for alf_prop_double_value DAO. + */ + private class PropertyDoubleValueCallbackDAO implements EntityLookupCallbackDAO + { + private final Pair convertEntityToPair(PropertyDoubleValueEntity entity) + { + if (entity == null) + { + return null; + } + else + { + return entity.getEntityPair(); + } + } + + public Double getValueKey(Double value) + { + return value; + } + + public Pair createValue(Double value) + { + PropertyDoubleValueEntity entity = createDoubleValue(value); + return convertEntityToPair(entity); + } + + public Pair findByKey(Long key) + { + PropertyDoubleValueEntity entity = findDoubleValueById(key); + return convertEntityToPair(entity); + } + + public Pair findByValue(Double value) + { + PropertyDoubleValueEntity entity = findDoubleValueByValue(value); + return convertEntityToPair(entity); + } + } + + protected abstract PropertyDoubleValueEntity findDoubleValueById(Long id); + protected abstract PropertyDoubleValueEntity findDoubleValueByValue(Double value); + protected abstract PropertyDoubleValueEntity createDoubleValue(Double value); + + //================================ + // 'alf_prop_value' accessors + //================================ + + public Pair getPropertyValueById(Long id) + { + if (id == null) + { + throw new IllegalArgumentException("Cannot look up entity by null ID."); + } + Pair entityPair = propertyValueCache.getByKey(id); + if (entityPair == null) + { + throw new AlfrescoRuntimeException("No property value exists for ID " + id); + } + return entityPair; + } + + public Pair getPropertyValue(Serializable value) + { + Pair entityPair = propertyValueCache.getByValue(value); + return entityPair; + } + + public Pair getOrCreatePropertyValue(Serializable value) + { + Pair entityPair = propertyValueCache.getOrCreateByValue(value); + return (Pair) entityPair; + } + + /** + * Callback for alf_prop_value DAO. + */ + private class PropertyValueCallbackDAO implements EntityLookupCallbackDAO + { + private final Pair convertEntityToPair(PropertyValueEntity entity) + { + if (entity == null) + { + return null; + } + else + { + return entity.getEntityPair(); + } + } + + public Serializable getValueKey(Serializable value) + { + // Find out how it would be persisted + Pair persistedValuePair = converter.convertToPersistedType(value); + // We don't return keys for pure Serializable instances + if (persistedValuePair.getFirst().equals(PersistedType.SERIALIZABLE.getOrdinalNumber())) + { + // It will be Serialized, so no key + return null; + } + else if (value instanceof String) + { + return CrcHelper.getStringCrcPair((String)value, 128, true, true); + } + else + { + // We've dodged Serializable and String; everything else is OK as a key. + return persistedValuePair; + } + } + + public Pair createValue(Serializable value) + { + PropertyValueEntity entity = createPropertyValue(value); + return convertEntityToPair(entity); + } + + public Pair findByKey(Long key) + { + PropertyValueEntity entity = findPropertyValueById(key); + return convertEntityToPair(entity); + } + + 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); + } + } + + protected abstract PropertyValueEntity findPropertyValueById(Long id); + protected abstract PropertyValueEntity findPropertyValueByValue(Serializable value); + protected abstract PropertyValueEntity createPropertyValue(Serializable value); } diff --git a/source/java/org/alfresco/repo/domain/propval/DefaultPropertyTypeConverter.java b/source/java/org/alfresco/repo/domain/propval/DefaultPropertyTypeConverter.java new file mode 100644 index 0000000000..4674ee1d31 --- /dev/null +++ b/source/java/org/alfresco/repo/domain/propval/DefaultPropertyTypeConverter.java @@ -0,0 +1,138 @@ +/* + * 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; + +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}. + * + * @author Derek Hulley + * @since 3.3 + */ +public class DefaultPropertyTypeConverter implements PropertyTypeConverter +{ + private static final Log logger = LogFactory.getLog(DefaultPropertyTypeConverter.class); + + /** + * Default constructor + */ + public DefaultPropertyTypeConverter() + { + } + + /** + * {@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) + { + 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); + } + } +} diff --git a/source/java/org/alfresco/repo/domain/propval/PropertyDoubleValueEntity.java b/source/java/org/alfresco/repo/domain/propval/PropertyDoubleValueEntity.java new file mode 100644 index 0000000000..0f70fdb4f6 --- /dev/null +++ b/source/java/org/alfresco/repo/domain/propval/PropertyDoubleValueEntity.java @@ -0,0 +1,107 @@ +/* + * 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; + +import org.alfresco.util.EqualsHelper; +import org.alfresco.util.Pair; + +/** + * Entity bean for alf_prop_numeric_value table. + * + * @author Derek Hulley + * @since 3.3 + */ +public class PropertyDoubleValueEntity +{ + private Long id; + private Double doubleValue; + + public PropertyDoubleValueEntity() + { + } + + @Override + public int hashCode() + { + return (doubleValue == null ? 0 : doubleValue.hashCode()); + } + + @Override + public boolean equals(Object obj) + { + if (this == obj) + { + return true; + } + else if (obj != null && obj instanceof PropertyDoubleValueEntity) + { + PropertyDoubleValueEntity that = (PropertyDoubleValueEntity) obj; + return EqualsHelper.nullSafeEquals(this.doubleValue, that.doubleValue); + } + else + { + return false; + } + } + + @Override + public String toString() + { + StringBuilder sb = new StringBuilder(512); + sb.append("PropertyNumericValueEntity") + .append("[ ID=").append(id) + .append(", value=").append(doubleValue) + .append("]"); + return sb.toString(); + } + + /** + * @return Returns the ID-value pair + */ + public Pair getEntityPair() + { + return new Pair(id, doubleValue); + } + + public Long getId() + { + return id; + } + + public void setId(Long id) + { + this.id = id; + } + + public double getDoubleValue() + { + return doubleValue; + } + + public void setDoubleValue(Double doubleValue) + { + this.doubleValue = doubleValue; + } +} diff --git a/source/java/org/alfresco/repo/domain/propval/PropertyTypeConverter.java b/source/java/org/alfresco/repo/domain/propval/PropertyTypeConverter.java new file mode 100644 index 0000000000..293ff4ea1c --- /dev/null +++ b/source/java/org/alfresco/repo/domain/propval/PropertyTypeConverter.java @@ -0,0 +1,55 @@ +/* + * 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; + +import java.io.Serializable; + +import org.alfresco.util.Pair; + +/** + * Interface for converters that + * + * @author Derek Hulley + * @since 3.3 + */ +public interface PropertyTypeConverter +{ + /** + * Convert an external value into a persisted type and persistable value. + * + * @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); +} diff --git a/source/java/org/alfresco/repo/domain/propval/PropertyValueDAO.java b/source/java/org/alfresco/repo/domain/propval/PropertyValueDAO.java index afb0f3c913..7a0320c619 100644 --- a/source/java/org/alfresco/repo/domain/propval/PropertyValueDAO.java +++ b/source/java/org/alfresco/repo/domain/propval/PropertyValueDAO.java @@ -24,6 +24,8 @@ */ package org.alfresco.repo.domain.propval; +import java.io.Serializable; + import org.alfresco.util.Pair; /** @@ -36,31 +38,77 @@ public interface PropertyValueDAO { /** * alf_prop_class accessor + * + * @param id the ID (may not be null) */ - Pair> getPropertyClass(Long id); - + Pair> getPropertyClassById(Long id); /** * alf_prop_class accessor + * + * @param value the value to find the ID for (may not be null) */ Pair> getPropertyClass(Class value); - /** * alf_prop_class accessor + * + * @param value the value to find the ID for (may not be null) */ Pair> getOrCreatePropertyClass(Class value); /** * alf_prop_string_value accessor + * + * @param id the ID (may not be null) */ - Pair getPropertyStringValue(Long id); - + Pair getPropertyStringValueById(Long id); /** * alf_prop_string_value accessor + * + * @param value the value to find the ID for (may not be null) */ Pair getPropertyStringValue(String value); - /** * alf_prop_string_value accessor + * + * @param value the value to find the ID for (may not be null) */ Pair getOrCreatePropertyStringValue(String value); + + /** + * alf_prop_double_value accessor + * + * @param id the ID (may not be null) + */ + Pair getPropertyDoubleValueById(Long id); + /** + * alf_prop_double_value accessor + * + * @param value the value to find the ID for (may not be null) + */ + Pair getPropertyDoubleValue(Double value); + /** + * alf_prop_double_value accessor + * + * @param value the value to find the ID for (may not be null) + */ + Pair getOrCreatePropertyDoubleValue(Double value); + + /** + * alf_prop_value accessor + * + * @param id the ID (may not be null) + */ + Pair getPropertyValueById(Long id); + /** + * alf_prop_value accessor + * + * @param value the value to find the ID for (may be null) + */ + Pair getPropertyValue(Serializable value); + /** + * alf_prop_value accessor + * + * @param value the value to find the ID for (may be null) + */ + Pair getOrCreatePropertyValue(Serializable value); } diff --git a/source/java/org/alfresco/repo/domain/propval/PropertyValueDAOTest.java b/source/java/org/alfresco/repo/domain/propval/PropertyValueDAOTest.java index af955df2c5..e4b8bde6d5 100644 --- a/source/java/org/alfresco/repo/domain/propval/PropertyValueDAOTest.java +++ b/source/java/org/alfresco/repo/domain/propval/PropertyValueDAOTest.java @@ -78,7 +78,7 @@ public class PropertyValueDAOTest extends TestCase { public Void execute() throws Throwable { - Pair> checkPair1 = propertyValueDAO.getPropertyClass(clazzEntityPair.getFirst()); + Pair> checkPair1 = propertyValueDAO.getPropertyClassById(clazzEntityPair.getFirst()); assertEquals(clazzEntityPair, checkPair1); Pair> checkPair2 = propertyValueDAO.getPropertyClass(clazzEntityPair.getSecond()); assertEquals(clazzEntityPair, checkPair2); @@ -92,7 +92,7 @@ public class PropertyValueDAOTest extends TestCase { public Void execute() throws Throwable { - propertyValueDAO.getPropertyClass(Long.MIN_VALUE); + propertyValueDAO.getPropertyClassById(Long.MIN_VALUE); return null; } }; @@ -121,7 +121,7 @@ public class PropertyValueDAOTest extends TestCase public void testPropertyStringValue() throws Exception { - final String stringValue = "One Two Three"; + final String stringValue = "One Two Three - " + System.currentTimeMillis(); final String stringValueUpper = stringValue.toUpperCase(); final String stringValueLower = stringValue.toLowerCase(); RetryingTransactionCallback> createStringCallback = new RetryingTransactionCallback>() @@ -168,4 +168,87 @@ public class PropertyValueDAOTest extends TestCase assertEquals(stringValueUpper, stringUpperEntityPair.getSecond()); 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); +// RetryingTransactionCallback> createValueCallback = new RetryingTransactionCallback>() +// { +// public Pair execute() throws Throwable +// { +// // Get the classes +// return propertyValueDAO.getOrCreatePropertyNumericValue(longValue); +// } +// }; +// final Pair entityPair = txnHelper.doInTransaction(createValueCallback, false); +// assertNotNull(entityPair); +// assertEquals(longValue, entityPair.getSecond()); +// +// RetryingTransactionCallback> getValueCallback = new RetryingTransactionCallback>() +// { +// public Pair execute() throws Throwable +// { +// // Get the classes +// return propertyValueDAO.getPropertyDoubleValue(longValue); +// } +// }; +// final Pair entityPairCheck = txnHelper.doInTransaction(getValueCallback, false); +// assertNotNull(entityPairCheck); +// assertEquals(entityPair, entityPairCheck); +// } + + public void testPropertyDoubleValue() throws Exception + { + final Double doubleValue = Double.valueOf(1.7976931348623E+308); + RetryingTransactionCallback> createValueCallback = new RetryingTransactionCallback>() + { + public Pair execute() throws Throwable + { + // Get the classes + return propertyValueDAO.getOrCreatePropertyDoubleValue(doubleValue); + } + }; + final Pair entityPair = txnHelper.doInTransaction(createValueCallback, false); + assertNotNull(entityPair); + assertEquals(doubleValue, entityPair.getSecond()); + + RetryingTransactionCallback> getValueCallback = new RetryingTransactionCallback>() + { + public Pair execute() throws Throwable + { + // Get the classes + return propertyValueDAO.getPropertyDoubleValue(doubleValue); + } + }; + final Pair entityPairCheck = txnHelper.doInTransaction(getValueCallback, false); + assertNotNull(entityPairCheck); + assertEquals(entityPair, entityPairCheck); + } } diff --git a/source/java/org/alfresco/repo/domain/propval/PropertyValueEntity.java b/source/java/org/alfresco/repo/domain/propval/PropertyValueEntity.java new file mode 100644 index 0000000000..e2168c12f7 --- /dev/null +++ b/source/java/org/alfresco/repo/domain/propval/PropertyValueEntity.java @@ -0,0 +1,377 @@ +/* + * 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; + +import java.io.Serializable; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +import org.alfresco.util.EqualsHelper; +import org.alfresco.util.Pair; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + + +/** + * Entity bean for alf_prop_value table. + *

+ * Values here are either simple values that can be stored in a long + * or will be references to data in other tables. + * + * @author Derek Hulley + * @since 3.3 + */ +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); + + /** + * Enumeration of persisted types for alf_prop_value.persisted_type. + *

+ * This enumeration is a helper for the default implementation of the {@link PropertyTypeConverter} + * and should not be used in public interfaces. + * + * @author Derek Hulley + * @since 3.3 + */ + public static enum PersistedType + { + NULL + { + @Override + public Short getOrdinalNumber() + { + return ORDINAL_NULL; + } + @Override + public Class getAssociatedClass() + { + 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 + public Short getOrdinalNumber() + { + return ORDINAL_LONG; + } + @Override + public Class getAssociatedClass() + { + return Long.class; + } + }, + DOUBLE + { + @Override + public Short getOrdinalNumber() + { + return ORDINAL_DOUBLE; + } + @Override + public Class getAssociatedClass() + { + return Double.class; + } + }, + STRING + { + @Override + public Short getOrdinalNumber() + { + return ORDINAL_STRING; + } + @Override + public Class getAssociatedClass() + { + return String.class; + } + }, + SERIALIZABLE + { + @Override + public Short getOrdinalNumber() + { + return ORDINAL_SERIALIZABLE; + } + @Override + public Class getAssociatedClass() + { + return Serializable.class; + } + }; + + /** + * Fetch the numerical value that will represent the the persisted type. This is done + * explicitly to prevent ordering issues if further types are added. + * + * @return Returns the ordinal number + */ + public abstract Short getOrdinalNumber(); + + /** + * Get the persisted type's class. This is used for determining the source type when + * converting from persisted values. + * + * @return Returns the class associated with the persisted type + */ + public abstract Class getAssociatedClass(); + } + + public static final Pair PERSISTED_TYPE_NULL; + /** + * An unmodifiable map of persisted type enums keyed by their ordinal number + */ + public static final Map persistedTypesByOrdinal; + + /** + * An unmodifiable map of persisted type enums keyed by the classes they store + */ + public static final Map, PersistedType> persistedTypesByClass; + + static + { + // Create a pair for null values + PERSISTED_TYPE_NULL = new Pair(PersistedType.NULL.getOrdinalNumber(), new Long(0)); + // Create the map of ordinal-type + Map mapOrdinal = new HashMap(15); + for (PersistedType persistedType : PersistedType.values()) + { + mapOrdinal.put(persistedType.getOrdinalNumber(), persistedType); + } + 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(Short.class, PersistedType.LONG); + mapClass.put(Integer.class, PersistedType.LONG); + mapClass.put(Long.class, PersistedType.LONG); + mapClass.put(Float.class, PersistedType.DOUBLE); + mapClass.put(Double.class, PersistedType.DOUBLE); + mapClass.put(String.class, PersistedType.STRING); + mapClass.put(Date.class, PersistedType.LONG); + persistedTypesByClass = Collections.unmodifiableMap(mapClass); + } + + private static final Log logger = LogFactory.getLog(PropertyValueEntity.class); + + private Long id; + private Short persistedType; + private Long longValue; + private String stringValue; + private Double doubleValue; + private Serializable serializableValue; + + public PropertyValueEntity() + { + this.persistedType = PersistedType.NULL.getOrdinalNumber(); + this.longValue = LONG_ZERO; + } + + @Override + public int hashCode() + { + return (persistedType == null ? 0 : persistedType.intValue()) + (longValue == null ? 0 : longValue.intValue()); + } + + @Override + public boolean equals(Object obj) + { + if (this == obj) + { + return true; + } + else if (obj != null && obj instanceof PropertyValueEntity) + { + PropertyValueEntity that = (PropertyValueEntity) obj; + return EqualsHelper.nullSafeEquals(this.persistedType, that.persistedType) && + EqualsHelper.nullSafeEquals(this.longValue, that.longValue); + } + else + { + return false; + } + } + + @Override + public String toString() + { + StringBuilder sb = new StringBuilder(512); + sb.append("PropertyValueEntity") + .append("[ ID=").append(id) + .append(", type=").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() + { + if (persistedType.equals(PersistedType.NULL.getOrdinalNumber())) + { + return null; + } + else if (persistedType.equals(PersistedType.BOOLEAN.getOrdinalNumber())) + { + return (longValue.longValue() > 0 ? Boolean.TRUE : Boolean.FALSE); + } + else if (persistedType.equals(PersistedType.LONG.getOrdinalNumber())) + { + 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) + { + return serializableValue; + } + else if (doubleValue != null) + { + return doubleValue; + } + else if (stringValue != null) + { + return stringValue; + } + else + { + return longValue; + } + } + } + + public Long getId() + { + return id; + } + + public void setId(Long id) + { + this.id = id; + } + + public Short getPersistedType() + { + return persistedType; + } + + public void setPersistedType(Short persistedType) + { + this.persistedType = persistedType; + } + + public Long getLongValue() + { + return longValue; + } + + public void setLongValue(Long longValue) + { + this.longValue = longValue; + } + + public String getStringValue() + { + return stringValue; + } + + public void setStringValue(String stringValue) + { + this.stringValue = stringValue; + } + + public Double getDoubleValue() + { + return doubleValue; + } + + public void setDoubleValue(Double doubleValue) + { + this.doubleValue = doubleValue; + } + + public Serializable getSerializableValue() + { + return serializableValue; + } + + public void setSerializableValue(Serializable serializableValue) + { + this.serializableValue = serializableValue; + } +} 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 5290efddad..56eb2860a6 100644 --- a/source/java/org/alfresco/repo/domain/propval/ibatis/PropertyValueDAOImpl.java +++ b/source/java/org/alfresco/repo/domain/propval/ibatis/PropertyValueDAOImpl.java @@ -24,11 +24,16 @@ */ package org.alfresco.repo.domain.propval.ibatis; +import java.io.Serializable; import java.util.List; import org.alfresco.repo.domain.propval.AbstractPropertyValueDAOImpl; import org.alfresco.repo.domain.propval.PropertyClassEntity; +import org.alfresco.repo.domain.propval.PropertyDoubleValueEntity; import org.alfresco.repo.domain.propval.PropertyStringValueEntity; +import org.alfresco.repo.domain.propval.PropertyValueEntity; +import org.alfresco.repo.domain.propval.PropertyValueEntity.PersistedType; +import org.alfresco.util.Pair; import org.springframework.orm.ibatis.SqlMapClientTemplate; /** @@ -39,13 +44,16 @@ import org.springframework.orm.ibatis.SqlMapClientTemplate; */ public class PropertyValueDAOImpl extends AbstractPropertyValueDAOImpl { - private static final Long VERSION_ONE = new Long(1L); 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 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 INSERT_PROPERTY_VALUE = "insert.PropertyValue"; private SqlMapClientTemplate template; @@ -54,12 +62,18 @@ public class PropertyValueDAOImpl extends AbstractPropertyValueDAOImpl this.template = sqlMapClientTemplate; } + //================================ + // 'alf_prop_class' accessors + //================================ + @Override protected PropertyClassEntity findClassById(Long id) { PropertyClassEntity entity = new PropertyClassEntity(); entity.setId(id); - entity = (PropertyClassEntity) template.queryForObject(SELECT_PROPERTY_CLASS_BY_ID, entity); + entity = (PropertyClassEntity) template.queryForObject( + SELECT_PROPERTY_CLASS_BY_ID, + entity); // Done return entity; } @@ -69,7 +83,9 @@ public class PropertyValueDAOImpl extends AbstractPropertyValueDAOImpl { PropertyClassEntity entity = new PropertyClassEntity(); entity.setJavaClass(value); - entity = (PropertyClassEntity) template.queryForObject(SELECT_PROPERTY_CLASS_BY_NAME, entity); + entity = (PropertyClassEntity) template.queryForObject( + SELECT_PROPERTY_CLASS_BY_NAME, + entity); // Done return entity; } @@ -85,12 +101,18 @@ public class PropertyValueDAOImpl extends AbstractPropertyValueDAOImpl return entity; } + //================================ + // 'alf_prop_string_value' accessors + //================================ + @Override protected PropertyStringValueEntity findStringValueById(Long id) { PropertyStringValueEntity entity = new PropertyStringValueEntity(); entity.setId(id); - entity = (PropertyStringValueEntity) template.queryForObject(SELECT_PROPERTY_STRING_VALUE_BY_ID, entity); + entity = (PropertyStringValueEntity) template.queryForObject( + SELECT_PROPERTY_STRING_VALUE_BY_ID, + entity); // Done return entity; } @@ -101,8 +123,10 @@ public class PropertyValueDAOImpl extends AbstractPropertyValueDAOImpl { PropertyStringValueEntity entity = new PropertyStringValueEntity(); entity.setStringValue(value); - List results = (List) template.queryForList(SELECT_PROPERTY_STRING_VALUE_BY_STRING, entity); - // There are several matches, so find the first one that matches exactly + List results = (List) template.queryForList( + SELECT_PROPERTY_STRING_VALUE_BY_STRING, + entity); + // There double be several matches, so find the first one that matches exactly for (PropertyStringValueEntity resultEntity : results) { if (value.equals(resultEntity.getStringValue())) @@ -125,4 +149,134 @@ public class PropertyValueDAOImpl extends AbstractPropertyValueDAOImpl // Done return entity; } + + //================================ + // 'alf_prop_double_value' accessors + //================================ + + @Override + protected PropertyDoubleValueEntity findDoubleValueById(Long id) + { + PropertyDoubleValueEntity entity = new PropertyDoubleValueEntity(); + entity.setId(id); + entity = (PropertyDoubleValueEntity) template.queryForObject( + SELECT_PROPERTY_DOUBLE_VALUE_BY_ID, + entity); + // Done + return entity; + } + + @SuppressWarnings("unchecked") + @Override + protected PropertyDoubleValueEntity findDoubleValueByValue(Double value) + { + PropertyDoubleValueEntity entity = new PropertyDoubleValueEntity(); + entity.setDoubleValue(value); + 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) + { + if (value.equals(resultEntity.getDoubleValue())) + { + // Found a match + return resultEntity; + } + } + // No real match + return null; + } + + @Override + protected PropertyDoubleValueEntity createDoubleValue(Double value) + { + PropertyDoubleValueEntity entity = new PropertyDoubleValueEntity(); + entity.setDoubleValue(value); + Long id = (Long) template.insert(INSERT_PROPERTY_DOUBLE_VALUE, entity); + entity.setId(id); + // Done + return entity; + } + + //================================ + // 'alf_prop_value' accessors + //================================ + + @Override + protected PropertyValueEntity findPropertyValueById(Long id) + { + // TODO: Full query pulling back all related values + return null; + } + + @Override + protected PropertyValueEntity findPropertyValueByValue(Serializable value) + { + // TODO: Find out persisted type and perform relevant query + return null; + } + + @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())) + { + 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()); + } + + // Persist the entity + Long id = (Long) template.insert(INSERT_PROPERTY_VALUE, entity); + entity.setId(id); + // Done + return entity; + } }