/*
 * JBoss, the OpenSource J2EE webOS
 * 
 * Distributable under LGPL license.
 * See terms of license at gnu.org.
 */

package javax.emb;

import java.io.InputStream;
import java.net.URL;

import javax.ejb.EJBLocalObject;

/**
 * This basic interface extends the {@link javax.emb.Media}interface with
 * behavior common to all kinds of media objects that are persistent and can be
 * altered. It also extends <code>EJBLocalObject</code> and therefore
 * represents the local interface of a media entity EJB.
 * 
 * <p>Media Entity EJBs consist of the five basic alterable properties:
 * 
 * <ul><li>The content property models the byte content of a media entity
 * EJB. As such content can become rather large, additional streaming I/O
 * accessors are provided in addition to the standard set of get/set methods.
 * The content length of a single media entity EJB is not limited to 2GB; it
 * can theoretically be up to about 9 hexabytes (2^63) in size. Note that the
 * presence of the content property does not mean an implementation has to load
 * the media content into memory; as most implementations will avoid this to
 * keep memory consumption at bay. Also note that the content property is
 * correlated to the location property, i.e. the content property cannot be set
 * if the location property is set and vice versa. The default value for this
 * property is <code>null</code>.</li>
 * 
 * <li>The location property allows a media entity to gain read access to
 * externally managed content, as opposed to the content property which models
 * internally managed content. For example, a location URL can point to an HTTP
 * site that hosts an image. If the location property is set, read access to
 * the content is possible, but all operations requiring write access to the
 * content will fail. The location property is correlated to the content
 * property, i.e. the location property cannot be set if the content property
 * is set and vice versa. The default value for this property is <code>null</code>.
 * </li>
 * 
 * <li>The description property allows a textual description to be associated
 * with a media entity EJB, for example to be displayed in conjunction with
 * some thumbnail in an image list for orientation. The default value for this
 * property is <code>null</code>.</li>
 * 
 * <li>The name property models a file name that is used as a default in case
 * the content has to be exported to a file. The media format of a media entity
 * EJB is derived from the file name extension. The default value for this
 * property is <code>null</code>.</li>
 * 
 * <li>The mimeType property is used to hint web application programmers of
 * which mime type to use when transferring content directly over HTTP. The
 * default value for this property is <code>null</code>, but unless both the
 * mimeType and name properties are <code>null</code> the mimeType accessor
 * will provide a format specific default mime type.</li></ul>
 * 
 * @version <tt>$Revision: 1.3 $</tt>
 * @author <a href="mailto:ricardoarguello@users.sourceforge.net">Ricardo
 *         Argüello</a>
 */
public interface MediaEntityLocal extends EJBLocalObject, Media
{
   /**
    * Adds the given listener to the list of persistent observers that are
    * notified of important state changes or activities inside the receiver. If
    * the given listener is already part of the receiver's list of persistent
    * observers, no action is performed. Note that listeners are distinguished
    * using checks for content equality, not content identity.
    * 
    * @param listener the listener.
    * @throws java.lang.NullPointerException if the value passed is <code>null</code>.
    */
   void addListener(MediaListener listener) throws MediaException;

   /**
    * Adds the given metadata to the receiver's list of associated metadata.
    * Metadata consists of XML content that has been stored in separate
    * MetaDataEntity EJBs. Several applications can associate XML metadata with
    * a single media entity. If the given metadata EJB is already part of the
    * receiver's list of metadata entities, no action is performed.
    * 
    * @param metaData metadata.
    * @throws java.lang.NullPointerException if the value passed is <code>null</code>.
    */
   void addMetaData(MetaDataEntityLocal metaData) throws MediaException;

