org.alfresco.repo.domain.propval.PropertyValueEntity.java Source code

Java tutorial

Introduction

Here is the source code for org.alfresco.repo.domain.propval.PropertyValueEntity.java

Source

/*
 * #%L
 * Alfresco Repository
 * %%
 * Copyright (C) 2005 - 2016 Alfresco Software Limited
 * %%
 * This file is part of the Alfresco software. 
 * If the software was purchased under a paid Alfresco license, the terms of 
 * the paid license agreement will prevail.  Otherwise, the software is 
 * provided under the following open source license terms:
 * 
 * Alfresco is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * Alfresco 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 Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
 * #L%
 */
package org.alfresco.repo.domain.propval;

import java.io.Serializable;
import java.util.Collections;
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 <b>alf_prop_value</b> table.
 * <p>
 * Values here are either simple values that can be stored in a <code>long</code>
 * or will be references to data in other tables.
 * 
 * @author Derek Hulley
 * @since 3.2
 */
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 = 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;
    public static final Short ORDINAL_CONSTRUCTABLE = 5;
    public static final Short ORDINAL_ENUM = 6;

    /**
     * Enumeration of persisted types for <b>alf_prop_value.persisted_type</b>.
     * <p/>
     * 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.2
     */
    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.");
            }
        },
        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;
            }
        },
        CONSTRUCTABLE {
            @Override
            public Short getOrdinalNumber() {
                return ORDINAL_CONSTRUCTABLE;
            }

            @Override
            public Class<?> getAssociatedClass() {
                return Class.class;
            }
        },
        ENUM {
            @Override
            public Short getOrdinalNumber() {
                return ORDINAL_ENUM;
            }

            @Override
            public Class<?> getAssociatedClass() {
                return Enum.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<Short, Serializable> PERSISTED_TYPE_NULL;
    /**
     * An unmodifiable map of persisted type enums keyed by their ordinal number
     */
    public static final Map<Short, PersistedType> persistedTypesByOrdinal;

    static {
        // Create a pair for null values
        PERSISTED_TYPE_NULL = new Pair<Short, Serializable>(PersistedType.NULL.getOrdinalNumber(), new Long(0));
        // Create the map of ordinal-type
        Map<Short, PersistedType> mapOrdinal = new HashMap<Short, PersistedType>(15);
        for (PersistedType persistedType : PersistedType.values()) {
            mapOrdinal.put(persistedType.getOrdinalNumber(), persistedType);
        }
        persistedTypesByOrdinal = Collections.unmodifiableMap(mapOrdinal);
    }

    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;
    private Serializable serializableValue;

    public PropertyValueEntity() {
        this.persistedType = PersistedType.NULL.getOrdinalNumber();
        this.longValue = LONG_ZERO;
    }

    @Override
    public int hashCode() {
        return (actualTypeId == null ? 0 : actualTypeId.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.actualTypeId, that.actualTypeId)
                    && 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(", actualTypeId=").append(actualTypeId)
                .append(", persistedType=").append(persistedType).append(", value=").append(longValue).append("]");
        return sb.toString();
    }

    /**
     * Helper method to get the value based on the persisted type. 
     * 
     * @param actualType        the type to convert to
     * @param converter         the data converter to use
     * @return                  Returns the converted value
     */
    public Serializable getValue(Class<Serializable> actualType, PropertyTypeConverter converter) {
        switch (persistedTypeEnum) {
        case NULL:
            return null;
        case LONG:
            return converter.convert(actualType, Long.valueOf(longValue));
        case DOUBLE:
            return converter.convert(actualType, Double.valueOf(doubleValue));
        case STRING:
            if (stringValue != null && stringValue.equals(PropertyStringValueEntity.EMPTY_STRING_REPLACEMENT)) {
                return converter.convert(actualType, PropertyStringValueEntity.EMPTY_STRING);
            } else {
                return converter.convert(actualType, stringValue);
            }
        case SERIALIZABLE:
            return converter.convert(actualType, serializableValue);
        case CONSTRUCTABLE:
            // Construct an instance using the converter (it knows best!)
            return converter.constructInstance(stringValue);
        case ENUM:
            // The converter should handle enumeration types
            return converter.convert(actualType, stringValue);
        default:
            throw new IllegalStateException("Should not be able to get through switch");
        }
    }

    /**
     * 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 <tt>null</tt>)
     * @param converter     the converter that will perform and type conversion
     */
    public void setValue(Serializable value, PropertyTypeConverter converter) {
        if (value == null) {
            this.persistedType = ORDINAL_NULL;
            this.persistedTypeEnum = PersistedType.NULL;
            this.longValue = LONG_ZERO;
        } else {
            // The converter will be responsible for deserializing, so let it choose
            // how the data is to be stored.
            persistedTypeEnum = converter.getPersistentType(value);
            persistedType = persistedTypeEnum.getOrdinalNumber();
            // Get the class to persist as
            switch (persistedTypeEnum) {
            case LONG:
                longValue = converter.convert(Long.class, value);
                break;
            case DOUBLE:
                doubleValue = converter.convert(Double.class, value);
                break;
            case STRING:
                stringValue = converter.convert(String.class, value);
                if (stringValue.equals(PropertyStringValueEntity.EMPTY_STRING)) {
                    // Oracle: We can't insert empty strings into the column.
                    stringValue = PropertyStringValueEntity.EMPTY_STRING_REPLACEMENT;
                }
                break;
            case CONSTRUCTABLE:
                // A special case.  There is no conversion, so just Store the name of the class.
                stringValue = value.getClass().getName();
                break;
            case ENUM:
                // A special case.  Store the string-equivalent representation
                stringValue = converter.convert(String.class, value);
                break;
            case SERIALIZABLE:
                serializableValue = value;
                break;
            default:
                throw new IllegalStateException(
                        "PropertyTypeConverter.convertToPersistentType returned illegal type: "
                                + "   Converter:      " + converter + "\n" + "   Type Returned:  "
                                + persistedTypeEnum + "\n" + "   From Value:     " + value);
            }
        }
    }

    /**
     * Helper method to determine how the given value will be stored.
     * 
     * @param value         the value to check
     * @param converter     the type converter
     * @return              Returns the persisted type
     * 
     * @see PropertyTypeConverter#getPersistentType(Serializable)
     */
    public static PersistedType getPersistedTypeEnum(Serializable value, PropertyTypeConverter converter) {
        PersistedType persistedTypeEnum;
        if (value == null) {
            persistedTypeEnum = PersistedType.NULL;
        } else {
            persistedTypeEnum = converter.getPersistentType(value);
        }
        return persistedTypeEnum;
    }

    public PersistedType getPersistedTypeEnum() {
        return persistedTypeEnum;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public Long getActualTypeId() {
        return actualTypeId;
    }

    public void setActualTypeId(Long actualTypeId) {
        this.actualTypeId = actualTypeId;
    }

    public Short getPersistedType() {
        return persistedType;
    }

    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() {
        return longValue;
    }

    public void setLongValue(Long longValue) {
        this.longValue = longValue;
    }

    public String getStringValue() {
        return stringValue;
    }

    public void setStringValue(String stringValue) {
        if (stringValue == null) {
            // Oracle!  It pulls nulls out in place of empty strings.
            //  Since we don't put nulls into the DB (the column doesn't allow it)
            //  we can be sure that this is an Oracle empty 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;
    }
}