/*
* BitstreamFormat.java
*
* Version: $Revision: 3761 $
*
* Date: $Date: 2009-05-07 04:18:02 +0000 (Thu, 07 May 2009) $
*
* Copyright (c) 2002-2009, The DSpace Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of the DSpace Foundation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
package org.dspace.content;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import org.apache.log4j.Logger;
import org.dspace.authorize.AuthorizeException;
import org.dspace.authorize.AuthorizeManager;
import org.dspace.core.ConfigurationManager;
import org.dspace.core.Context;
import org.dspace.core.LogManager;
import org.dspace.storage.rdbms.DatabaseManager;
import org.dspace.storage.rdbms.TableRow;
import org.dspace.storage.rdbms.TableRowIterator;
/**
* Class representing a particular bitstream format.
* <P>
* Changes to the bitstream format metadata are only written to the database
* when <code>update</code> is called.
*
* @author Robert Tansley
* @version $Revision: 3761 $
*/
public class BitstreamFormat
{
/** log4j logger */
private static Logger log = Logger.getLogger(BitstreamFormat.class);
/**
* The "unknown" support level - for bitstream formats that are unknown to
* the system
*/
public static final int UNKNOWN = 0;
/**
* The "known" support level - for bitstream formats that are known to the
* system, but not fully supported
*/
public static final int KNOWN = 1;
/**
* The "supported" support level - for bitstream formats known to the system
* and fully supported.
*/
public static final int SUPPORTED = 2;
/** Our context */
private Context bfContext;
/** The row in the table representing this format */
private TableRow bfRow;
/** File extensions for this format */
private List extensions;
/**
* Class constructor for creating a BitstreamFormat object based on the
* contents of a DB table row.
*
* @param context
* the context this object exists in
* @param row
* the corresponding row in the table
* @throws SQLException
*/
BitstreamFormat(Context context, TableRow row) throws SQLException
{
bfContext = context;
bfRow = row;
extensions = new ArrayList();
TableRowIterator tri = DatabaseManager.query(context,
"SELECT * FROM fileextension WHERE bitstream_format_id= ? ",
getID());
try
{
while (tri.hasNext())
{
extensions.add(tri.next().getStringColumn("extension"));
}
}
finally
{
// close the TableRowIterator to free up resources
if (tri != null)
tri.close();
}
// Cache ourselves
context.cache(this, row.getIntColumn("bitstream_format_id"));
}
/**
* Get a bitstream format from the database.
*
* @param context
* DSpace context object
* @param id
* ID of the bitstream format
*
* @return the bitstream format, or null if the ID is invalid.
* @throws SQLException
*/
public static BitstreamFormat find(Context context, int id)
throws SQLException
{
// First check the cache
BitstreamFormat fromCache = (BitstreamFormat) context.fromCache(
BitstreamFormat.class, id);
if (fromCache != null)
{
return fromCache;
}
TableRow row = DatabaseManager.find(context, "bitstreamformatregistry",
id);
if (row == null)
{
if (log.isDebugEnabled())
{
log.debug(LogManager.getHeader(context,
"find_bitstream_format",
"not_found,bitstream_format_id=" + id));
}
return null;
}
// not null, return format object
if (log.isDebugEnabled())
{
log.debug(LogManager.getHeader(context, "find_bitstream_format",
"bitstream_format_id=" + id));
}
return new BitstreamFormat(context, row);
}
/**
* Find a bitstream format by its (unique) MIME type.
* If more than one bitstream format has the same MIME type, the
* one returned is unpredictable.
*
* @param context
* DSpace context object
* @param mimeType
* MIME type value
*
* @return the corresponding bitstream format, or <code>null</code> if
* there's no bitstream format with the given MIMEtype.
* @throws SQLException
*/
public static BitstreamFormat findByMIMEType(Context context,
String mimeType) throws SQLException
{
// NOTE: Avoid internal formats since e.g. "License" also has
// a MIMEtype of text/plain.
TableRow formatRow = DatabaseManager.querySingle(context,
"SELECT * FROM bitstreamformatregistry "+
"WHERE mimetype LIKE ? AND internal = '0' ",
mimeType);
if (formatRow == null)
return null;
return findByFinish(context, formatRow);
}
/**
* Find a bitstream format by its (unique) short description
*
* @param context
* DSpace context object
* @param desc
* the short description
*
* @return the corresponding bitstream format, or <code>null</code> if
* there's no bitstream format with the given short description
* @throws SQLException
*/
public static BitstreamFormat findByShortDescription(Context context,
String desc) throws SQLException
{
TableRow formatRow = DatabaseManager.findByUnique(context,
"bitstreamformatregistry", "short_description", desc);
if (formatRow == null)
{
return null;
}
return findByFinish(context, formatRow);
}
// shared final logic in findBy... methods;
// use context's cache for object mapped from table row.
private static BitstreamFormat findByFinish(Context context,
TableRow formatRow)
throws SQLException
{
// not null
if (log.isDebugEnabled())
{
log.debug(LogManager.getHeader(context, "find_bitstream",
"bitstream_format_id="
+ formatRow.getIntColumn("bitstream_format_id")));
}
// From cache?
BitstreamFormat fromCache = (BitstreamFormat) context.fromCache(
BitstreamFormat.class, formatRow
.getIntColumn("bitstream_format_id"));
if (fromCache != null)
{
return fromCache;
}
return new BitstreamFormat(context, formatRow);
}
/**
* Get the generic "unknown" bitstream format.
*
* @param context
* DSpace context object
*
* @return the "unknown" bitstream format.
* @throws SQLException
*
* @throws IllegalStateException
* if the "unknown" bitstream format couldn't be found
*/
public static BitstreamFormat findUnknown(Context context)
throws SQLException
{
BitstreamFormat bf = findByShortDescription(context, "Unknown");
if (bf == null)
{
throw new IllegalStateException(
"No `Unknown' bitstream format in registry");
}
return bf;
}
/**
* Retrieve all bitstream formats from the registry, ordered by ID
*
* @param context
* DSpace context object
*
* @return the bitstream formats.
* @throws SQLException
*/
public static BitstreamFormat[] findAll(Context context)
throws SQLException
{
List formats = new ArrayList();
TableRowIterator tri = DatabaseManager.queryTable(context, "bitstreamformatregistry",
"SELECT * FROM bitstreamformatregistry ORDER BY bitstream_format_id");
try
{
while (tri.hasNext())
{
TableRow row = tri.next();
// From cache?
BitstreamFormat fromCache = (BitstreamFormat) context.fromCache(
BitstreamFormat.class, row
.getIntColumn("bitstream_format_id"));
if (fromCache != null)
{
formats.add(fromCache);
}
else
{
formats.add(new BitstreamFormat(context, row));
}
}
}
finally
{
// close the TableRowIterator to free up resources
if (tri != null)
tri.close();
}
// Return the formats as an array
BitstreamFormat[] formatArray = new BitstreamFormat[formats.size()];
formatArray = (BitstreamFormat[]) formats.toArray(formatArray);
return formatArray;
}
/**
* Retrieve all non-internal bitstream formats from the registry. The
* "unknown" format is not included, and the formats are ordered by support
* level (highest first) first then short description.
*
* @param context
* DSpace context object
*
* @return the bitstream formats.
* @throws SQLException
*/
public static BitstreamFormat[] findNonInternal(Context context)
throws SQLException
{
List formats = new ArrayList();
String myQuery = "SELECT * FROM bitstreamformatregistry WHERE internal='0' "
+ "AND short_description NOT LIKE 'Unknown' "
+ "ORDER BY support_level DESC, short_description";
TableRowIterator tri = DatabaseManager.queryTable(context,
"bitstreamformatregistry", myQuery);
try
{
while (tri.hasNext())
{
TableRow row = tri.next();
// From cache?
BitstreamFormat fromCache = (BitstreamFormat) context.fromCache(
BitstreamFormat.class, row
.getIntColumn("bitstream_format_id"));
if (fromCache != null)
{
formats.add(fromCache);
}
else
{
formats.add(new BitstreamFormat(context, row));
}
}
}
finally
{
// close the TableRowIterator to free up resources
if (tri != null)
tri.close();
}
// Return the formats as an array
BitstreamFormat[] formatArray = new BitstreamFormat[formats.size()];
formatArray = (BitstreamFormat[]) formats.toArray(formatArray);
return formatArray;
}
/**
* Create a new bitstream format
*
* @param context
* DSpace context object
* @return the newly created BitstreamFormat
* @throws SQLException
* @throws AuthorizeException
*/
public static BitstreamFormat create(Context context) throws SQLException,
AuthorizeException
{
// Check authorisation - only administrators can create new formats
if (!AuthorizeManager.isAdmin(context))
{
throw new AuthorizeException(
"Only administrators can create bitstream formats");
}
// Create a table row
TableRow row = DatabaseManager.create(context,
"bitstreamformatregistry");
log.info(LogManager.getHeader(context, "create_bitstream_format",
"bitstream_format_id="
+ row.getIntColumn("bitstream_format_id")));
return new BitstreamFormat(context, row);
}
/**
* Get the internal identifier of this bitstream format
*
* @return the internal identifier
*/
public int getID()
{
return bfRow.getIntColumn("bitstream_format_id");
}
/**
* Get a short (one or two word) description of this bitstream format
*
* @return the short description
*/
public String getShortDescription()
{
return bfRow.getStringColumn("short_description");
}
/**
* Set the short description of the bitstream format
*
* @param s
* the new short description
*/
public void setShortDescription(String s)
throws SQLException
{
// You can not reset the unknown's registry's name
BitstreamFormat unknown = null;;
try {
unknown = findUnknown(bfContext);
} catch (IllegalStateException e) {
// No short_description='Unknown' found in bitstreamformatregistry
// table. On first load of registries this is expected because it
// hasn't been inserted yet! So, catch but ignore this runtime
// exception thrown by method findUnknown.
}
// If the exception was thrown, unknown will == null so goahead and
// load s. If not, check that the unknown's registry's name is not
// being reset.
if (unknown == null || unknown.getID() != getID()) {
bfRow.setColumn("short_description", s);
}
}
/**
* Get a description of this bitstream format, including full application or
* format name
*
* @return the description
*/
public String getDescription()
{
return bfRow.getStringColumn("description");
}
/**
* Set the description of the bitstream format
*
* @param s
* the new description
*/
public void setDescription(String s)
{
bfRow.setColumn("description", s);
}
/**
* Get the MIME type of this bitstream format, for example
* <code>text/plain</code>
*
* @return the MIME type
*/
public String getMIMEType()
{
return bfRow.getStringColumn("mimetype");
}
/**
* Set the MIME type of the bitstream format
*
* @param s
* the new MIME type
*/
public void setMIMEType(String s)
{
bfRow.setColumn("mimetype", s);
}
/**
* Get the support level for this bitstream format - one of
* <code>UNKNOWN</code>,<code>KNOWN</code> or <code>SUPPORTED</code>.
*
* @return the support level
*/
public int getSupportLevel()
{
return bfRow.getIntColumn("support_level");
}
/**
* Set the support level for this bitstream format - one of
* <code>UNKNOWN</code>,<code>KNOWN</code> or <code>SUPPORTED</code>.
*
* @param sl
* the new support level
*/
public void setSupportLevel(int sl)
{
// Sanity check
if ((sl < 0) || (sl > 2))
{
throw new IllegalArgumentException("Invalid support level");
}
bfRow.setColumn("support_level", sl);
}
/**
* Find out if the bitstream format is an internal format - that is, one
* that is used to store system information, rather than the content of
* items in the system
*
* @return <code>true</code> if the bitstream format is an internal type
*/
public boolean isInternal()
{
return bfRow.getBooleanColumn("internal");
}
/**
* Set whether the bitstream format is an internal format
*
* @param b
* pass in <code>true</code> if the bitstream format is an
* internal type
*/
public void setInternal(boolean b)
{
bfRow.setColumn("internal", b);
}
/**
* Update the bitstream format metadata
*
* @throws SQLException
* @throws AuthorizeException
*/
public void update() throws SQLException, AuthorizeException
{
// Check authorisation - only administrators can change formats
if (!AuthorizeManager.isAdmin(bfContext))
{
throw new AuthorizeException(
"Only administrators can modify bitstream formats");
}
log.info(LogManager.getHeader(bfContext, "update_bitstream_format",
"bitstream_format_id=" + getID()));
// Delete extensions
DatabaseManager.updateQuery(bfContext,
"DELETE FROM fileextension WHERE bitstream_format_id= ? ",
getID());
// Rewrite extensions
for (int i = 0; i < extensions.size(); i++)
{
String s = (String) extensions.get(i);
TableRow r = DatabaseManager.create(bfContext, "fileextension");
r.setColumn("bitstream_format_id", getID());
r.setColumn("extension", s);
DatabaseManager.update(bfContext, r);
}
DatabaseManager.update(bfContext, bfRow);
}
/**
* Delete this bitstream format. This converts the types of any bitstreams
* that may have this type to "unknown". Use this with care!
*
* @throws SQLException
* @throws AuthorizeException
*/
public void delete() throws SQLException, AuthorizeException
{
// Check authorisation - only administrators can delete formats
if (!AuthorizeManager.isAdmin(bfContext))
{
throw new AuthorizeException(
"Only administrators can delete bitstream formats");
}
// Find "unknown" type
BitstreamFormat unknown = findUnknown(bfContext);
if (unknown.getID() == getID())
throw new IllegalArgumentException("The Unknown bitstream format may not be deleted.");
// Remove from cache
bfContext.removeCached(this, getID());
// Set bitstreams with this format to "unknown"
int numberChanged = DatabaseManager.updateQuery(bfContext,
"UPDATE bitstream SET bitstream_format_id= ? " +
" WHERE bitstream_format_id= ? ",
unknown.getID(),getID());
// Delete extensions
DatabaseManager.updateQuery(bfContext,
"DELETE FROM fileextension WHERE bitstream_format_id= ? ",
getID());
// Delete this format from database
DatabaseManager.delete(bfContext, bfRow);
log.info(LogManager.getHeader(bfContext, "delete_bitstream_format",
"bitstream_format_id=" + getID() + ",bitstreams_changed="
+ numberChanged));
}
/**
* Get the filename extensions associated with this format
*
* @return the extensions
*/
public String[] getExtensions()
{
String[] exts = new String[extensions.size()];
exts = (String[]) extensions.toArray(exts);
return exts;
}
/**
* Set the filename extensions associated with this format
*
* @param exts
* String [] array of extensions
*/
public void setExtensions(String[] exts)
{
extensions = new ArrayList();
for (int i = 0; i < exts.length; i++)
{
extensions.add(exts[i]);
}
}
}