   /**
    * This operation updates the receiver's content after performing a series
    * of transformations on the original content, as defined in the given
    * specifications array. The order of the specifications array defines the
    * order of the transformations being performed. This allows modification of
    * the receiver without transferring the content over machine boundaries.
    * Note that the receiver's format can change due to this operation, and
    * that it implicitly updates the receiver's lastModified property. Also
    * note that this operation will fail if the location property is set.
    * 
    * @param specifications array of <code>MediaConverterSpec</code>s.
    * @throws java.lang.NullPointerException if the value passed is <code>null</code>.
    * @throws javax.emb.ContentAccessException if the content cannot be
    *         accessed.
    * @throws javax.emb.ContentUnmutableException if the <code>location</code>
    *         property is not <code>null</code>.
    * @throws javax.emb.MediaFormatException if a problem occurs handling the
    *         different media formats involved.
    * @throws javax.emb.ConversionException if one of the conversions fails.
    * @throws javax.emb.ListenerVetoException if a media listener vetoes the
    *         change.
    * @throws javax.emb.ContentTooLargeException if the content generated is
    *         larger than supported by the implementation.
    */
   void convert(MediaConverterSpec[] specifications) throws MediaException;

   /**
    * Copies the receiver's content to the given target directory location, a
    * URL pointing to a directory. If <code>null</code> is passed, the
    * content is exported to a default directory. The URL must be of protocol
    * type "file" or any additional protocol supported by the implementation.
    * In case of non-embedded media formats, the content of related children is
    * also recursively copied into the same directory or one of its
    * subdirectories. Implementations must guarantee that no existing files are
    * overwritten during execution, i.e. they must resolve naming conflicts by
    * generating file names and adjusting parent content if necessary.
    * 
    * <p>The location returned points to the file exported for the receiver,
    * which is necessary to know in case a directory location was given, or the
    * location given pointed to an existing file.
    * 
    * @param targetDirectoryLocation a URL pointing to a directory. Must be of
    *        protocol type "file".
    * @return URL
    * @throws javax.emb.ContentAccessException if the content cannot be stored
    *         at the given target location, or if the content transfer fails.
    * @throws javax.emb.MalformedLocationException if the given target location
    *         is malformed or the given protocol is not supported.
    * @throws javax.emb.MediaFormatException is thrown if there is a problem
    *         dealing with one of the media formats involved.
    */
   URL exportMedia(URL targetDirectoryLocation) throws MediaException;

   /**
    * Returns the receiver's children as an array of media entities. Children
    * are media entities being referenced from within the receiver's content,
    * and the array is therefore guaranteed to be empty in case of embedded
    * media formats.
    * 
    * <p>Note that in case of non-embedded media formats a change of the media
    * content can implicitly alter the set of children. Also note that altering
    * the resulting array content will not alter the persisted set of children,
    * i.e. no persistent relationship collection is exposed. The reason for
    * this is that the number of children depends on the content.
    * 
    * @return the receiver's children as an array of media entities.
    */
   MediaEntityLocal[] getChildren() throws MediaException;

   /**
    * Returns the receiver's description as a String or <code>null</code>.
    * The string is not guaranteed to have any structure, and is primarily
    * designed to allow storing a descriptive label without the need to model
    * an EJB relation to another entity bean describing the receiver.
    * 
    * @return the receiver's description.
    */
   String getDescription() throws MediaException;

   /**
    * Returns a timestamp stating when the receiver's persistent state was last
    * modified. Note that relationships are not considered part of the
    * persistent state and therefore don't affect the value of this property.
    * 
    * @return the receiver's persistent state last modification date.
    */
   long getLastModified() throws MediaException;

   /**
    * Returns an array containing the media listeners associated with the
    * receiver. If no listeners are associated with the receiver, an empty
    * array is returned. Note that listeners are distinguished using checks for
    * content equality, not content identity.
    * 
    * @return the persistent listeners observing to the receiver.
    */
   MediaListener[] getListeners() throws MediaException;

   /**
    * Returns the location of the media content as an instance of
    * {@link java.net.URL}or <code>null</code> if no location has been set.
    */
   URL getLocation() throws MediaException;

   /**
    * Returns the receiver's associated metadata as an array of MetaDataEntity
    * EJBs. Metadata consists of XML content that has been stored in separate
    * MetaDataEntity EJBs. Several applications can associate their metadata
    * with a single MetaDataEntity EJB. An empty array is returned if no
    * metadata has been set.
    * 
    * @return metadata
    */
   MetaDataEntityLocal[] getMetaData() throws MediaException;

