| MediaBean.java |
/*
* JBoss, the OpenSource J2EE webOS
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package javax.emb;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.RandomAccessFile;
/**
* This class implements the Media interface and models media objects that are
* transient, immutable, and local. In order to avoid excessive memory use, a
* temporary file may be used to store and access the media content while an
* instance is alive.
*
* @version <tt>$Revision: 1.11 $</tt>
* @author <a href="mailto:ricardoarguello@users.sourceforge.net">Ricardo
* Argüello</a>
*/
public class MediaBean implements Media
{
/** Media name. */
private String name;
/** Media MIME type. */
private String mimeType;
/** Temporary file. */
private transient File tempFile;
/**
* This constructor initializes a new instance with content copied from the
* given content stream, and the given mime type and name. The given name is
* a file name that should be associated with the object. If the given
* mimeType is <code>null</code>, one is chosen automatically by
* analyzing the given file extension, or <code>Media.MIME_TYPE_UNKNOWN</code>
* is assigned in case none can be derived.
*
* <p>This constructor is suitable for media content regardless of its
* size. Please note that the given input stream is closed once the content
* is read completely. Also note that a temporary file is used internally to
* maintain the content. The implementation tries to delete this file once
* the instance is garbage collected, and again once the process dies in
* case the former attempt fails.
*
* @param contentStream media content stream.
* @param mimeType media mime type.
* @param name media name.
* @throws javax.emb.ContentAccessException if something goes wrong during
* content transfer.
* @throws java.lang.NullPointerException if the given content stream or
* name is <code>null</code>.
*/
public MediaBean(InputStream contentStream, String mimeType, String name)
throws MediaException
{
if (contentStream == null || name == null)
{
throw new NullPointerException();
}
this.name = name;
if (mimeType != null)
{
this.mimeType = mimeType;
}
else
{
try
{
// Lookup a mime type given the file extension
MediaFormatRegistry.SINGLETON.lookup(getFileExtension(name));
}
catch (FormatNotFoundException e)
{
this.mimeType = Media.MIME_TYPE_UNKNOWN;
}
}
String tempFilePrefix = getFileName(name);
String tempFileSuffix = getFileExtension(name);
try
{
// Create the temporary file
tempFile = File.createTempFile(tempFilePrefix, tempFileSuffix);
tempFile.deleteOnExit();
// Copy the contents of the content stream to the temporary file
OutputStream tempFileStream = new FileOutputStream(tempFile);
try
{
int DEFAULT_BUFFER_SIZE = 65536;
byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
int bytesRead;
// Copy contentStream to tempFileStream
while ((bytesRead = contentStream.read(buffer)) != -1)
{
tempFileStream.write(buffer, 0, bytesRead);
}
}
catch (IOException e)
{
// Throwed by OutputStream.write(byte[], int, int);
throw new ContentAccessException(e.getMessage());
}
finally
{
try
{
tempFileStream.close();
}
catch (IOException ignore)
{
}
}
}
catch (IOException e)
{
// Throwed by File.createTempFile(String, String);
throw new ContentAccessException(e.getMessage());
}
finally
{
try
{
contentStream.close();
}
catch (IOException ignore)
{
}
}
}
/**
* This constructor wraps a new instance around the given media file. The
* name property of the receiver is initialized to the name of the given
* file (without path information). If the given mimeType is null, one is
* chosen automatically by analyzing the file extension, or <code>Media.MIME_TYPE_UNKNOWN</code>
* is assigned in case none can be derived.
*
* This constructor is useful to invoke a media related service on an
* existing media file without copying the content of the latter. Please
* note that the file is not deleted once an instance referencing it is
* garbage collected.
*
* @param mediaFile a file.
* @param mimeType the optional MIME type of the content.
* @throws javax.emb.ContentAccessException if something goes wrong during
* content transfer, or if the given file is not present or cannot
* be accessed.
* @throws java.lang.NullPointerException if the given media file is null.
*/
public MediaBean(File mediaFile, String mimeType) throws MediaException
{
if (mediaFile == null)
{
throw new NullPointerException();
}
if (!mediaFile.exists())
{
throw new ContentAccessException("The given file is not present or cannot be accessed.");
}
this.tempFile = mediaFile;
this.name = mediaFile.getName();
if (mimeType != null)
{
this.mimeType = mimeType;
}
else
{
try
{
// Lookup a mime type given the file extension
MediaFormatRegistry.SINGLETON.lookup(getFileExtension(name));
}
catch (FormatNotFoundException e)
{
this.mimeType = Media.MIME_TYPE_UNKNOWN;
}
}
}
/**
* @see javax.emb.Media#getContent()
*/
public byte[] getContent() throws MediaException
{
long size = getSize();
if (size > Integer.MAX_VALUE)
{
throw new ContentTooLargeException("Content exceeds maximum Java array size.");
}
return getContent(0, (int) size);
}
/**
* @see javax.emb.Media#getFormat()
*/
public MediaFormat getFormat() throws MediaException
{
String fileExtension = getFileExtension(name);
return MediaFormatRegistry.SINGLETON.lookup(fileExtension);
}
/**
* @see javax.emb.Media#getHeader()
*/
public MediaHeader getHeader() throws MediaException
{
return getFormat().extractHeader(getContentStream());
}
/**
* @see javax.emb.Media#getMimeType()
*/
public String getMimeType() throws MediaException
{
return mimeType;
}
/**
* @see javax.emb.Media#getName()
*/
public String getName() throws MediaException
{
return name;
}
/**
* @see javax.emb.Media#getProxy()
*/
public Media getProxy() throws MediaException
{
return getFormat().extractProxy(getContentStream());
}
/**
* @see javax.emb.Media#getSize()
*/
public long getSize() throws MediaException
{
return tempFile.length();
}
/**
* @see javax.emb.Media#readContent(long, byte[])
*/
public int readContent(long position, byte[] buffer) throws MediaException
{
return this.readContent(position, buffer, 0, buffer.length);
}
/**
* @see javax.emb.Media#readContent(long, byte[], int, int)
*/
public int readContent(long position, byte[] buffer, int offset, int length)
throws MediaException
{
if (position < 0 || position > getSize())
{
throw new IndexOutOfBoundsException();
}
if (position < 0)
{
throw new NegativeArraySizeException();
}
if (buffer == null)
{
throw new NullPointerException();
}
// TODO: Calculate offset
int bytesRead = 0;
try
{
InputStream contentStream = new FileInputStream(tempFile);
long contentPosition = contentStream.skip(position);
bytesRead = contentStream.read(buffer, offset, length);
}
catch (IOException e)
{
throw new ContentAccessException(e.getMessage());
}
return bytesRead;
}
private byte[] getContent(long position, int length) throws MediaException
{
if (position < 0 || position > getSize())
{
throw new IndexOutOfBoundsException();
}
int contentLength;
if ((getSize() - position) < (long) length)
{
contentLength = (int) (getSize() - position);
}
else
{
contentLength = length;
}
RandomAccessFile randomAccessFile = null;
try
{
randomAccessFile = new RandomAccessFile(tempFile, "r");
byte[] content = new byte[contentLength];
randomAccessFile.seek(position);
randomAccessFile.read(content);
return content;
}
catch (FileNotFoundException e)
{
throw new ContentAccessException(e.getMessage());
}
catch (IOException e)
{
throw new ContentAccessException(e.getMessage());
}
finally
{
if (randomAccessFile != null)
{
try
{
randomAccessFile.close();
}
catch (IOException ignore)
{
}
}
}
}
/**
* Returns an input stream on the receiver's content that can be utilized to
* read said content in a stream I/O fashion.
*
* <p>This method can be used instead of the generic block access to
* content as defined in the <code>Media</code> interface to reduce memory
* fragmentation in order to reduce garbage collection.
*
* @return content stream.
* @throws javax.emb.ContentAccessException if the content cannot be
* accessed.
*/
private InputStream getContentStream() throws MediaException
{
try
{
return new FileInputStream(tempFile);
}
catch (FileNotFoundException e)
{
throw new ContentAccessException(e.getMessage());
}
}
private static String getFileName(String name)
{
int lastDotPosition = name.lastIndexOf('.');
if (lastDotPosition == -1)
{
return name;
}
else
{
return name.substring(0, lastDotPosition);
}
}
private static String getFileExtension(String name)
{
int lastDotPosition = name.lastIndexOf('.');
if (lastDotPosition == -1)
{
return null;
}
else
{
return name.substring(lastDotPosition + 1);
}
}
}| MediaBean.java |