/* * Copyright 2001-2008 Geert Bevin <gbevin[remove] at uwyn dot com> * Licensed under the Apache License, Version 2.0 (the "License") * $Id: Content.java 3918 2008-04-14 17:35:35Z gbevin $ */ package com.uwyn.rife.cmf; import com.uwyn.rife.tools.ExceptionUtils; import java.util.HashMap; import java.util.Map; import java.util.logging.Logger; /** * Contains the information required to store new content data together with * additional meta-data. * <p>All content is determined by its mime type and the raw data that will be * used to load the content. The type of the data is dependent on the mime * type. * <p>For example, images can be loaded from byte arrays and texts can be * loaded from strings. If an unsupported data type is used or the format is * incorrect, suitable exceptions will be thrown when the content is stored in * the back-end. * * @author Geert Bevin (gbevin[remove] at uwyn dot com) * @version $Revision: 3918 $ * @since 1.0 */ public class Content implements Cloneable { private MimeType mMimeType = null; private Object mData = null; private boolean mFragment = false; private String mName = null; private Map<String, String> mAttributes = null; private Map<String, String> mProperties = null; private Object mCachedLoadedData = null; /** * Creates a new <code>Content</code> instance with the minimal required * arguments. * * @param mimeType the mime type as which the content will be stored in * the back-end, note that this doesn't necessarily has to correspond to * the mime type of the provided data. Image formats can for example be * automatically detected and converted to the target mime type by image * loading and conversion libraries. * @param data the data of the content, if this is <code>null</code>, * empty content should be stored * @since 1.0 */ public Content(MimeType mimeType, Object data) { if (null == mimeType) throw new IllegalArgumentException("mimeType can't be null"); mMimeType = mimeType; mData = data; } /** * Retrieves the mime type of the content. * * @return the mime type of the content * @since 1.0 */ public MimeType getMimeType() { return mMimeType; } /** * Retrieves the data of the content. * * @return the data of the content * @since 1.0 */ public Object getData() { return mData; } /** * Sets the data of the content. * @since 1.4 */ public void setData(Object data) { mData = data; } /** * Sets whether the content data is a fragment. A fragment means that it's * not a complete document or a file, but rather a small part that is * intended to be used within a larger document. For example a HTML * snippet. This information is for example important when validating the * data. * * @param fragment <code>true</code> if the content is a fragment; or * <p><code>false</code> otherwise * @return the current <code>Content</code> instance * @see #setFragment(boolean) * @see #isFragment() * @since 1.0 */ public Content fragment(boolean fragment) { setFragment(fragment); return this; } /** * Sets whether the content data is a fragment. * * @param fragment <code>true</code> if the content is a fragment; or * <p><code>false</code> otherwise * @see #fragment(boolean) * @see #isFragment() * @since 1.0 */ public void setFragment(boolean fragment) { mFragment = fragment; } /** * Indicates whether the content data is a fragment. * * @return <code>true</code> if the content is a fragment; or * <p><code>false</code> otherwise * @see #fragment(boolean) * @see #setFragment(boolean) * @since 1.0 */ public boolean isFragment() { return mFragment; } /** * Sets the name of the content. * * @param name the name * @return the current <code>Content</code> instance * @see #setName(String) * @see #getName() * @see #hasName() * @since 1.0 */ public Content name(String name) { setName(name); return this; } /** * Sets the name of the content. * * @param name the name * @see #name(String) * @see #getName() * @see #hasName() * @since 1.0 */ public void setName(String name) { mName = name; } /** * Retrieves the name of the content. * * @return <code>null</code> if the content has no name; or * <p>the name of the content * @see #name(String) * @see #setName(String) * @see #hasName() * @since 1.0 */ public String getName() { return mName; } /** * Indicates whether the content data has a name. * * @return <code>true</code> if the content has a name; or * <p><code>false</code> otherwise * @see #name(String) * @see #setName(String) * @see #getName() * @since 1.0 */ public boolean hasName() { return mName != null; } /** * Replaces the map of named content attributes. * <p>Note that attributes provide information about how to load, convert * and transform content into its stored data form. If you want to provide * meta information about the content, you should provide it through * properties instead. * * @param attributes the map of named content attributes * @return the current <code>Content</code> instance * @see #setAttributes(Map) * @see #getAttributes() * @see #hasAttributes() * @since 1.0 */ public Content attributes(Map<String, String> attributes) { setAttributes(attributes); return this; } /** * Sets a named content attribute that will be converted internally to a * <code>String</code> value. * * @param name the name of the attribute * @param value the value of the attribute * @return the current <code>Content</code> instance * @see #getAttribute(String) * @see #hasAttribute(String) * @since 1.0 */ public Content attribute(String name, boolean value) { return attribute(name, String.valueOf(value)); } /** * Sets a named content attribute that will be converted internally to a * <code>String</code> value. * * @param name the name of the attribute * @param value the value of the attribute * @return the current <code>Content</code> instance * @see #getAttribute(String) * @see #hasAttribute(String) * @since 1.0 */ public Content attribute(String name, char value) { return attribute(name, String.valueOf(value)); } /** * Sets a named content attribute that will be converted internally to a * <code>String</code> value. * * @param name the name of the attribute * @param value the value of the attribute * @return the current <code>Content</code> instance * @see #getAttribute(String) * @see #hasAttribute(String) * @since 1.0 */ public Content attribute(String name, byte value) { return attribute(name, String.valueOf(value)); } /** * Sets a named content attribute that will be converted internally to a * <code>String</code> value. * * @param name the name of the attribute * @param value the value of the attribute * @return the current <code>Content</code> instance * @see #getAttribute(String) * @see #hasAttribute(String) * @since 1.0 */ public Content attribute(String name, short value) { return attribute(name, String.valueOf(value)); } /** * Sets a named content attribute that will be converted internally to a * <code>String</code> value. * * @param name the name of the attribute * @param value the value of the attribute * @return the current <code>Content</code> instance * @see #getAttribute(String) * @see #hasAttribute(String) * @since 1.0 */ public Content attribute(String name, int value) { return attribute(name, String.valueOf(value)); } /** * Sets a named content attribute that will be converted internally to a * <code>String</code> value. * * @param name the name of the attribute * @param value the value of the attribute * @return the current <code>Content</code> instance * @see #getAttribute(String) * @see #hasAttribute(String) * @since 1.0 */ public Content attribute(String name, long value) { return attribute(name, String.valueOf(value)); } /** * Sets a named content attribute that will be converted internally to a * <code>String</code> value. * * @param name the name of the attribute * @param value the value of the attribute * @return the current <code>Content</code> instance * @see #getAttribute(String) * @see #hasAttribute(String) * @since 1.0 */ public Content attribute(String name, float value) { return attribute(name, String.valueOf(value)); } /** * Sets a named content attribute that will be converted internally to a * <code>String</code> value. * * @param name the name of the attribute * @param value the value of the attribute * @return the current <code>Content</code> instance * @see #getAttribute(String) * @see #hasAttribute(String) * @since 1.0 */ public Content attribute(String name, double value) { return attribute(name, String.valueOf(value)); } /** * Sets a named content attribute. * * @param name the name of the attribute * @param value the value of the attribute * @return the current <code>Content</code> instance * @see #getAttribute(String) * @see #hasAttribute(String) * @since 1.0 */ public Content attribute(String name, String value) { if (null == mAttributes) { mAttributes = new HashMap<String, String>(); } mAttributes.put(name, value); return this; } /** * Replaces the map of named content attributes. * * @param attributes the map of named content attributes * @see #attributes(Map) * @see #getAttributes() * @see #hasAttributes() * @since 1.0 */ public void setAttributes(Map<String, String> attributes) { if (null == attributes) { mAttributes = null; return; } mAttributes = new HashMap<String, String>(attributes); } /** * Retrieves the map of named content attributes. * * @return the map of named content attributes; or * <p><code>null</code> if no attributes are present * @see #attributes(Map) * @see #setAttributes(Map) * @see #hasAttributes() * @since 1.0 */ public Map<String, String> getAttributes() { return mAttributes; } /** * Indicates whether named content attributes are present. * * @return <code>true</code> if named content attributes are present; or * <p><code>false</code> otherwise * @see #attributes(Map) * @see #setAttributes(Map) * @see #getAttributes() * @since 1.0 */ public boolean hasAttributes() { return mAttributes != null && mAttributes.size() > 0; } /** * Indicates whether a specific named content attribute is present. * * @param name the name of the attribute * @return <code>true</code> if the name content attribute is present; or * <p><code>false</code> otherwise * @see #getAttribute(String) * @since 1.0 */ public boolean hasAttribute(String name) { if (null == mAttributes) { return false; } return mAttributes.containsKey(name); } /** * Retrieves the value of a named content attribute. * * @param name the name of the attribute * @return the value of the named content attribute; or * <p><code>null</code> if no such attribute could be found * @see #hasAttribute(String) * @since 1.0 */ public String getAttribute(String name) { if (null == mAttributes) { return null; } return mAttributes.get(name); } /** * Replaces the content properties. * <p>This is also internally used by content formatters to provide * additional information about the content that's stored after formatting * and transformation. Note that this is not the same as content * attributes, who provide infomration about how to format and transform * the provided data before storage. The content properties describe the * result as it's stored in the back-end. * * @param properties the content properties * @return the current <code>Content</code> instance * @see #setProperties(Map) * @see #hasProperties() * @see #getProperties() * @since 1.0 */ public Content properties(Map<String, String> properties) { setProperties(properties); return this; } /** * Sets a named content property that will be converted internally to a * <code>String</code> value. * * @param name the name of the property * @param value the value of the property * @return the current <code>Content</code> instance * @see #getProperty(String) * @see #hasProperty(String) * @since 1.0 */ public Content property(String name, boolean value) { return property(name, String.valueOf(value)); } /** * Sets a named content property that will be converted internally to a * <code>String</code> value. * * @param name the name of the property * @param value the value of the property * @return the current <code>Content</code> instance * @see #getProperty(String) * @see #hasProperty(String) * @since 1.0 */ public Content property(String name, char value) { return property(name, String.valueOf(value)); } /** * Sets a named content property that will be converted internally to a * <code>String</code> value. * * @param name the name of the property * @param value the value of the property * @return the current <code>Content</code> instance * @see #getProperty(String) * @see #hasProperty(String) * @since 1.0 */ public Content property(String name, byte value) { return property(name, String.valueOf(value)); } /** * Sets a named content property that will be converted internally to a * <code>String</code> value. * * @param name the name of the property * @param value the value of the property * @return the current <code>Content</code> instance * @see #getProperty(String) * @see #hasProperty(String) * @since 1.0 */ public Content property(String name, short value) { return property(name, String.valueOf(value)); } /** * Sets a named content property that will be converted internally to a * <code>String</code> value. * * @param name the name of the property * @param value the value of the property * @return the current <code>Content</code> instance * @see #getProperty(String) * @see #hasProperty(String) * @since 1.0 */ public Content property(String name, int value) { return property(name, String.valueOf(value)); } /** * Sets a named content property that will be converted internally to a * <code>String</code> value. * * @param name the name of the property * @param value the value of the property * @return the current <code>Content</code> instance * @see #getProperty(String) * @see #hasProperty(String) * @since 1.0 */ public Content property(String name, long value) { return property(name, String.valueOf(value)); } /** * Sets a named content property that will be converted internally to a * <code>String</code> value. * * @param name the name of the property * @param value the value of the property * @return the current <code>Content</code> instance * @see #getProperty(String) * @see #hasProperty(String) * @since 1.0 */ public Content property(String name, float value) { return property(name, String.valueOf(value)); } /** * Sets a named content property that will be converted internally to a * <code>String</code> value. * * @param name the name of the property * @param value the value of the property * @return the current <code>Content</code> instance * @see #getProperty(String) * @see #hasProperty(String) * @since 1.0 */ public Content property(String name, double value) { return property(name, String.valueOf(value)); } /** * Sets a named content property. * * @param name the name of the property * @param value the value of the property * @return the current <code>Content</code> instance * @see #getProperty(String) * @see #hasProperty(String) * @since 1.0 */ public Content property(String name, String value) { if (null == mProperties) { mProperties = new HashMap<String, String>(); } mProperties.put(name, value); return this; } /** * Replaces the content properties. * * @param properties the content properties * @see #properties(Map) * @see #hasProperties() * @see #getProperties() * @since 1.0 */ public void setProperties(Map<String, String> properties) { if (null == properties) { mProperties = null; return; } mProperties = new HashMap<String, String>(properties); } /** * Indicates whether content properties are present * * @return <code>true</code> if properties are present; or * <p><code>false</code> otherwise * @see #properties(Map) * @see #setProperties(Map) * @see #getProperties() * @since 1.0 */ public boolean hasProperties() { return mProperties != null && mProperties.size() > 0; } /** * Indicates whether a specific named content property is present. * * @param name the name of the property * @return <code>true</code> if the name content property is present; or * <p><code>false</code> otherwise * @see #getProperty(String) * @since 1.0 */ public boolean hasProperty(String name) { if (null == mProperties) { return false; } return mProperties.containsKey(name); } /** * Retrieves the value of a named content property. * * @param name the name of the property * @return the value of the named content property; or * <p><code>null</code> if no such property could be found * @see #hasProperty(String) * @since 1.0 */ public String getProperty(String name) { if (null == mProperties) { return null; } return mProperties.get(name); } /** * Retrieves the content properties. * * @return the content properties; or * <p><code>null</code> if no content properties are present * @see #properties(Map) * @see #setProperties(Map) * @see #hasProperties() * @since 1.0 */ public Map<String, String> getProperties() { return mProperties; } /** * Sets the cached loaded data. * <p>This is <b>internally</b> used by content loaders to prevent having * to load and convert data to the specified mime type several times for * the same content. It is for instance very resource intensive to detect * an image format, validate the provided raw data and create a generic * image instance for further processing. These operations are however * required in several different locations in the content handling logic. * Storing the result after the first successful loading and simply * retrieving it later enhances the speed considerably. * * @param data the loaded data * @return the current <code>Content</code> instance * @see #setCachedLoadedData(Object) * @see #hasCachedLoadedData() * @see #getCachedLoadedData() * @since 1.0 */ public Content cachedLoadedData(Object data) { setCachedLoadedData(data); return this; } /** * Sets the cached loaded data. * * @param data the loaded data * @see #cachedLoadedData(Object) * @see #hasCachedLoadedData() * @see #getCachedLoadedData() * @since 1.0 */ public void setCachedLoadedData(Object data) { mCachedLoadedData = data; } /** * Indicates whether cached loaded content data is present. * * @return <code>true</code> if cached loaded content data is present; or * <p><code>false</code> otherwise * @see #cachedLoadedData(Object) * @see #setCachedLoadedData(Object) * @see #getCachedLoadedData() * @since 1.0 */ public boolean hasCachedLoadedData() { return null != mCachedLoadedData; } /** * Retrieves the cached loaded content data. * * @return the cached loaded content data; or * <p><code>null</code> if no loaded content data has been cached * @see #cachedLoadedData(Object) * @see #setCachedLoadedData(Object) * @see #hasCachedLoadedData() * @since 1.0 */ public Object getCachedLoadedData() { return mCachedLoadedData; } /** * Simply clones the instance with the default clone method since we * want to create a shallow copy * * @since 1.0 */ public Content clone() { try { return (Content)super.clone(); } catch (CloneNotSupportedException e) { // this should never happen Logger.getLogger("com.uwyn.rife.cmf").severe(ExceptionUtils.getExceptionStackTrace(e)); return null; } } }