   /**
    * Returns the succeeding version of the receiver, which allows querying and
    * a history chain of media objects that represent the same thing. The value
    * <code>null</code> is returned if no next version exists.
    */
   MediaEntityLocal getNextVersion() throws MediaException;

   /**
    * Returns the receiver's parents as an array of media entities. Parents are
    * media entities that reference the receiver as their child, and the
    * collection is therefore guaranteed to consist entirely of non-embedded
    * media entities. Note that changing parents' content can alter a child
    * media entitie's set of parents implicitly. An empty array is returned if
    * no parents are available.
    */
   MediaEntityLocal[] getParents() throws MediaException;

   /**
    * Returns the previous version of the receiver, which allows querying a
    * history of media objects that represent the same logical thing. The value
    * <code>null</code> is returned if no previous version exists.
    * 
    * @return @throws MediaException
    */
   MediaEntityLocal getPreviousVersion() throws MediaException;

   /**
    * Alters the content of the receiver with the one read from the given
    * source location, a URL of type "file" or any other protocol type
    * supported by the implementation pointing to a piece of content. If the
    * given name is not <code>null</code>, the name property is also set to
    * match the given name. It may only contain characters that are valid in
    * file names. If both the name property and the name given are <code>null</code>
    * the name property is updated with a generated name, possibly based on the
    * given source location.
    * 
    * <p>In case the media content is non-embedded, the operation recursively
    * creates media entity EJBs for the children, with their respective names
    * being derived from the child links within the content. Note that the
    * operation identifies children that are referenced from multiple parents
    * in the operation's context and avoids creating multiple media entity EJBs
    * in this case.
    * 
    * <p>Please note that passing a sourceLocation that is equal to the
    * receiver's current location is allowed and can trigger the recursive
    * recreation of all children. Additionally the receiver's format can change
    * due to this operation if the file extension passed with the given name
    * differs from the one set for the receiver. Also note that this operation
    * implicitly updates the receiver's lastModified property, and it will fail
    * if the location property is set.
    * 
    * @param sourceLocation
    * @param name
    * @throws java.lang.NullPointerException if the value passed is <code>null</code>.
    * @throws java.lang.IllegalArgumentException if the name argument passed
    *         contains invalid characters.
    * @throws javax.emb.ContentAccessException if the content cannot be
    *         accessed at the given source location, or if the content transfer
    *         fails.
    * @throws javax.emb.ContentUnmutableException is thrown if the location
    *         property is not <code>null</code>.
    * @throws javax.ejb.CreateException if the creation of a child EJB fails.
    * @throws javax.emb.MediaFormatException if a format related problem
    *         occurs.
    * @throws javax.emb.MalformedLocationException if the given source location
    *         is malformed.
    * @throws javax.emb.ListenerVetoException if a media listener vetoes the
    *         change.
    * @throws javax.emb.ContentTooLargeException if the content given is larger
    *         than supported by the implementation.
    */
   void importMedia(URL sourceLocation, String name) throws MediaException;

   /**
    * Removes the given listener from the list of persistent observers that are
    * notified of important state changes or activities inside the receiver. If
    * the listener is not part of the receiver's list of persistent observers,
    * no action is performed. Note that listeners are distinguished using
    * checks for content equality, not content identity.
    * 
    * @param listener the listener.
    * @throws java.lang.NullPointerException if the value passed is <code>null</code>.
    */
   void removeListener(MediaListener listener) throws MediaException;

   /**
    * Removes the given metadata from the receiver's list of associated
    * metadata. Metadata consists of XML content that has been stored in
    * MetaDataEntity EJBs. Several applications can associate XML metadata with
    * a single media entity. If the given metadata EJB is not part of the
    * receiver's list of metadata entities, no action is performed.
    * 
    * <p>Note that this operation will not remove the MetaDataEntity EJB from
    * the persistent store, but rather disassociate the metadata from the Media
    * Entity on which the method was invoked.
    * 
    * @param metaData metadata
    * @throws java.lang.NullPointerException if the value passed is <code>null</code>.
    */
   void removeMetaData(MetaDataEntityLocal metaData) throws MediaException;

