Package org.dspace.content

Source Code of org.dspace.content.Bitstream

/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.content;

import java.io.IOException;
import java.io.InputStream;
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.Constants;
import org.dspace.core.Context;
import org.dspace.core.LogManager;
import org.dspace.event.Event;
import org.dspace.storage.bitstore.BitstreamStorageManager;
import org.dspace.storage.rdbms.DatabaseManager;
import org.dspace.storage.rdbms.TableRow;
import org.dspace.storage.rdbms.TableRowIterator;

/**
* Class representing bitstreams stored in the DSpace system.
* <P>
* When modifying the bitstream metadata, changes are not reflected in the
* database until <code>update</code> is called. Note that you cannot alter
* the contents of a bitstream; you need to create a new bitstream.
*
* @author Robert Tansley
* @version $Revision$
*/
public class Bitstream extends DSpaceObject
{
    /** log4j logger */
    private static Logger log = Logger.getLogger(Bitstream.class);


    /** The row in the table representing this bitstream */
    private TableRow bRow;

    /** The bitstream format corresponding to this bitstream */
    private BitstreamFormat bitstreamFormat;

    /** Flag set when data is modified, for events */
    private boolean modified;

    /**
     * Private constructor for creating a Bitstream 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
     */
    Bitstream(Context context, TableRow row) throws SQLException
    {
        super(context);
        bRow = row;

        // Get the bitstream format
        bitstreamFormat = BitstreamFormat.find(context, row
                .getIntColumn("bitstream_format_id"));

        if (bitstreamFormat == null)
        {
            // No format: use "Unknown"
            bitstreamFormat = BitstreamFormat.findUnknown(context);

            // Panic if we can't find it
            if (bitstreamFormat == null)
            {
                throw new IllegalStateException("No Unknown bitstream format");
            }
        }

        // Cache ourselves
        context.cache(this, row.getIntColumn("bitstream_id"));

        modified = false;
        clearDetails();
    }

    /**
     * Get a bitstream from the database. The bitstream metadata is loaded into
     * memory.
     *
     * @param context
     *            DSpace context object
     * @param id
     *            ID of the bitstream
     *
     * @return the bitstream, or null if the ID is invalid.
     * @throws SQLException
     */
    public static Bitstream find(Context context, int id) throws SQLException
    {
        // First check the cache
        Bitstream fromCache = (Bitstream) context
                .fromCache(Bitstream.class, id);

        if (fromCache != null)
        {
            return fromCache;
        }

        TableRow row = DatabaseManager.find(context, "bitstream", id);

        if (row == null)
        {
            if (log.isDebugEnabled())
            {
                log.debug(LogManager.getHeader(context, "find_bitstream",
                        "not_found,bitstream_id=" + id));
            }

            return null;
        }

        // not null, return Bitstream
        if (log.isDebugEnabled())
        {
            log.debug(LogManager.getHeader(context, "find_bitstream",
                    "bitstream_id=" + id));
        }

        return new Bitstream(context, row);
    }

    public static Bitstream[] findAll(Context context) throws SQLException
    {
        TableRowIterator tri = DatabaseManager.queryTable(context, "bitstream",
                "SELECT * FROM bitstream");

        List<Bitstream> bitstreams = new ArrayList<Bitstream>();

        try
        {
            while (tri.hasNext())
            {
                TableRow row = tri.next();

                // First check the cache
                Bitstream fromCache = (Bitstream) context.fromCache(
                        Bitstream.class, row.getIntColumn("bitstream_id"));

                if (fromCache != null)
                {
                    bitstreams.add(fromCache);
                }
                else
                {
                    bitstreams.add(new Bitstream(context, row));
                }
            }
        }
        finally
        {
            // close the TableRowIterator to free up resources
            if (tri != null)
            {
                tri.close();
            }
        }

        Bitstream[] bitstreamArray = new Bitstream[bitstreams.size()];
        bitstreamArray = bitstreams.toArray(bitstreamArray);

        return bitstreamArray;
    }

    /**
     * Create a new bitstream, with a new ID. The checksum and file size are
     * calculated. This method is not public, and does not check authorisation;
     * other methods such as Bundle.createBitstream() will check authorisation.
     * The newly created bitstream has the "unknown" format.
     *
     * @param context
     *            DSpace context object
     * @param is
     *            the bits to put in the bitstream
     *
     * @return the newly created bitstream
     * @throws IOException
     * @throws SQLException
     */
    static Bitstream create(Context context, InputStream is)
            throws IOException, SQLException
    {
        // Store the bits
        int bitstreamID = BitstreamStorageManager.store(context, is);

        log.info(LogManager.getHeader(context, "create_bitstream",
                "bitstream_id=" + bitstreamID));

        // Set the format to "unknown"
        Bitstream bitstream = find(context, bitstreamID);
        bitstream.setFormat(null);

        context.addEvent(new Event(Event.CREATE, Constants.BITSTREAM,
                bitstreamID, null, bitstream.getIdentifiers(context)));

        return bitstream;
    }

