org.opencms.file.CmsProperty Maven / Gradle / Ivy
Show all versions of opencms-core Show documentation
/*
* This library is part of OpenCms -
* the Open Source Content Management System
*
* Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com)
*
* This library 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 2.1 of the License, or (at your option) any later version.
*
* This library 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.
*
* For further information about Alkacon Software GmbH & Co. KG, please see the
* company website: http://www.alkacon.com
*
* For further information about OpenCms, please see the
* project website: http://www.opencms.org
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.opencms.file;
import org.opencms.i18n.CmsLocaleManager;
import org.opencms.main.CmsRuntimeException;
import org.opencms.util.CmsStringUtil;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.RandomAccess;
import org.apache.commons.collections.Transformer;
/**
* Represents a property (meta-information) mapped to a VFS resource.
*
* A property is an object that contains three string values: a name, a property value which is mapped
* to the structure record of a resource, and a property value which is mapped to the resource
* record of a resource. A property object is valid if it has both values or just one value set.
* Each property needs at least a name and one value set.
*
* A property value mapped to the structure record of a resource is significant for a single
* resource (sibling). A property value mapped to the resource record of a resource is significant
* for all siblings of a resource record. This is possible by getting the "compound value"
* (see {@link #getValue()}) of a property in case a property object has both values set. The compound
* value of a property object is the value mapped to the structure record, because it's structure
* value is more significant than it's resource value. This allows to set a property only one time
* on the resource record, and the property takes effect on all siblings of this resource record.
*
* The ID of the structure or resource record where a property value is mapped to is represented by
* the "PROPERTY_MAPPING_ID" table attribute in the database. The "PROPERTY_MAPPING_TYPE" table
* attribute (see {@link #STRUCTURE_RECORD_MAPPING} and {@link #RESOURCE_RECORD_MAPPING})
* determines whether the value of the "PROPERTY_MAPPING_ID" attribute of the current row is
* a structure or resource record ID.
*
* Property objects are written to the database using {@link org.opencms.file.CmsObject#writePropertyObject(String, CmsProperty)}
* or {@link org.opencms.file.CmsObject#writePropertyObjects(String, List)}, no matter
* whether you want to save a new (non-existing) property, update an existing property, or delete an
* existing property. To delete a property you would write a property object with either the
* structure and/or resource record values set to {@link #DELETE_VALUE} to indicate that a
* property value should be deleted in the database. Set property values to null if they should
* remain unchanged in the database when a property object is written. As for example you want to
* update just the structure value of a property, you would set the structure value to the new string,
* and the resource value to null (which is already the case by default).
*
* Use {@link #setAutoCreatePropertyDefinition(boolean)} to set a boolean flag whether a missing property
* definition should be created implicitly for a resource type when a property is written to the database.
* The default value for this flag is false
. Thus, you receive a CmsException if you try
* to write a property of a resource with a resource type which lacks a property definition for
* this resource type. It is not a good style to set {@link #setAutoCreatePropertyDefinition(boolean)}
* on true to make writing properties to the database work in any case, because then you will loose
* control about which resource types support which property definitions.
*
* @since 6.0.0
*/
public class CmsProperty implements Serializable, Cloneable, Comparable {
/** Transforms a given properties map, to a map where the returned values for a property are
* dependent on the locale.
*/
public static class CmsPropertyLocaleTransformer implements Transformer {
/** The original properties map. */
private Map m_properties;
/** The locale, w.r.t. which the properties should be accessed. */
private Locale m_locale;
/**
* Default constructor.
* @param properties the "raw" properties map as read for a resource.
* @param locale the locale w.r.t. which the properties should be accessed.
*/
public CmsPropertyLocaleTransformer(Map properties, Locale locale) {
m_properties = null == properties ? new HashMap() : properties;
m_locale = null == locale ? new Locale("") : locale;
}
/**
* @see org.apache.commons.collections.Transformer#transform(java.lang.Object)
*/
public Object transform(Object propertyName) {
return readProperty((String)propertyName);
}
/**
* Looks up a property in {@link #m_properties}, but returns the localized variant.
*
* @param propertyName the property to look up
* @return the value of the property
*/
protected String readProperty(String propertyName) {
if (null == m_locale) {
return m_properties.get(propertyName);
} else {
return m_properties.get(getLocalizedKey(m_properties, propertyName, m_locale));
}
}
}
/**
* Signals that the resource property values of a resource
* should be deleted using deleteAllProperties.
*/
public static final int DELETE_OPTION_DELETE_RESOURCE_VALUES = 3;
/**
* Signals that both the structure and resource property values of a resource
* should be deleted using deleteAllProperties.
*/
public static final int DELETE_OPTION_DELETE_STRUCTURE_AND_RESOURCE_VALUES = 1;
/**
* Signals that the structure property values of a resource
* should be deleted using deleteAllProperties.
*/
public static final int DELETE_OPTION_DELETE_STRUCTURE_VALUES = 2;
/**
* An empty string to decide that a property value should be deleted when this
* property object is written to the database.
*/
public static final String DELETE_VALUE = "";
/**
* Value of the "mapping-type" database attribute to indicate that a property value is mapped
* to a resource record.
*/
public static final int RESOURCE_RECORD_MAPPING = 2;
/**
* Value of the "mapping-type" database attribute to indicate that a property value is mapped
* to a structure record.
*/
public static final int STRUCTURE_RECORD_MAPPING = 1;
/** Key used for a individual (structure) property value. */
public static final String TYPE_INDIVIDUAL = "individual";
/** Key used for a shared (resource) property value. */
public static final String TYPE_SHARED = "shared";
/** The delimiter value for separating values in a list, per default this is the |
char. */
public static final char VALUE_LIST_DELIMITER = '|';
/** The list delimiter replacement String used if the delimiter itself is contained in a String value. */
public static final String VALUE_LIST_DELIMITER_REPLACEMENT = "%(ld)";
/** The delimiter value for separating values in a map, per default this is the =
char. */
public static final char VALUE_MAP_DELIMITER = '=';
/** The map delimiter replacement String used if the delimiter itself is contained in a String value. */
public static final String VALUE_MAP_DELIMITER_REPLACEMENT = "%(md)";
/** The null property object to be used in caches if a property is not found. */
private static final CmsProperty NULL_PROPERTY = new CmsProperty();
/** Serial version UID required for safe serialization. */
private static final long serialVersionUID = 93613508924212782L;
/**
* Static initializer required for freezing the {@link #NULL_PROPERTY}
.
*/
static {
NULL_PROPERTY.m_frozen = true;
NULL_PROPERTY.m_name = "";
}
/**
* Boolean flag to decide if the property definition for this property should be created
* implicitly on any write operation if doesn't exist already.
*/
private boolean m_autoCreatePropertyDefinition;
/** Indicates if the property is frozen (required for NULL_PROPERTY
). */
private boolean m_frozen;
/** The name of this property. */
private String m_name;
/** The origin root path of the property. */
private String m_origin;
/** The value of this property attached to the resource record. */
private String m_resourceValue;
/** The (optional) value list of this property attached to the resource record. */
private List m_resourceValueList;
/** The (optional) value map of this property attached to the resource record. */
private Map m_resourceValueMap;
/** The value of this property attached to the structure record. */
private String m_structureValue;
/** The (optional) value list of this property attached to the structure record. */
private List m_structureValueList;
/** The (optional) value map of this property attached to the structure record. */
private Map m_structureValueMap;
/**
* Creates a new CmsProperty object.
*
* The structure and resource property values are initialized to null. The structure and
* resource IDs are initialized to {@link org.opencms.util.CmsUUID#getNullUUID()}.
*/
public CmsProperty() {
// nothing to do, all values will be initialized with null
or false
by default
}
/**
* Creates a new CmsProperty object using the provided values.
*
* If the property definition does not exist for the resource type it
* is automatically created when this property is written.
*
* @param name the name of the property definition
* @param structureValue the value to write as structure property
* @param resourceValue the value to write as resource property
*/
public CmsProperty(String name, String structureValue, String resourceValue) {
this(name, structureValue, resourceValue, true);
}
/**
* Creates a new CmsProperty object using the provided values.
*
* If null
is supplied for the resource or structure value, this
* value will not be available for this property.
*
* @param name the name of the property definition
* @param structureValue the value to write as structure property, or null
* @param resourceValue the value to write as resource property , or null
* @param autoCreatePropertyDefinition if true
, the property definition for this property will be
* created implicitly on any write operation if it doesn't exist already
*/
public CmsProperty(String name, String structureValue, String resourceValue, boolean autoCreatePropertyDefinition) {
m_name = name.trim();
m_structureValue = structureValue;
m_resourceValue = resourceValue;
m_autoCreatePropertyDefinition = autoCreatePropertyDefinition;
}
/**
* Searches in a list for the first occurrence of a {@link CmsProperty} object with the given name.
*
* To check if the "null property" has been returned if a property was
* not found, use {@link #isNullProperty()} on the result.
*
* @param name a property name
* @param list a list of {@link CmsProperty} objects
* @return the index of the first occurrence of the name in they specified list,
* or {@link CmsProperty#getNullProperty()} if the name is not found
*/
public static final CmsProperty get(String name, List list) {
CmsProperty property = null;
name = name.trim();
// choose the fastest method to traverse the list
if (list instanceof RandomAccess) {
for (int i = 0, n = list.size(); i < n; i++) {
property = list.get(i);
if (property.m_name.equals(name)) {
return property;
}
}
} else {
Iterator i = list.iterator();
while (i.hasNext()) {
property = i.next();
if (property.m_name.equals(name)) {
return property;
}
}
}
return NULL_PROPERTY;
}
/**
* Returns the value for the best matching local-specific property version.
*
* @param propertiesMap the "raw" property map
* @param key the name of the property to search for
* @param locale the locale to search for
*
* @return the key for the best matching local-specific property version.
*/
public static String getLocaleSpecificPropertyValue(
Map propertiesMap,
String key,
Locale locale) {
String localeSpecificKey = CmsProperty.getLocalizedKey(propertiesMap, key, locale);
if (propertiesMap.containsKey(localeSpecificKey)) {
return propertiesMap.get(localeSpecificKey).getValue();
}
return null;
}
/**
* Returns the key for the best matching local-specific property version.
*
* @param propertiesMap the "raw" property map
* @param key the name of the property to search for
* @param locale the locale to search for
*
* @return the key for the best matching local-specific property version.
*/
public static String getLocalizedKey(Map propertiesMap, String key, Locale locale) {
List localizedKeys = CmsLocaleManager.getLocaleVariants(key, locale, true, false);
for (String localizedKey : localizedKeys) {
if (propertiesMap.containsKey(localizedKey)) {
return localizedKey;
}
}
return key;
}
/**
* Returns the null property object.
*
* @return the null property object
*/
public static final CmsProperty getNullProperty() {
return NULL_PROPERTY;
}
/**
* Transforms a list of CmsProperty objects with structure and resource values into a map with
* CmsProperty object values keyed by property keys.
*
* @param list a list of CmsProperty objects
* @return a map with CmsPropery object values keyed by property keys
*/
public static Map getPropertyMap(List list) {
Map result = null;
String key = null;
CmsProperty property = null;
if ((list == null) || (list.size() == 0)) {
return Collections.emptyMap();
}
result = new HashMap();
// choose the fastest method to iterate the list
if (list instanceof RandomAccess) {
for (int i = 0, n = list.size(); i < n; i++) {
property = list.get(i);
key = property.getName();
result.put(key, property);
}
} else {
Iterator i = list.iterator();
while (i.hasNext()) {
property = i.next();
key = property.getName();
result.put(key, property);
}
}
return result;
}
/**
* Calls {@link #setAutoCreatePropertyDefinition(boolean)}
for each
* property object in the given List with the given value
parameter.
*
* This method will modify the objects in the input list directly.
*
* @param list a list of {@link CmsProperty} objects to modify
* @param value boolean value
*
* @return the modified list of {@link CmsProperty} objects
*
* @see #setAutoCreatePropertyDefinition(boolean)
*/
public static final List setAutoCreatePropertyDefinitions(List list, boolean value) {
CmsProperty property;
// choose the fastest method to traverse the list
if (list instanceof RandomAccess) {
for (int i = 0, n = list.size(); i < n; i++) {
property = list.get(i);
property.m_autoCreatePropertyDefinition = value;
}
} else {
Iterator i = list.iterator();
while (i.hasNext()) {
property = i.next();
property.m_autoCreatePropertyDefinition = value;
}
}
return list;
}
/**
* Calls {@link #setFrozen(boolean)}
for each
* {@link CmsProperty} object in the given List if it is not already frozen.
*
* This method will modify the objects in the input list directly.
*
* @param list a list of {@link CmsProperty} objects
*
* @return the modified list of properties
*
* @see #setFrozen(boolean)
*/
public static final List setFrozen(List list) {
CmsProperty property;
// choose the fastest method to traverse the list
if (list instanceof RandomAccess) {
for (int i = 0, n = list.size(); i < n; i++) {
property = list.get(i);
if (!property.isFrozen()) {
property.setFrozen(true);
}
}
} else {
Iterator i = list.iterator();
while (i.hasNext()) {
property = i.next();
if (!property.isFrozen()) {
property.setFrozen(true);
}
}
}
return list;
}
/**
* Transforms a Map of String values into a list of
* {@link CmsProperty} objects with the property name set from the
* Map key, and the structure value set from the Map value.
*
* @param map a Map with String keys and String values
*
* @return a list of {@link CmsProperty} objects
*/
public static List toList(Map map) {
if ((map == null) || (map.size() == 0)) {
return Collections.emptyList();
}
List result = new ArrayList(map.size());
Iterator> i = map.entrySet().iterator();
while (i.hasNext()) {
Map.Entry e = i.next();
CmsProperty property = new CmsProperty(e.getKey(), e.getValue(), null);
result.add(property);
}
return result;
}
/**
* Transforms a list of {@link CmsProperty} objects into a Map which uses the property name as
* Map key (String), and the property value as Map value (String).
*
* @param list a list of {@link CmsProperty} objects
*
* @return a Map which uses the property names as
* Map keys (String), and the property values as Map values (String)
*/
public static Map toMap(List list) {
if ((list == null) || (list.size() == 0)) {
return Collections.emptyMap();
}
String name = null;
String value = null;
CmsProperty property = null;
Map result = new HashMap(list.size());
// choose the fastest method to traverse the list
if (list instanceof RandomAccess) {
for (int i = 0, n = list.size(); i < n; i++) {
property = list.get(i);
name = property.m_name;
value = property.getValue();
result.put(name, value);
}
} else {
Iterator i = list.iterator();
while (i.hasNext()) {
property = i.next();
name = property.m_name;
value = property.getValue();
result.put(name, value);
}
}
return result;
}
/**
* Stores a collection of properties in a map, with the property names as keys.
*
* @param properties the properties to store in the map
*
* @return the map with the property names as keys and the property objects as values
*/
public static Map toObjectMap(Iterable properties) {
Map result = new LinkedHashMap();
for (CmsProperty property : properties) {
result.put(property.getName(), property);
}
return result;
}
/**
* Wraps a null value into a null property, and returns all other values unchanged.
*
* @param prop the value to wrap
*
* @return a wrapped null property, or the original prop if it wasn't null
*/
public static CmsProperty wrapIfNull(CmsProperty prop) {
if (prop == null) {
return getNullProperty();
} else {
return prop;
}
}
/**
* Checks if the property definition for this property will be
* created implicitly on any write operation if doesn't already exist.
*
* @return true
, if the property definition for this property will be created implicitly on any write operation
*/
public boolean autoCreatePropertyDefinition() {
return m_autoCreatePropertyDefinition;
}
/**
* Creates a clone of this property.
*
* @return a clone of this property
*
* @see #cloneAsProperty()
*/
@Override
public CmsProperty clone() {
return cloneAsProperty();
}
/**
* Creates a clone of this property that already is of type {@link CmsProperty}
.
*
* The cloned property will not be frozen.
*
* @return a clone of this property that already is of type {@link CmsProperty}
*/
public CmsProperty cloneAsProperty() {
if (this == NULL_PROPERTY) {
// null property must never be cloned
return NULL_PROPERTY;
}
CmsProperty clone = new CmsProperty();
clone.m_name = m_name;
clone.m_structureValue = m_structureValue;
clone.m_structureValueList = m_structureValueList;
clone.m_resourceValue = m_resourceValue;
clone.m_resourceValueList = m_resourceValueList;
clone.m_autoCreatePropertyDefinition = m_autoCreatePropertyDefinition;
clone.m_origin = m_origin;
// the value for m_frozen does not need to be set as it is false by default
return clone;
}
/**
* Compares this property to another Object.
*
* @param obj the other object to be compared
* @return if the argument is a property object, returns zero if the name of the argument is equal to the name of this property object,
* a value less than zero if the name of this property is lexicographically less than the name of the argument,
* or a value greater than zero if the name of this property is lexicographically greater than the name of the argument
*/
public int compareTo(CmsProperty obj) {
if (obj == this) {
return 0;
}
return m_name.compareTo(obj.m_name);
}
/**
* Tests if a specified object is equal to this CmsProperty object.
*
* Two property objects are equal if their names are equal.
*
* In case you want to compare the values as well as the name,
* use {@link #isIdentical(CmsProperty)} instead.
*
* @param obj another object
* @return true, if the specified object is equal to this CmsProperty object
*
* @see #isIdentical(CmsProperty)
*/
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (obj instanceof CmsProperty) {
return ((CmsProperty)obj).m_name.equals(m_name);
}
return false;
}
/**
* Returns the name of this property.
*
* @return the name of this property
*/
public String getName() {
return m_name;
}
/**
* Returns the root path of the resource from which the property was read.
*
* @return the root path of the resource from which the property was read
*/
public String getOrigin() {
return m_origin;
}
/**
* Returns the value of this property attached to the resource record.
*
* @return the value of this property attached to the resource record
*/
public String getResourceValue() {
return m_resourceValue;
}
/**
* Returns the value of this property attached to the resource record, split as a list.
*
* This list is build form the resource value, which is split into separate values
* using the |
char as delimiter. If the delimiter is not found,
* then the list will contain one entry which is equal to {@link #getResourceValue()}
.
*
* @return the value of this property attached to the resource record, split as a (unmodifiable) list of Strings
*/
public List getResourceValueList() {
if ((m_resourceValueList == null) && (m_resourceValue != null)) {
// use lazy initializing of the list
m_resourceValueList = createListFromValue(m_resourceValue);
m_resourceValueList = Collections.unmodifiableList(m_resourceValueList);
}
return m_resourceValueList;
}
/**
* Returns the value of this property attached to the resource record as a map.
*
* This map is build from the used value, which is split into separate key/value pairs
* using the |
char as delimiter. If the delimiter is not found,
* then the map will contain one entry.
*
* The key/value pairs are separated with the =
.
*
* @return the value of this property attached to the resource record, as an (unmodifiable) map of Strings
*/
public Map getResourceValueMap() {
if ((m_resourceValueMap == null) && (m_resourceValue != null)) {
// use lazy initializing of the map
m_resourceValueMap = createMapFromValue(m_resourceValue);
m_resourceValueMap = Collections.unmodifiableMap(m_resourceValueMap);
}
return m_resourceValueMap;
}
/**
* Returns the value of this property attached to the structure record.
*
* @return the value of this property attached to the structure record
*/
public String getStructureValue() {
return m_structureValue;
}
/**
* Returns the value of this property attached to the structure record, split as a list.
*
* This list is build form the structure value, which is split into separate values
* using the |
char as delimiter. If the delimiter is not found,
* then the list will contain one entry which is equal to {@link #getStructureValue()}
.
*
* @return the value of this property attached to the structure record, split as a (unmodifiable) list of Strings
*/
public List getStructureValueList() {
if ((m_structureValueList == null) && (m_structureValue != null)) {
// use lazy initializing of the list
m_structureValueList = createListFromValue(m_structureValue);
m_structureValueList = Collections.unmodifiableList(m_structureValueList);
}
return m_structureValueList;
}
/**
* Returns the value of this property attached to the structure record as a map.
*
* This map is build from the used value, which is split into separate key/value pairs
* using the |
char as delimiter. If the delimiter is not found,
* then the map will contain one entry.
*
* The key/value pairs are separated with the =
.
*
* @return the value of this property attached to the structure record, as an (unmodifiable) map of Strings
*/
public Map getStructureValueMap() {
if ((m_structureValueMap == null) && (m_structureValue != null)) {
// use lazy initializing of the map
m_structureValueMap = createMapFromValue(m_structureValue);
m_structureValueMap = Collections.unmodifiableMap(m_structureValueMap);
}
return m_structureValueMap;
}
/**
* Returns the compound value of this property.
*
* The value returned is the value of {@link #getStructureValue()}, if it is not null
.
* Otherwise the value if {@link #getResourceValue()} is returned (which may also be null
).
*
* @return the compound value of this property
*/
public String getValue() {
return (m_structureValue != null) ? m_structureValue : m_resourceValue;
}
/**
* Returns the compound value of this property, or a specified default value,
* if both the structure and resource values are null.
*
* In other words, this method returns the defaultValue if this property object
* is the null property (see {@link CmsProperty#getNullProperty()}).
*
* @param defaultValue a default value which is returned if both the structure and resource values are null
*
* @return the compound value of this property, or the default value
*/
public String getValue(String defaultValue) {
if (this == CmsProperty.NULL_PROPERTY) {
// return the default value if this property is the null property
return defaultValue;
}
// somebody might have set both values to null manually
// on a property object different from the null property...
return (m_structureValue != null)
? m_structureValue
: ((m_resourceValue != null) ? m_resourceValue : defaultValue);
}
/**
* Returns the compound value of this property, split as a list.
*
* This list is build form the used value, which is split into separate values
* using the |
char as delimiter. If the delimiter is not found,
* then the list will contain one entry.
*
* The value returned is the value of {@link #getStructureValueList()}, if it is not null
.
* Otherwise the value of {@link #getResourceValueList()} is returned (which may also be null
).
*
* @return the compound value of this property, split as a (unmodifiable) list of Strings
*/
public List getValueList() {
return (m_structureValue != null) ? getStructureValueList() : getResourceValueList();
}
/**
* Returns the compound value of this property, split as a list, or a specified default value list,
* if both the structure and resource values are null.
*
* In other words, this method returns the defaultValue if this property object
* is the null property (see {@link CmsProperty#getNullProperty()}).
*
* @param defaultValue a default value list which is returned if both the structure and resource values are null
*
* @return the compound value of this property, split as a (unmodifiable) list of Strings
*/
public List getValueList(List defaultValue) {
if (this == CmsProperty.NULL_PROPERTY) {
// return the default value if this property is the null property
return defaultValue;
}
// somebody might have set both values to null manually
// on a property object different from the null property...
return (m_structureValue != null)
? getStructureValueList()
: ((m_resourceValue != null) ? getResourceValueList() : defaultValue);
}
/**
* Returns the compound value of this property as a map.
*
* This map is build from the used value, which is split into separate key/value pairs
* using the |
char as delimiter. If the delimiter is not found,
* then the map will contain one entry.
*
* The key/value pairs are separated with the =
.
*
* The value returned is the value of {@link #getStructureValueMap()}, if it is not null
.
* Otherwise the value of {@link #getResourceValueMap()} is returned (which may also be null
).
*
* @return the compound value of this property as a (unmodifiable) map of Strings
*/
public Map getValueMap() {
return (m_structureValue != null) ? getStructureValueMap() : getResourceValueMap();
}
/**
* Returns the compound value of this property as a map, or a specified default value map,
* if both the structure and resource values are null.
*
* In other words, this method returns the defaultValue if this property object
* is the null property (see {@link CmsProperty#getNullProperty()}).
*
* @param defaultValue a default value map which is returned if both the structure and resource values are null
*
* @return the compound value of this property as a (unmodifiable) map of Strings
*/
public Map getValueMap(Map defaultValue) {
if (this == CmsProperty.NULL_PROPERTY) {
// return the default value if this property is the null property
return defaultValue;
}
// somebody might have set both values to null manually
// on a property object different from the null property...
return (m_structureValue != null)
? getStructureValueMap()
: ((m_resourceValue != null) ? getResourceValueMap() : defaultValue);
}
/**
* Returns the hash code of the property, which is based only on the property name, not on the values.
*
* The resource and structure values are not taken into consideration for the hashcode generation
* because the {@link #equals(Object)} implementation also does not take these into consideration.
*
* @return the hash code of the property
*
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
return m_name.hashCode();
}
/**
* Checks if the resource value of this property should be deleted when this
* property object is written to the database.
*
* @return true, if the resource value of this property should be deleted
* @see CmsProperty#DELETE_VALUE
*/
public boolean isDeleteResourceValue() {
return (m_resourceValue == DELETE_VALUE) || ((m_resourceValue != null) && (m_resourceValue.length() == 0));
}
/**
* Checks if the structure value of this property should be deleted when this
* property object is written to the database.
*
* @return true, if the structure value of this property should be deleted
* @see CmsProperty#DELETE_VALUE
*/
public boolean isDeleteStructureValue() {
return (m_structureValue == DELETE_VALUE) || ((m_structureValue != null) && (m_structureValue.length() == 0));
}
/**
* Returns true
if this property is frozen, that is read only.
*
* @return true
if this property is frozen, that is read only
*/
public boolean isFrozen() {
return m_frozen;
}
/**
* Tests if a given CmsProperty is identical to this CmsProperty object.
*
* The property object are identical if their name, structure and
* resource values are all equals.
*
* @param property another property object
* @return true, if the specified object is equal to this CmsProperty object
*/
public boolean isIdentical(CmsProperty property) {
boolean isEqual;
// compare the name
if (m_name == null) {
isEqual = (property.getName() == null);
} else {
isEqual = m_name.equals(property.getName());
}
// compare the structure value
if (m_structureValue == null) {
isEqual &= (property.getStructureValue() == null);
} else {
isEqual &= m_structureValue.equals(property.getStructureValue());
}
// compare the resource value
if (m_resourceValue == null) {
isEqual &= (property.getResourceValue() == null);
} else {
isEqual &= m_resourceValue.equals(property.getResourceValue());
}
return isEqual;
}
/**
* Checks if this property object is the null property object.
*
* @return true if this property object is the null property object
*/
public boolean isNullProperty() {
return NULL_PROPERTY.equals(this);
}
/**
* Sets the boolean flag to decide if the property definition for this property should be
* created implicitly on any write operation if doesn't exist already.
*
* @param value true, if the property definition for this property should be created implicitly on any write operation
*/
public void setAutoCreatePropertyDefinition(boolean value) {
checkFrozen();
m_autoCreatePropertyDefinition = value;
}
/**
* Sets the frozen state of the property, if set to true
then this property is read only.
*
* If the property is already frozen, then setting the frozen state to true
again is allowed,
* but setting the value to false
causes a {@link CmsRuntimeException}
.
*
* @param frozen the frozen state to set
*/
public void setFrozen(boolean frozen) {
if (!frozen) {
checkFrozen();
}
m_frozen = frozen;
}
/**
* Sets the name of this property.
*
* @param name the name to set
*/
public void setName(String name) {
checkFrozen();
m_name = name.trim();
}
/**
* Sets the path of the resource from which the property was read.
*
* @param originRootPath the root path of the root path from which the property was read
*/
public void setOrigin(String originRootPath) {
checkFrozen();
m_origin = originRootPath;
}
/**
* Sets the value of this property attached to the resource record.
*
* @param resourceValue the value of this property attached to the resource record
*/
public void setResourceValue(String resourceValue) {
checkFrozen();
m_resourceValue = resourceValue;
m_resourceValueList = null;
}
/**
* Sets the value of this property attached to the resource record from the given list of Strings.
*
* The value will be created from the individual values of the given list, which are appended
* using the |
char as delimiter.
*
* @param valueList the list of value (Strings) to attach to the resource record
*/
public void setResourceValueList(List valueList) {
checkFrozen();
if (valueList != null) {
m_resourceValueList = new ArrayList(valueList);
m_resourceValueList = Collections.unmodifiableList(m_resourceValueList);
m_resourceValue = createValueFromList(m_resourceValueList);
} else {
m_resourceValueList = null;
m_resourceValue = null;
}
}
/**
* Sets the value of this property attached to the resource record from the given map of Strings.
*
* The value will be created from the individual values of the given map, which are appended
* using the |
char as delimiter, the map keys and values are separated by a =
.
*
* @param valueMap the map of key/value (Strings) to attach to the resource record
*/
public void setResourceValueMap(Map valueMap) {
checkFrozen();
if (valueMap != null) {
m_resourceValueMap = new HashMap(valueMap);
m_resourceValueMap = Collections.unmodifiableMap(m_resourceValueMap);
m_resourceValue = createValueFromMap(m_resourceValueMap);
} else {
m_resourceValueMap = null;
m_resourceValue = null;
}
}
/**
* Sets the value of this property attached to the structure record.
*
* @param structureValue the value of this property attached to the structure record
*/
public void setStructureValue(String structureValue) {
checkFrozen();
m_structureValue = structureValue;
m_structureValueList = null;
}
/**
* Sets the value of this property attached to the structure record from the given list of Strings.
*
* The value will be created from the individual values of the given list, which are appended
* using the |
char as delimiter.
*
* @param valueList the list of value (Strings) to attach to the structure record
*/
public void setStructureValueList(List valueList) {
checkFrozen();
if (valueList != null) {
m_structureValueList = new ArrayList(valueList);
m_structureValueList = Collections.unmodifiableList(m_structureValueList);
m_structureValue = createValueFromList(m_structureValueList);
} else {
m_structureValueList = null;
m_structureValue = null;
}
}
/**
* Sets the value of this property attached to the structure record from the given map of Strings.
*
* The value will be created from the individual values of the given map, which are appended
* using the |
char as delimiter, the map keys and values are separated by a =
.
*
* @param valueMap the map of key/value (Strings) to attach to the structure record
*/
public void setStructureValueMap(Map valueMap) {
checkFrozen();
if (valueMap != null) {
m_structureValueMap = new HashMap(valueMap);
m_structureValueMap = Collections.unmodifiableMap(m_structureValueMap);
m_structureValue = createValueFromMap(m_structureValueMap);
} else {
m_structureValueMap = null;
m_structureValue = null;
}
}
/**
* Sets the value of this property as either shared or
* individual value.
*
* If the given type equals {@link CmsProperty#TYPE_SHARED} then
* the value is set as a shared (resource) value, otherwise it
* is set as individual (structure) value.
*
* @param value the value to set
* @param type the value type to set
*/
public void setValue(String value, String type) {
checkFrozen();
setAutoCreatePropertyDefinition(true);
if (TYPE_SHARED.equalsIgnoreCase(type)) {
// set the provided value as shared (resource) value
setResourceValue(value);
} else {
// set the provided value as individual (structure) value
setStructureValue(value);
}
}
/**
* Returns a string representation of this property object.
*
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
StringBuffer strBuf = new StringBuffer();
strBuf.append("[").append(getClass().getName()).append(": ");
strBuf.append("name: '").append(m_name).append("'");
strBuf.append(", value: '").append(getValue()).append("'");
strBuf.append(", structure value: '").append(m_structureValue).append("'");
strBuf.append(", resource value: '").append(m_resourceValue).append("'");
strBuf.append(", frozen: ").append(m_frozen);
strBuf.append(", origin: ").append(m_origin);
strBuf.append("]");
return strBuf.toString();
}
/**
* Checks if this property is frozen, that is read only.
*/
private void checkFrozen() {
if (m_frozen) {
throw new CmsRuntimeException(Messages.get().container(Messages.ERR_PROPERTY_FROZEN_1, toString()));
}
}
/**
* Returns the list value representation for the given String.
*
* The given value is split along the |
char.
*
* @param value the value to create the list representation for
*
* @return the list value representation for the given String
*/
private List createListFromValue(String value) {
if (value == null) {
return null;
}
List result = CmsStringUtil.splitAsList(value, VALUE_LIST_DELIMITER);
if (value.indexOf(VALUE_LIST_DELIMITER_REPLACEMENT) != -1) {
List tempList = new ArrayList(result.size());
Iterator i = result.iterator();
while (i.hasNext()) {
String item = i.next();
tempList.add(rebuildDelimiter(item, VALUE_LIST_DELIMITER, VALUE_LIST_DELIMITER_REPLACEMENT));
}
result = tempList;
}
return result;
}
/**
* Returns the map value representation for the given String.
*
* The given value is split along the |
char, the map keys and values are separated by a =
.
*
* @param value the value to create the map representation for
*
* @return the map value representation for the given String
*/
private Map createMapFromValue(String value) {
if (value == null) {
return null;
}
List entries = createListFromValue(value);
Iterator i = entries.iterator();
Map result = new HashMap(entries.size());
boolean rebuildDelimiters = false;
if (value.indexOf(VALUE_MAP_DELIMITER_REPLACEMENT) != -1) {
rebuildDelimiters = true;
}
while (i.hasNext()) {
String entry = i.next();
int index = entry.indexOf(VALUE_MAP_DELIMITER);
if (index != -1) {
String key = entry.substring(0, index);
String val = "";
if ((index + 1) < entry.length()) {
val = entry.substring(index + 1);
}
if (CmsStringUtil.isNotEmpty(key)) {
if (rebuildDelimiters) {
key = rebuildDelimiter(key, VALUE_MAP_DELIMITER, VALUE_MAP_DELIMITER_REPLACEMENT);
val = rebuildDelimiter(val, VALUE_MAP_DELIMITER, VALUE_MAP_DELIMITER_REPLACEMENT);
}
result.put(key, val);
}
}
}
return result;
}
/**
* Returns the single String value representation for the given value list.
*
* @param valueList the value list to create the single String value for
*
* @return the single String value representation for the given value list
*/
private String createValueFromList(List valueList) {
if (valueList == null) {
return null;
}
StringBuffer result = new StringBuffer(valueList.size() * 32);
Iterator i = valueList.iterator();
while (i.hasNext()) {
result.append(
replaceDelimiter(i.next().toString(), VALUE_LIST_DELIMITER, VALUE_LIST_DELIMITER_REPLACEMENT));
if (i.hasNext()) {
result.append(VALUE_LIST_DELIMITER);
}
}
return result.toString();
}
/**
* Returns the single String value representation for the given value map.
*
* @param valueMap the value map to create the single String value for
*
* @return the single String value representation for the given value map
*/
private String createValueFromMap(Map valueMap) {
if (valueMap == null) {
return null;
}
StringBuffer result = new StringBuffer(valueMap.size() * 32);
Iterator> i = valueMap.entrySet().iterator();
while (i.hasNext()) {
Map.Entry entry = i.next();
String key = entry.getKey();
String value = entry.getValue();
key = replaceDelimiter(key, VALUE_LIST_DELIMITER, VALUE_LIST_DELIMITER_REPLACEMENT);
key = replaceDelimiter(key, VALUE_MAP_DELIMITER, VALUE_MAP_DELIMITER_REPLACEMENT);
value = replaceDelimiter(value, VALUE_LIST_DELIMITER, VALUE_LIST_DELIMITER_REPLACEMENT);
value = replaceDelimiter(value, VALUE_MAP_DELIMITER, VALUE_MAP_DELIMITER_REPLACEMENT);
result.append(key);
result.append(VALUE_MAP_DELIMITER);
result.append(value);
if (i.hasNext()) {
result.append(VALUE_LIST_DELIMITER);
}
}
return result.toString();
}
/**
* Rebuilds the given delimiter character from the replacement string.
*
* @param value the string that is scanned
* @param delimiter the delimiter character to rebuild
* @param delimiterReplacement the replacement string for the delimiter character
* @return the substituted string
*/
private String rebuildDelimiter(String value, char delimiter, String delimiterReplacement) {
return CmsStringUtil.substitute(value, delimiterReplacement, String.valueOf(delimiter));
}
/**
* Replaces the given delimiter character with the replacement string.
*
* @param value the string that is scanned
* @param delimiter the delimiter character to replace
* @param delimiterReplacement the replacement string for the delimiter character
* @return the substituted string
*/
private String replaceDelimiter(String value, char delimiter, String delimiterReplacement) {
return CmsStringUtil.substitute(value, String.valueOf(delimiter), delimiterReplacement);
}
}