   /**
    * This operation sets the children of the receiver to an array of media
    * entity EJBs. Note that the number of children passed must match the
    * number of existing children. Also note that this operation is only
    * allowed if the content property is set because it might require updating
    * said content.
    * 
    * @param children children
    * @throws java.lang.NullPointerException if the value passed or one of its
    *         elements is <code>null</code>.
    * @throws java.lang.IllegalArgumentException if the value passed has more
    *         or fewer elements than the receiver's existing number of
    *         children.
    * @throws javax.emb.ContentUnmutableException if the <code>location</code>
    *         property is set.
    * @throws javax.emb.ContentAccessException if the <code>content</code>
    *         has not been set.
    */
   void setChildren(MediaEntityLocal[] children) throws MediaException;

   /**
    * This operation offers a convenient way to alter the content of the
    * receiver for small and embedded media content. In case the content is
    * non-embedded, the <code>importMedia(URL, String)</code> operation
    * should be used instead, as this method only modifies the receiver's
    * content and no child content is affected. The same is true if the content
    * is rather large.
    * 
    * <p>If both the value passed and the receiver's existing content property
    * are not <code>null</code>, no format change may occur during this
    * operation. If the location property is not <code>null</code> then this
    * operation is not permitted. Note that the location property may not be
    * set while the content property contains a value different from <code>null</code>.
    * Note that this operation implicitly updates the receive's <code>lastModified</code>
    * property. Also note that this operation will fail if the <code>location</code>
    * property is set.
    * 
    * @param content content.
    * @throws javax.emb.ContentAccessException if content transfer fails.
    * @throws javax.emb.FormatNotFoundException if the name property is <code>null</code>.
    * @throws javax.emb.FormatSyntaxException if the system notices a format
    *         change.
    * @throws javax.emb.ContentUnmutableException if the location property is
    *         not <code>null</code>.
    * @throws javax.emb.ContentTooLargeException if the content given is larger
    *         than supported by the implementation.
    */
   void setContent(byte[] content) throws MediaException;

   /**
    * This operation offers a convenient way to alter the content of the
    * receiver for all kinds of embedded media formats. If the content is
    * non-embedded, the <code>importMedia(URL, String)</code> operation
    * should be used instead, as this method only modifies the receiver's
    * content and no child content is affected. The same is true if the content
    * is rather large.
    * 
    * <p>If both the value passed and the receiver's existing content property
    * are not <code>null</code>, no format change may occur during this
    * operation. If the location property is not <code>null</code>, this
    * operation is not permitted. The location property may not be set while
    * the content property contains a value different from <code>null</code>.
    * Note that this operation implicitly updates the receiver's lastModified
    * property. Also note that this operation will fail if the <code>location</code>
    * property is set.
    * 
    * @param content content.
    * @throws java.lang.NullPointerException if the value passed is <code>null</code>.
    * @throws javax.emb.ContentAccessException if content transfer fails.
    * @throws javax.emb.FormatNotFoundException if the name property is <code>null</code>.
    * @throws javax.emb.FormatSyntaxException if the system notices a format
    *         change.
    * @throws javax.emb.ContentUnmutableException if the location property is
    *         not <code>null</code>.
    * @throws javax.emb.ListenerVetoException if a media listener vetoes the
    *         change.
    * @throws javax.emb.ContentTooLargeException if the content given is larger
    *         than supported by the implementation.
    */
   void setContent(InputStream content) throws MediaException;

   /**
    * Alters the receiver's description. The description string is primarily
    * designed to allow storing a descriptive label without the need to model
    * an EJB relation to another entity bean describing the receiver. Passing
    * <code>null</code> causes the description field to be reset to <code>null</code>.
    * Note that this operation implicitly updates the receiver's <code>lastModified</code>
    * property.
    * 
    * @param description description.
    * @throws javax.emb.ListenerVetoException if a media listener vetoes the
    *         change.
    */
   void setDescription(String description) throws MediaException;