    /**
     * Register a new bitstream, with a new ID.  The checksum and file size
     * are calculated.  This method is not public, and does not check
     * authorisation; other methods such as Bundle.createBitstream() will
     * check authorisation.  The newly created bitstream has the "unknown"
     * format.
     *
     * @param  context DSpace context object
     * @param assetstore corresponds to an assetstore in dspace.cfg
     * @param bitstreamPath the path and filename relative to the assetstore
     * @return  the newly registered bitstream
     * @throws IOException
     * @throws SQLException
     */
    static Bitstream register(Context context,
        int assetstore, String bitstreamPath)
          throws IOException, SQLException
    {
        // Store the bits
        int bitstreamID = BitstreamStorageManager.register(
            context, assetstore, bitstreamPath);

        log.info(LogManager.getHeader(context,
            "create_bitstream",
            "bitstream_id=" + bitstreamID));

        // Set the format to "unknown"
        Bitstream bitstream = find(context, bitstreamID);
        bitstream.setFormat(null);

        context.addEvent(new Event(Event.CREATE, Constants.BITSTREAM,
                bitstreamID, "REGISTER", bitstream.getIdentifiers(context)));

        return bitstream;
    }

    /**
     * Get the internal identifier of this bitstream
     *
     * @return the internal identifier
     */
    public int getID()
    {
        return bRow.getIntColumn("bitstream_id");
    }

    public String getHandle()
    {
        // No Handles for bitstreams
        return null;
    }

    /**
     * Get the sequence ID of this bitstream
     *
     * @return the sequence ID
     */
    public int getSequenceID()
    {
        return bRow.getIntColumn("sequence_id");
    }

    /**
     * Set the sequence ID of this bitstream
     *
     * @param sid
     *            the ID
     */
    public void setSequenceID(int sid)
    {
        bRow.setColumn("sequence_id", sid);
        modifiedMetadata = true;
        addDetails("SequenceID");
    }

    /**
     * Get the name of this bitstream - typically the filename, without any path
     * information
     *
     * @return the name of the bitstream
     */
    public String getName(){
        return getMetadataFirstValue(MetadataSchema.DC_SCHEMA, "title", null, Item.ANY);
    }

    /**
     * Set the name of the bitstream
     *
     * @param n
     *            the new name of the bitstream
     */
    public void setName(String n) {
        setMetadataSingleValue(MetadataSchema.DC_SCHEMA, "title", null, null, n);
    }

    /**
     * Get the source of this bitstream - typically the filename with path
     * information (if originally provided) or the name of the tool that
     * generated this bitstream
     *
     * @return the source of the bitstream
     */
    public String getSource()
    {
        return getMetadataFirstValue(MetadataSchema.DC_SCHEMA, "source", null, Item.ANY);
    }

    /**
     * Set the source of the bitstream
     *
     * @param n
     *            the new source of the bitstream
     */
    public void setSource(String n) {
        setMetadataSingleValue(MetadataSchema.DC_SCHEMA, "source", null, null, n);
    }

    /**
     * Get the description of this bitstream - optional free text, typically
     * provided by a user at submission time
     *
     * @return the description of the bitstream
     */
    public String getDescription()
    {
        return getMetadataFirstValue(MetadataSchema.DC_SCHEMA, "description", null, Item.ANY);
    }

    /**
     * Set the description of the bitstream
     *
     * @param n
     *            the new description of the bitstream
     */
    public void setDescription(String n) {
        setMetadataSingleValue(MetadataSchema.DC_SCHEMA, "description", null, null, n);
    }

    /**
     * Get the checksum of the content of the bitstream, for integrity checking
     *
     * @return the checksum
     */
    public String getChecksum()
    {
        return bRow.getStringColumn("checksum");
    }

    /**
     * Get the algorithm used to calculate the checksum
     *
     * @return the algorithm, e.g. "MD5"
     */
    public String getChecksumAlgorithm()
    {
        return bRow.getStringColumn("checksum_algorithm");
    }

    /**
     * Get the size of the bitstream
     *
     * @return the size in bytes
     */
    public long getSize()
    {
        return bRow.getLongColumn("size_bytes");
    }

    /**
     * Set the user's format description. This implies that the format of the
     * bitstream is uncertain, and the format is set to "unknown."
     *
     * @param desc
     *            the user's description of the format
     * @throws SQLException
     */
    public void setUserFormatDescription(String desc) throws SQLException {
        setFormat(null);
        setMetadataSingleValue(MetadataSchema.DC_SCHEMA, "format", null, null, desc);
    }