   /**
    * Sets the location of the receiver to the given location URL or <code>null</code>.
    * The purpose of this method is to provide a mechanism for read access to
    * externally managed content. For example, content that is hosted by an
    * external content provider.
    * 
    * <p>Note that if the content property is not <code>null</code>, this
    * operation is not permitted. Note that the content property may not be set
    * while the <code>location</code> property contains a value different
    * from <code>null</code>. Also note that this operation implicitly
    * updates the receiver's <code>lastModified</code> property.
    * 
    * @param location location URL.
    * @throws javax.emb.ContentAccessException if the media content cannot be
    *         accessed under the new location, or if the given location URL
    *         points to a directory.
    * @throws javax.emb.LocationUnmutableException if the content property is
    *         not <code>null</code>.
    * @throws javax.emb.ListenerVetoException if a media listener vetoes the
    *         change.
    */
   void setLocation(URL location) throws MediaException;

   /**
    * Alters the receiver's MIME type that allows media content to be written
    * directly to a Servlet output stream. Note that this operation implicitly
    * updates the receiver's <code>lastModified</code> property. Note that
    * passing <code>null</code> will cause the <code>getMimeType()</code>
    * method to return a format specific default. Also note that this operation
    * implicitly updates the receiver's <code>lastModified</code> property.
    * 
    * @param mimeType MIME type.
    * @throws javax.emb.ListenerVetoException if a media listener vetoes the
    *         change.
    */
   void setMimeType(String mimeType) throws MediaException;

   /**
    * Sets the receiver's non-unique name as a <code>String</code>. The name
    * is used as a file name hint in case the media content is to be stored or
    * published in a file system and therefore may only contain characters that
    * are valid in file names. Also, it must contain a file extension that
    * represents the receiver's media format. Note that this operation
    * implicitly updates the receiver's <code>lastModified</code> property.
    * 
    * @param name name.
    * @throws java.lang.NullPointerException if the value passed is <code>null</code>.
    * @throws java.lang.IllegalArgumentException if the name argument passed
    *         contains invalid characters.
    * @throws javax.emb.FormatNotFoundException if the format cannot be
    *         determined from the file extension.
    * @throws javax.emb.ListenerVetoException is thrown if a media listener
    *         vetoes the change.
    */
   void setName(String name) throws MediaException;

   /**
    * Defines the given media entity to be the preceding version of the
    * receiver, which allows querying a history chain of media objects that
    * represent the same logical thing. In return, the operation causes the
    * receiver to be the given media entity's next version. Passing the value
    * <code>null</code> causes the receiver not to have a previous version
    * anymore. The operation is only allowed if version chain integrity is
    * preserved:
    * 
    * <ul><li>If the given media entity is the receiver itself: A
    * javax.emb.VersionChainIntegrityException is thrown.</li>
    * 
    * <li>If the given media entity is already the previous version of the
    * receiver: No action is performed.</li>
    * 
    * <li>If the given media entity is <code>null</code>: A
    * javax.emb.VersionChainIntegrityException is thrown if the receiver has a
    * successor.</li>
    * 
    * <li>Otherwise: A javax.emb.VersionChainIntegrityException is thrown if
    * the given media entity has a successor, or if the receiver has a
    * predecessor, a successor, or both.</li></ul>
    *  
    */
   void setPreviousVersion(MediaEntityLocal mediaEntity) throws MediaException;

   /**
    * Sets the given media entity as the receiver's persistent proxy, e.g. a
    * thumbnail, an icon, a short video or audio clip of any format. Proxies
    * represent media objects to give people interested an up front impression
    * of the latter. If there is already a proxy relation for the receiver, the
    * old relation is discarded and the old persistent proxy is not deleted. In
    * case <code>null</code> is passed, the relation to any existing
    * persistent proxy is broken up and <code>getProxy()</code> will return a
    * generated transient proxy.
    * 
    * @param mediaEntity media entity.
    */
   void setProxy(MediaEntityLocal mediaEntity) throws MediaException;
}