    /**
     * Get the user's format description. Returns null if the format is known by
     * the system.
     *
     * @return the user's format description.
     */
    public String getUserFormatDescription()
    {
        return getMetadataFirstValue(MetadataSchema.DC_SCHEMA, "format", null, Item.ANY);
    }

    /**
     * Get the description of the format - either the user's or the description
     * of the format defined by the system.
     *
     * @return a description of the format.
     */
    public String getFormatDescription()
    {
        if (bitstreamFormat.getShortDescription().equals("Unknown"))
        {
            // Get user description if there is one
            String desc = getUserFormatDescription();

            if (desc == null)
            {
                return "Unknown";
            }

            return desc;
        }

        // not null or Unknown
        return bitstreamFormat.getShortDescription();
    }

    /**
     * Get the format of the bitstream
     *
     * @return the format of this bitstream
     */
    public BitstreamFormat getFormat()
    {
        return bitstreamFormat;
    }

    /**
     * Set the format of the bitstream. If the user has supplied a type
     * description, it is cleared. Passing in <code>null</code> sets the type
     * of this bitstream to "unknown".
     *
     * @param f
     *            the format of this bitstream, or <code>null</code> for
     *            unknown
     * @throws SQLException
     */
    public void setFormat(BitstreamFormat f) throws SQLException
    {
        // FIXME: Would be better if this didn't throw an SQLException,
        // but we need to find the unknown format!
        if (f == null)
        {
            // Use "Unknown" format
            bitstreamFormat = BitstreamFormat.findUnknown(ourContext);
        }
        else
        {
            bitstreamFormat = f;
        }

        // Remove user type description
        clearMetadata(MetadataSchema.DC_SCHEMA,"format",null, Item.ANY);

        // Update the ID in the table row
        bRow.setColumn("bitstream_format_id", bitstreamFormat.getID());
        modified = true;
    }

    /**
     * Update the bitstream metadata. Note that the content of the bitstream
     * cannot be changed - for that you need to create a new bitstream.
     *
     * @throws SQLException
     * @throws AuthorizeException
     */
    public void update() throws SQLException, AuthorizeException
    {
        // Check authorisation
        AuthorizeManager.authorizeAction(ourContext, this, Constants.WRITE);

        log.info(LogManager.getHeader(ourContext, "update_bitstream",
                "bitstream_id=" + getID()));

        DatabaseManager.update(ourContext, bRow);

        if (modified)
        {
            ourContext.addEvent(new Event(Event.MODIFY, Constants.BITSTREAM, getID(), null, getIdentifiers(ourContext)));
            modified = false;
        }
        if (modifiedMetadata)
        {
            updateMetadata();
            clearDetails();
        }

    }

    /**
     * Delete the bitstream, including any mappings to bundles
     *
     * @throws SQLException
     */
    void delete() throws SQLException
    {
        boolean oracle = DatabaseManager.isOracle();

        // changed to a check on remove
        // Check authorisation
        //AuthorizeManager.authorizeAction(ourContext, this, Constants.DELETE);
        log.info(LogManager.getHeader(ourContext, "delete_bitstream",
                "bitstream_id=" + getID()));

        ourContext.addEvent(new Event(Event.DELETE, Constants.BITSTREAM, getID(),
                String.valueOf(getSequenceID()), getIdentifiers(ourContext)));

        // Remove from cache
        ourContext.removeCached(this, getID());

        // Remove policies
        AuthorizeManager.removeAllPolicies(ourContext, this);

        // Remove references to primary bitstreams in bundle
        String query = "update bundle set primary_bitstream_id = ";
        query += (oracle ? "''" : "Null") + " where primary_bitstream_id = ? ";
        DatabaseManager.updateQuery(ourContext,
                query, bRow.getIntColumn("bitstream_id"));

        // Remove bitstream itself
        BitstreamStorageManager.delete(ourContext, bRow
                .getIntColumn("bitstream_id"));

        removeMetadataFromDatabase();
    }

    /**
     * Bitstreams are only logically deleted (via a flag in the database).
     * This method allows us to verify is the bitstream is still valid
     *
     * @return true if the bitstream has been deleted
     */
    boolean isDeleted() throws SQLException
    {
        String query = "select count(*) as mycount from Bitstream where deleted = '1' and bitstream_id = ? ";
        TableRowIterator tri = DatabaseManager.query(ourContext, query, bRow.getIntColumn("bitstream_id"));
        long count = 0;

        try
        {
            TableRow r = tri.next();
            count = r.getLongColumn("mycount");
        }
        finally
        {
            // close the TableRowIterator to free up resources
            if (tri != null)
            {
                tri.close();
            }
        }
       
        return count == 1;
    }

    /**
     * Retrieve the contents of the bitstream
     *
     * @return a stream from which the bitstream can be read.
     * @throws IOException
     * @throws SQLException
     * @throws AuthorizeException
     */
    public InputStream retrieve() throws IOException, SQLException,
            AuthorizeException
    {
        // Maybe should return AuthorizeException??
        AuthorizeManager.authorizeAction(ourContext, this, Constants.READ);

        return BitstreamStorageManager.retrieve(ourContext, bRow
                .getIntColumn("bitstream_id"));
    }

    /**
     * Get the bundles this bitstream appears in
     *
     * @return array of <code>Bundle</code> s this bitstream appears in
     * @throws SQLException
     */
    public Bundle[] getBundles() throws SQLException
    {
        // Get the bundle table rows
        TableRowIterator tri = DatabaseManager.queryTable(ourContext, "bundle",
                "SELECT bundle.* FROM bundle, bundle2bitstream WHERE " +
                        "bundle.bundle_id=bundle2bitstream.bundle_id AND " +
                        "bundle2bitstream.bitstream_id= ? ",
                bRow.getIntColumn("bitstream_id"));

        // Build a list of Bundle objects
        List<Bundle> bundles = new ArrayList<Bundle>();
        try
        {
            while (tri.hasNext())
            {
                TableRow r = tri.next();

                // First check the cache
                Bundle fromCache = (Bundle) ourContext.fromCache(Bundle.class, r
                        .getIntColumn("bundle_id"));

                if (fromCache != null)
                {
                    bundles.add(fromCache);
                }
                else
                {
                    bundles.add(new Bundle(ourContext, r));
                }
            }
        }
        finally
        {
            // close the TableRowIterator to free up resources
            if (tri != null)
            {
                tri.close();
            }
        }

        Bundle[] bundleArray = new Bundle[bundles.size()];
        bundleArray = (Bundle[]) bundles.toArray(bundleArray);

        return bundleArray;
    }

    /**
     * return type found in Constants
     *
     * @return int Constants.BITSTREAM
     */
    public int getType()
    {
        return Constants.BITSTREAM;
    }
   
    /**
     * Determine if this bitstream is registered (available elsewhere on
     * filesystem than in assetstore). More about registered items:
     * https://wiki.duraspace.org/display/DSDOC3x/Registering+(not+Importing)+Bitstreams+via+Simple+Archive+Format
     *
     * @return true if the bitstream is registered, false otherwise
     */
    public boolean isRegisteredBitstream() {
        return BitstreamStorageManager
        .isRegisteredBitstream(bRow.getStringColumn("internal_id"));
    }
   
    /**
     * Get the asset store number where this bitstream is stored
     *
     * @return the asset store number of the bitstream
     */
    public int getStoreNumber() {
        return bRow.getIntColumn("store_number");
    }

    /**
     * Get the parent object of a bitstream. The parent can be an item if this
     * is a normal bitstream, or it could be a collection or a community if the
     * bitstream is a logo.
     *
     * @return this bitstream's parent.
     * @throws SQLException
     */   
    public DSpaceObject getParentObject() throws SQLException
    {
        Bundle[] bundles = getBundles();
        if (bundles != null && (bundles.length > 0 && bundles[0] != null))
        {
            // the ADMIN action is not allowed on Bundle object so skip to the item
            Item[] items = bundles[0].getItems();
            if (items != null && items.length > 0)
            {
                return items[0];
            }
            else
            {
                return null;
            }
        }
        else
        {
            // is the bitstream a logo for a community or a collection?
            TableRow qResult = DatabaseManager.querySingle(ourContext,
                       "SELECT collection_id FROM collection " +
                       "WHERE logo_bitstream_id = ?",getID());
            if (qResult != null)
            {
                return Collection.find(ourContext,qResult.getIntColumn("collection_id"));
            }
            else
            {  
                // is the bitstream related to a community?
                qResult = DatabaseManager.querySingle(ourContext,
                        "SELECT community_id FROM community " +
                        "WHERE logo_bitstream_id = ?",getID());
   
                if (qResult != null)
                {
                    return Community.find(ourContext,qResult.getIntColumn("community_id"));
                }
                else
                {
                    return null;
                }
            }                                  
        }
    }

    @Override
    public void updateLastModified()
    {
        //Also fire a modified event since the bitstream HAS been modified
        ourContext.addEvent(new Event(Event.MODIFY, Constants.BITSTREAM, getID(), null, getIdentifiers(ourContext)));
    }
}
TOP

Related Classes of org.dspace.content.Bitstream

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.