org.dspace.rest.ItemsResource.java Source code

Java tutorial

Introduction

Here is the source code for org.dspace.rest.ItemsResource.java

Source

/**
 * 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
 * <p>
 * http://www.dspace.org/license/
 */
package org.dspace.rest;

import com.atmire.lne.content.ItemServiceBean;
import com.wordnik.swagger.annotations.Api;
import com.wordnik.swagger.annotations.ApiOperation;
import com.wordnik.swagger.annotations.ApiParam;
import org.apache.commons.collections.CollectionUtils;
import org.apache.log4j.Logger;
import org.dspace.authorize.AuthorizeException;
import org.dspace.authorize.AuthorizeManager;
import org.dspace.content.BitstreamFormat;
import org.dspace.content.Bundle;
import org.dspace.content.ItemIterator;
import org.dspace.content.Metadatum;
import org.dspace.content.service.ItemService;
import org.dspace.discovery.SearchServiceException;
import org.dspace.eperson.Group;
import org.dspace.handle.HandleManager;
import org.dspace.rest.common.Bitstream;
import org.dspace.rest.common.Item;
import org.dspace.rest.common.MetadataEntry;
import org.dspace.rest.exceptions.ContextException;
import org.dspace.storage.rdbms.TableRow;
import org.dspace.storage.rdbms.TableRowIterator;
import org.dspace.usage.UsageEvent;
import org.dspace.utils.DSpace;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.*;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;

/**
 * Class which provide all CRUD methods over items.
 *
 * @author Rostislav Novak (Computing and Information Centre, CTU in Prague)
 */
// Every DSpace class used without namespace is from package org.dspace.rest.common.*. Otherwise namespace is defined.
@SuppressWarnings("deprecation")
@Path("/items")
@Api(value = "/items", description = "Retrieve items", position = 3)
public class ItemsResource extends Resource {

    private static final Logger log = Logger.getLogger(ItemsResource.class);

    /**
     * Return item properties without metadata and bitstreams. You can add
     * additional properties by parameter expand.
     *
     * @param itemId  Id of item in DSpace.
     * @param expand  String which define, what additional properties will be in
     *                returned item. Options are separeted by commas and are: "all",
     *                "metadata", "parentCollection", "parentCollectionList",
     *                "parentCommunityList" and "bitstreams".
     * @param headers If you want to access to item under logged user into context.
     *                In headers must be set header "rest-dspace-token" with passed
     *                token from login method.
     * @return If user is allowed to read item, it returns item. Otherwise is
     * thrown WebApplicationException with response status
     * UNAUTHORIZED(401) or NOT_FOUND(404) if was id incorrect.
     * @throws WebApplicationException This exception can be throw by NOT_FOUND(bad id of item),
     *                                 UNAUTHORIZED, SQLException if wasproblem with reading from
     *                                 database and ContextException, if there was problem with
     *                                 creating context of DSpace.
     */
    @GET
    @Path("/{item_id}")
    @ApiOperation(value = "Retrieve a single item by using the internal DSpace item identifier.", response = org.dspace.rest.common.Item.class)
    @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
    public Item getItem(
            @ApiParam(value = "The identifier of the item.", required = true) @PathParam("item_id") Integer itemId,

            @ApiParam(value = "Show additional data for the item.", required = false, allowMultiple = true, allowableValues = "all,metadata,parentCollection,parentCollectionList,parentCommunityList,bitstreams") @QueryParam("expand") String expand,

            @QueryParam("userIP") String user_ip, @QueryParam("userAgent") String user_agent,
            @QueryParam("xforwardedfor") String xforwardedfor, @Context HttpHeaders headers,
            @Context HttpServletRequest request) throws WebApplicationException {

        log.info("Reading item(id=" + itemId + ").");
        org.dspace.core.Context context = null;
        Item item = null;

        try {
            context = createContext();
            org.dspace.content.Item dspaceItem = findItem(context, itemId, org.dspace.core.Constants.READ);

            writeStats(dspaceItem, UsageEvent.Action.VIEW, user_ip, user_agent, xforwardedfor, headers, request,
                    context);

            item = new Item(dspaceItem, expand, context);
            context.complete();
            log.trace("Item(id=" + itemId + ") was successfully read.");

        } catch (SQLException e) {
            processException("Could not read item(id=" + itemId + "), SQLException. Message: " + e, context);
        } catch (ContextException e) {
            processException("Could not read item(id=" + itemId + "), ContextException. Message: " + e.getMessage(),
                    context);
        } finally {
            processFinally(context);
        }

        return item;
    }

    @GET
    @Path("/external-handle/{handle}")
    @ApiOperation(value = "Retrieve an item by using the external item handle.", response = org.dspace.rest.common.Item[].class)
    @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
    public Response getItemByExternalHandle(
            @ApiParam(value = "The identifier of the item.", required = true) @PathParam("handle") String handle,

            @ApiParam(value = "Show additional data for the item.", required = false, allowMultiple = true, allowableValues = "all,metadata,parentCollection,parentCollectionList,parentCommunityList,bitstreams") @QueryParam("expand") String expand,

            @QueryParam("userIP") String user_ip, @QueryParam("userAgent") String user_agent,
            @QueryParam("xforwardedfor") String xforwardedfor, @Context HttpHeaders headers,
            @Context HttpServletRequest request) throws WebApplicationException {

        org.dspace.core.Context context = null;

        try {
            String dspaceHandle = URLDecoder.decode(handle, "UTF-8");
            com.atmire.lne.content.ItemService service = new ItemServiceBean();
            context = createContext();
            List<org.dspace.content.Item> items = service.findItemsByExternalHandle(context, dspaceHandle);

            Response response = null;
            if (CollectionUtils.isEmpty(items)) {
                response = Response.status(Status.NOT_FOUND)
                        .entity("Item with external handle " + handle + " was not found").build();
            } else {
                if (items.size() >= 1) {
                    Item[] returnItems = new Item[items.size()];
                    for (int i = 0; i < items.size(); i++) {
                        returnItems[i] = new Item(items.get(i), expand, context);
                        writeStats(items.get(i), UsageEvent.Action.VIEW, user_ip, user_agent, xforwardedfor,
                                headers, request, context);
                    }

                    if (items.size() > 1) {
                        response = Response.status(Status.CONFLICT).entity(returnItems).build();
                    } else {
                        response = Response.ok(returnItems).build();
                    }

                }
            }

            context.complete();
            return response;

        } catch (ContextException e) {
            processException("Could not read item(handle=" + handle + "), ContextException. Message: " + e,
                    context);
        } catch (SearchServiceException e) {
            processException("Could not read item(handle=" + handle + "), SearchServiceException. Message: " + e,
                    context);
        } catch (SQLException e) {
            processException("Could not read item(handle=" + handle + "), SQLException. Message: " + e, context);
        } catch (UnsupportedEncodingException e) {
            processException(
                    "Could not read item(handle=" + handle + "), UnsupportedEncodingException. Message: " + e,
                    context);
        } finally {
            processFinally(context);
        }
        return null;
    }

    /**
     * It returns an array of items in DSpace. You can define how many items in
     * list will be and from which index will start. Items in list are sorted by
     * handle, not by id.
     *
     * @param limit   How many items in array will be. Default value is 100.
     * @param offset  On which index will array start. Default value is 0.
     * @param headers If you want to access to item under logged user into context.
     *                In headers must be set header "rest-dspace-token" with passed
     *                token from login method.
     * @return Return array of items, on which has logged user into context
     * permission.
     * @throws WebApplicationException It can be thrown by SQLException, when was problem with
     *                                 reading items from database or ContextException, when was
     *                                 problem with creating context of DSpace.
     */
    @GET
    @ApiOperation(value = "Retrieve all items from the repository.", response = org.dspace.rest.common.Item[].class)
    @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
    public Response getItems(
            @ApiParam(value = "Show additional data for the item.", required = false, allowMultiple = true, allowableValues = "all,metadata,parentCollection,parentCollectionList,parentCommunityList,bitstreams") @QueryParam("expand") String expand,

            @ApiParam(value = "The maximum amount of items shown.", required = false) @QueryParam("limit") @DefaultValue("100") Integer limit,

            @ApiParam(value = "The amount of items to skip.", required = false) @QueryParam("offset") @DefaultValue("0") Integer offset,

            @QueryParam("userIP") String user_ip, @QueryParam("userAgent") String user_agent,
            @QueryParam("xforwardedfor") String xforwardedfor, @Context HttpHeaders headers,
            @Context HttpServletRequest request) throws WebApplicationException {

        log.info("Reading items.(offset=" + offset + ",limit=" + limit + ").");

        try {
            SearchResource searchResource = new SearchResource();
            return searchResource.searchItems("*:*", expand, limit, offset, "dc.date.accessioned", null, "asc",
                    user_ip, user_agent, xforwardedfor, headers, request);
        } catch (Exception ex) {
            log.error(ex.getMessage());
            return Response.status(Response.Status.BAD_REQUEST).entity(ex.getMessage()).build();
        }

    }

    /**
     * Returns item metadata in list.
     *
     * @param itemId  Id of item in DSpace.
     * @param headers If you want to access to item under logged user into context.
     *                In headers must be set header "rest-dspace-token" with passed
     *                token from login method.
     * @return Return list of metadata fields if was everything ok. Otherwise it
     * throw WebApplication exception with response code NOT_FOUND(404)
     * or UNAUTHORIZED(401).
     * @throws WebApplicationException It can be thrown by two exceptions: SQLException if was
     *                                 problem wtih reading item from database and ContextException,
     *                                 if was problem with creating context of DSpace. And can be
     *                                 thrown by NOT_FOUND and UNAUTHORIZED too.
     */
    @GET
    @Path("/{item_id}/metadata")
    @ApiOperation(value = "Retrieve a list of metadata for an item by using the internal DSpace item identifier.", response = org.dspace.rest.common.MetadataEntry[].class)
    @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
    public MetadataEntry[] getItemMetadata(
            @ApiParam(value = "The identifier of the item.", required = true) @PathParam("item_id") Integer itemId,

            @QueryParam("userIP") String user_ip, @QueryParam("userAgent") String user_agent,
            @QueryParam("xforwardedfor") String xforwardedfor, @Context HttpHeaders headers,
            @Context HttpServletRequest request) throws WebApplicationException {

        log.info("Reading item(id=" + itemId + ") metadata.");
        org.dspace.core.Context context = null;
        List<MetadataEntry> metadata = null;

        try {
            context = createContext();
            org.dspace.content.Item dspaceItem = findItem(context, itemId, org.dspace.core.Constants.READ);

            writeStats(dspaceItem, UsageEvent.Action.VIEW, user_ip, user_agent, xforwardedfor, headers, request,
                    context);

            metadata = new Item(dspaceItem, "metadata", context).getMetadata();
            context.complete();
        } catch (SQLException e) {
            processException("Could not read item(id=" + itemId + "), SQLException. Message: " + e, context);
        } catch (ContextException e) {
            processException("Could not read item(id=" + itemId + "), ContextException. Message: " + e.getMessage(),
                    context);
        } finally {
            processFinally(context);
        }

        log.trace("Item(id=" + itemId + ") metadata were successfully read.");
        return metadata.toArray(new MetadataEntry[0]);
    }

    /**
     * Return array of bitstreams in item. It can be pagged.
     *
     * @param itemId  Id of item in DSpace.
     * @param limit   How many items will be in array.
     * @param offset  On which index will start array.
     * @param headers If you want to access to item under logged user into context.
     *                In headers must be set header "rest-dspace-token" with passed
     *                token from login method.
     * @return Return pagged array of bitstreams in item.
     * @throws WebApplicationException It can be throw by NOT_FOUND, UNAUTHORIZED, SQLException if
     *                                 was problem with reading from database and ContextException
     *                                 if was problem with creating context of DSpace.
     */
    @GET
    @Path("/{item_id}/bitstreams")
    @ApiOperation(value = "Retrieve a list of bitstreams for an item by using the internal DSpace item identifier.", response = org.dspace.rest.common.Bitstream[].class)
    @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
    public Bitstream[] getItemBitstreams(
            @ApiParam(value = "The identifier of the item.", required = true) @PathParam("item_id") Integer itemId,

            @ApiParam(value = "The maximum amount of bitstreams shown.", required = false) @QueryParam("limit") @DefaultValue("20") Integer limit,

            @ApiParam(value = "The amount of bitstreams to skip.", required = false) @QueryParam("offset") @DefaultValue("0") Integer offset,

            @QueryParam("userIP") String user_ip, @QueryParam("userAgent") String user_agent,
            @QueryParam("xforwardedfor") String xforwardedfor, @Context HttpHeaders headers,
            @Context HttpServletRequest request) throws WebApplicationException {

        log.info("Reading item(id=" + itemId + ") bitstreams.(offset=" + offset + ",limit=" + limit + ")");
        org.dspace.core.Context context = null;
        List<Bitstream> bitstreams = null;
        try {
            context = createContext();
            org.dspace.content.Item dspaceItem = findItem(context, itemId, org.dspace.core.Constants.READ);

            writeStats(dspaceItem, UsageEvent.Action.VIEW, user_ip, user_agent, xforwardedfor, headers, request,
                    context);

            List<Bitstream> itemBitstreams = new Item(dspaceItem, "bitstreams", context).getBitstreams();

            if ((offset + limit) > (itemBitstreams.size() - offset)) {
                bitstreams = itemBitstreams.subList(offset, itemBitstreams.size());
            } else {
                bitstreams = itemBitstreams.subList(offset, offset + limit);
            }
            context.complete();
        } catch (SQLException e) {
            processException("Could not read item(id=" + itemId + ") bitstreams, SQLExcpetion. Message: " + e,
                    context);
        } catch (ContextException e) {
            processException("Could not read item(id=" + itemId + ") bitstreams, ContextException. Message: "
                    + e.getMessage(), context);
        } finally {
            processFinally(context);
        }

        log.trace("Item(id=" + itemId + ") bitstreams were successfully read.");
        return bitstreams.toArray(new Bitstream[0]);
    }

    /**
     * Adding metadata fields to item. If metadata key is in item, it will be
     * added, NOT REPLACED!
     *
     * @param itemId   Id of item in DSpace.
     * @param metadata List of metadata fields, which will be added into item.
     * @param headers  If you want to access to item under logged user into context.
     *                 In headers must be set header "rest-dspace-token" with passed
     *                 token from login method.
     * @return It returns status code OK(200) if all was ok. UNAUTHORIZED(401)
     * if user is not allowed to write to item. NOT_FOUND(404) if id of
     * item is incorrect.
     * @throws WebApplicationException It is throw by these exceptions: SQLException, if was problem
     *                                 with reading from database or writing to database.
     *                                 AuthorizeException, if was problem with authorization to item
     *                                 fields. ContextException, if was problem with creating
     *                                 context of DSpace.
     */
    @POST
    @Path("/{item_id}/metadata")
    @ApiOperation(value = "Add metadata to an item by using the internal DSpace item identifier.", response = org.dspace.rest.common.Bitstream.class)
    @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
    public Response addItemMetadata(
            @ApiParam(value = "The identifier of the item.", required = true) @PathParam("item_id") Integer itemId,

            @ApiParam(value = "List of metadata objects", required = true) List<MetadataEntry> metadata,

            @QueryParam("userIP") String user_ip, @QueryParam("userAgent") String user_agent,
            @QueryParam("xforwardedfor") String xforwardedfor, @Context HttpHeaders headers,
            @Context HttpServletRequest request) throws WebApplicationException {

        log.info("Adding metadata to item(id=" + itemId + ").");
        org.dspace.core.Context context = null;

        try {
            context = createContext();
            org.dspace.content.Item dspaceItem = findItem(context, itemId, org.dspace.core.Constants.WRITE);

            writeStats(dspaceItem, UsageEvent.Action.UPDATE, user_ip, user_agent, xforwardedfor, headers, request,
                    context);

            for (MetadataEntry entry : metadata) {
                // TODO Test with Java split
                String data[] = mySplit(entry.getKey()); // Done by my split, because of java split was not function.
                if ((data.length >= 2) && (data.length <= 3)) {
                    dspaceItem.addMetadata(data[0], data[1], data[2], entry.getLanguage(), entry.getValue());
                }
            }
            dspaceItem.update();
            context.complete();

        } catch (SQLException e) {
            processException("Could not write metadata to item(id=" + itemId + "), SQLException. Message: " + e,
                    context);
        } catch (AuthorizeException e) {
            processException(
                    "Could not write metadata to item(id=" + itemId + "), AuthorizeException. Message: " + e,
                    context);
        } catch (ContextException e) {
            processException("Could not write metadata to item(id=" + itemId + "), ContextException. Message: "
                    + e.getMessage(), context);
        } finally {
            processFinally(context);
        }

        log.info("Metadata to item(id=" + itemId + ") were successfully added.");
        return Response.status(Status.OK).build();
    }

    /**
     * Create bitstream in item.
     *
     * @param itemId      Id of item in DSpace.
     * @param inputStream Data of bitstream in inputStream.
     * @param headers     If you want to access to item under logged user into context.
     *                    In headers must be set header "rest-dspace-token" with passed
     *                    token from login method.
     * @return Returns bitstream with status code OK(200). If id of item is
     * invalid , it returns status code NOT_FOUND(404). If user is not
     * allowed to write to item, UNAUTHORIZED(401).
     * @throws WebApplicationException It is thrown by these exceptions: SQLException, when was
     *                                 problem with reading/writing from/to database.
     *                                 AuthorizeException, when was problem with authorization to
     *                                 item and add bitstream to item. IOException, when was problem
     *                                 with creating file or reading from inpustream.
     *                                 ContextException. When was problem with creating context of
     *                                 DSpace.
     */
    // TODO Add option to add bitstream by URI.(for very big files)
    @POST
    @Path("/{item_id}/bitstreams")
    @ApiOperation(value = "Create a bitstream in an item by using the internal DSpace item identifier.", response = org.dspace.rest.common.Bitstream.class)
    public Bitstream addItemBitstream(
            @ApiParam(value = "The identifier of the item.", required = true) @PathParam("item_id") Integer itemId,

            @ApiParam(value = "InputStream object", required = true) InputStream inputStream,

            @ApiParam(value = "The name of the bitstream.", required = true) @QueryParam("name") String name,

            @ApiParam(value = "The description of the bitstream.", required = false) @QueryParam("description") String description,

            @ApiParam(value = "The group id of the policy group.", required = false) @QueryParam("groupId") Integer groupId,

            @ApiParam(value = "The year of the policy start date.", required = false) @QueryParam("year") Integer year,

            @ApiParam(value = "The month of the policy start date.", required = false) @QueryParam("month") Integer month,

            @ApiParam(value = "The day of the policy start date.", required = false) @QueryParam("day") Integer day,

            @QueryParam("userIP") String user_ip, @QueryParam("userAgent") String user_agent,
            @QueryParam("xforwardedfor") String xforwardedfor, @Context HttpHeaders headers,
            @Context HttpServletRequest request) throws WebApplicationException {

        log.info("Adding bitstream to item(id=" + itemId + ").");
        org.dspace.core.Context context = null;
        Bitstream bitstream = null;

        try {
            context = createContext();
            org.dspace.content.Item dspaceItem = findItem(context, itemId, org.dspace.core.Constants.WRITE);

            writeStats(dspaceItem, UsageEvent.Action.UPDATE, user_ip, user_agent, xforwardedfor, headers, request,
                    context);

            // Is better to add bitstream to ORIGINAL bundle or to item own?
            log.trace("Creating bitstream in item.");
            Bundle bundle = null;
            org.dspace.content.Bitstream dspaceBitstream = null;
            Bundle[] bundles = dspaceItem.getBundles("ORIGINAL");
            if (bundles != null && bundles.length != 0) {
                bundle = bundles[0]; // There should be only one bundle ORIGINAL.
            }
            if (bundle == null) {
                log.trace("Creating bundle in item.");
                dspaceBitstream = dspaceItem.createSingleBitstream(inputStream);
            } else {
                log.trace("Getting bundle from item.");
                dspaceBitstream = bundle.createBitstream(inputStream);
            }

            dspaceBitstream.setSource("DSpace Rest api");

            // Set bitstream name and description
            if (name != null) {
                if (BitstreamResource.getMimeType(name) == null) {
                    dspaceBitstream.setFormat(BitstreamFormat.findUnknown(context));
                } else {
                    dspaceBitstream.setFormat(
                            BitstreamFormat.findByMIMEType(context, BitstreamResource.getMimeType(name)));
                }
                dspaceBitstream.setName(name);
            }
            if (description != null) {
                dspaceBitstream.setDescription(description);
            }

            dspaceBitstream.update();

            // Create policy for bitstream
            if (groupId != null) {
                bundles = dspaceBitstream.getBundles();
                for (Bundle dspaceBundle : bundles) {
                    List<org.dspace.authorize.ResourcePolicy> bitstreamsPolicies = dspaceBundle
                            .getBitstreamPolicies();

                    // Remove default bitstream policies
                    List<org.dspace.authorize.ResourcePolicy> policiesToRemove = new ArrayList<org.dspace.authorize.ResourcePolicy>();
                    for (org.dspace.authorize.ResourcePolicy policy : bitstreamsPolicies) {
                        if (policy.getResourceID() == dspaceBitstream.getID()) {
                            policiesToRemove.add(policy);
                        }
                    }
                    for (org.dspace.authorize.ResourcePolicy policy : policiesToRemove) {
                        bitstreamsPolicies.remove(policy);
                    }

                    org.dspace.authorize.ResourcePolicy dspacePolicy = org.dspace.authorize.ResourcePolicy
                            .create(context);
                    dspacePolicy.setAction(org.dspace.core.Constants.READ);
                    dspacePolicy.setGroup(Group.find(context, groupId));
                    dspacePolicy.setResourceID(dspaceBitstream.getID());
                    dspacePolicy.setResource(dspaceBitstream);
                    dspacePolicy.setResourceType(org.dspace.core.Constants.BITSTREAM);
                    if ((year != null) || (month != null) || (day != null)) {
                        Date date = new Date();
                        if (year != null) {
                            date.setYear(year - 1900);
                        }
                        if (month != null) {
                            date.setMonth(month - 1);
                        }
                        if (day != null) {
                            date.setDate(day);
                        }
                        date.setHours(0);
                        date.setMinutes(0);
                        date.setSeconds(0);
                        dspacePolicy.setStartDate(date);
                    }

                    dspacePolicy.update();
                    dspaceBitstream.updateLastModified();
                }
            }

            dspaceBitstream = org.dspace.content.Bitstream.find(context, dspaceBitstream.getID());
            bitstream = new Bitstream(dspaceBitstream, "");

            context.complete();

        } catch (SQLException e) {
            processException("Could not create bitstream in item(id=" + itemId + "), SQLException. Message: " + e,
                    context);
        } catch (AuthorizeException e) {
            processException(
                    "Could not create bitstream in item(id=" + itemId + "), AuthorizeException. Message: " + e,
                    context);
        } catch (IOException e) {
            processException("Could not create bitstream in item(id=" + itemId + "), IOException Message: " + e,
                    context);
        } catch (ContextException e) {
            processException("Could not create bitstream in item(id=" + itemId + "), ContextException Message: "
                    + e.getMessage(), context);
        } finally {
            processFinally(context);
        }

        log.info("Bitstream(id=" + bitstream.getId() + ") was successfully added into item(id=" + itemId + ").");
        return bitstream;
    }

    /**
     * Replace all metadata in item with new passed metadata.
     *
     * @param itemId   Id of item in DSpace.
     * @param metadata List of metadata fields, which will replace old metadata in
     *                 item.
     * @param headers  If you want to access to item under logged user into context.
     *                 In headers must be set header "rest-dspace-token" with passed
     *                 token from login method.
     * @return It returns status code: OK(200). NOT_FOUND(404) if item was not
     * found, UNAUTHORIZED(401) if user is not allowed to write to item.
     * @throws WebApplicationException It is thrown by: SQLException, when was problem with database
     *                                 reading or writting, AuthorizeException when was problem with
     *                                 authorization to item and metadata fields. And
     *                                 ContextException, when was problem with creating context of
     *                                 DSpace.
     */
    @PUT
    @Path("/{item_id}/metadata")
    @ApiOperation(value = "Replace the metadata of an item by using the internal DSpace item identifier.", response = Response.class)
    @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
    public Response updateItemMetadata(
            @ApiParam(value = "The identifier of the item.", required = true) @PathParam("item_id") Integer itemId,

            @ApiParam(value = "Array of metadata objects", required = true) MetadataEntry[] metadata,

            @QueryParam("userIP") String user_ip, @QueryParam("userAgent") String user_agent,
            @QueryParam("xforwardedfor") String xforwardedfor, @Context HttpHeaders headers,
            @Context HttpServletRequest request) throws WebApplicationException {

        log.info("Updating metadata in item(id=" + itemId + ").");
        org.dspace.core.Context context = null;

        try {
            context = createContext();
            org.dspace.content.Item dspaceItem = findItem(context, itemId, org.dspace.core.Constants.WRITE);

            writeStats(dspaceItem, UsageEvent.Action.UPDATE, user_ip, user_agent, xforwardedfor, headers, request,
                    context);

            log.trace("Deleting original metadata from item.");
            for (MetadataEntry entry : metadata) {
                String data[] = mySplit(entry.getKey());
                if ((data.length >= 2) && (data.length <= 3)) {
                    dspaceItem.clearMetadata(data[0], data[1], data[2], org.dspace.content.Item.ANY);
                }
            }

            log.trace("Adding new metadata to item.");
            for (MetadataEntry entry : metadata) {
                String data[] = mySplit(entry.getKey());
                if ((data.length >= 2) && (data.length <= 3)) {
                    dspaceItem.addMetadata(data[0], data[1], data[2], entry.getLanguage(), entry.getValue());
                }
            }

            dspaceItem.update();
            context.complete();

        } catch (SQLException e) {
            processException("Could not update metadata in item(id=" + itemId + "), SQLException. Message: " + e,
                    context);
        } catch (AuthorizeException e) {
            processException(
                    "Could not update metadata in item(id=" + itemId + "), AuthorizeException. Message: " + e,
                    context);
        } catch (ContextException e) {
            processException("Could not update metadata in item(id=" + itemId + "), ContextException. Message: "
                    + e.getMessage(), context);
        } finally {
            processFinally(context);
        }

        log.info("Metadata of item(id=" + itemId + ") were successfully updated.");
        return Response.status(Status.OK).build();
    }

    /**
     * Delete item from DSpace. It delete bitstreams only from item bundle.
     *
     * @param itemId  Id of item which will be deleted.
     * @param headers If you want to access to item under logged user into context.
     *                In headers must be set header "rest-dspace-token" with passed
     *                token from login method.
     * @return It returns status code: OK(200). NOT_FOUND(404) if item was not
     * found, UNAUTHORIZED(401) if user is not allowed to delete item
     * metadata.
     * @throws WebApplicationException It can be thrown by: SQLException, when was problem with
     *                                 database reading. AuthorizeException, when was problem with
     *                                 authorization to item.(read and delete) IOException, when was
     *                                 problem with deleting bitstream file. ContextException, when
     *                                 was problem with creating context of DSpace.
     */
    @DELETE
    @Path("/{item_id}")
    @ApiOperation(value = "Delete and item by using the internal DSpace item identifier.", response = Response.class)
    public Response deleteItem(
            @ApiParam(value = "The identifier of the item.", required = true) @PathParam("item_id") Integer itemId,

            @QueryParam("userIP") String user_ip, @QueryParam("userAgent") String user_agent,
            @QueryParam("xforwardedfor") String xforwardedfor, @Context HttpHeaders headers,
            @Context HttpServletRequest request) throws WebApplicationException {

        log.info("Deleting item(id=" + itemId + ").");
        org.dspace.core.Context context = null;

        try {
            context = createContext();
            org.dspace.content.Item dspaceItem = findItem(context, itemId, org.dspace.core.Constants.DELETE);

            writeStats(dspaceItem, UsageEvent.Action.REMOVE, user_ip, user_agent, xforwardedfor, headers, request,
                    context);

            log.trace("Deleting item.");
            org.dspace.content.Collection collection = org.dspace.content.Collection.find(context,
                    dspaceItem.getCollections()[0].getID());
            collection.removeItem(dspaceItem);
            context.complete();

        } catch (SQLException e) {
            processException("Could not delete item(id=" + itemId + "), SQLException. Message: " + e, context);
        } catch (AuthorizeException e) {
            processException("Could not delete item(id=" + itemId + "), AuthorizeException. Message: " + e,
                    context);
            throw new WebApplicationException(Status.INTERNAL_SERVER_ERROR);
        } catch (IOException e) {
            processException("Could not delete item(id=" + itemId + "), IOException. Message: " + e, context);
        } catch (ContextException e) {
            processException(
                    "Could not delete item(id=" + itemId + "), ContextException. Message: " + e.getMessage(),
                    context);
        } finally {
            processFinally(context);
        }

        log.info("Item(id=" + itemId + ") was successfully deleted.");
        return Response.status(Status.OK).build();
    }

    /**
     * Delete all item metadata.
     *
     * @param itemId  Id of item in DSpace.
     * @param headers If you want to access to item under logged user into context.
     *                In headers must be set header "rest-dspace-token" with passed
     *                token from login method.
     * @return It returns status code: OK(200). NOT_FOUND(404) if item was not
     * found, UNAUTHORIZED(401) if user is not allowed to delete item
     * metadata.
     * @throws WebApplicationException It is thrown by three exceptions. SQLException, when was
     *                                 problem with reading item from database or editting metadata
     *                                 fields. AuthorizeException, when was problem with
     *                                 authorization to item. And ContextException, when was problem
     *                                 with creating context of DSpace.
     */
    @DELETE
    @Path("/{item_id}/metadata")
    @ApiOperation(value = "Delete all metadata of an item by using the internal DSpace item identifier.", response = Response.class)
    public Response deleteItemMetadata(
            @ApiParam(value = "The identifier of the item.", required = true) @PathParam("item_id") Integer itemId,

            @QueryParam("userIP") String user_ip, @QueryParam("userAgent") String user_agent,
            @QueryParam("xforwardedfor") String xforwardedfor, @Context HttpHeaders headers,
            @Context HttpServletRequest request) throws WebApplicationException {

        log.info("Deleting metadata in item(id=" + itemId + ").");
        org.dspace.core.Context context = null;

        try {
            context = createContext();
            org.dspace.content.Item dspaceItem = findItem(context, itemId, org.dspace.core.Constants.WRITE);

            writeStats(dspaceItem, UsageEvent.Action.UPDATE, user_ip, user_agent, xforwardedfor, headers, request,
                    context);

            log.trace("Deleting metadata.");
            // TODO Rewrite without deprecated object. Leave there only generated metadata.
            Metadatum[] value = dspaceItem.getMetadata("dc", "date", "accessioned", org.dspace.content.Item.ANY);
            Metadatum[] value2 = dspaceItem.getMetadata("dc", "date", "available", org.dspace.content.Item.ANY);
            Metadatum[] value3 = dspaceItem.getMetadata("dc", "identifier", "uri", org.dspace.content.Item.ANY);
            Metadatum[] value4 = dspaceItem.getMetadata("dc", "description", "provenance",
                    org.dspace.content.Item.ANY);

            dspaceItem.clearMetadata(org.dspace.content.Item.ANY, org.dspace.content.Item.ANY,
                    org.dspace.content.Item.ANY, org.dspace.content.Item.ANY);
            dspaceItem.update();

            // Add there generated metadata
            dspaceItem.addMetadata(value[0].schema, value[0].element, value[0].qualifier, null, value[0].value);
            dspaceItem.addMetadata(value2[0].schema, value2[0].element, value2[0].qualifier, null, value2[0].value);
            dspaceItem.addMetadata(value3[0].schema, value3[0].element, value3[0].qualifier, null, value3[0].value);
            dspaceItem.addMetadata(value4[0].schema, value4[0].element, value4[0].qualifier, null, value4[0].value);

            dspaceItem.update();
            context.complete();

        } catch (SQLException e) {
            processException("Could not delete item(id=" + itemId + "), SQLException. Message: " + e, context);
        } catch (AuthorizeException e) {
            processException("Could not delete item(id=" + itemId + "), AuthorizeExcpetion. Message: " + e,
                    context);
        } catch (ContextException e) {
            processException(
                    "Could not delete item(id=" + itemId + "), ContextException. Message:" + e.getMessage(),
                    context);
        } finally {
            processFinally(context);
        }

        log.info("Item(id=" + itemId + ") metadata were successfully deleted.");
        return Response.status(Status.OK).build();
    }

    /**
     * Delete bitstream from item bundle.
     *
     * @param itemId      Id of item in DSpace.
     * @param headers     If you want to access to item under logged user into context.
     *                    In headers must be set header "rest-dspace-token" with passed
     *                    token from login method.
     * @param bitstreamId Id of bitstream, which will be deleted from bundle.
     * @return Return status code OK(200) if is all ok. NOT_FOUND(404) if item
     * or bitstream was not found. UNAUTHORIZED(401) if user is not
     * allowed to delete bitstream.
     * @throws WebApplicationException It is thrown, when: Was problem with edditting database,
     *                                 SQLException. Or problem with authorization to item, bundle
     *                                 or bitstream, AuthorizeException. When was problem with
     *                                 deleting file IOException. Or problem with creating context
     *                                 of DSpace, ContextException.
     */
    @DELETE
    @Path("/{item_id}/bitstreams/{bitstream_id}")
    @ApiOperation(value = "Delete a bitstream of an item by using the internal DSpace item and bitstream identifiers.", response = Response.class)
    public Response deleteItemBitstream(
            @ApiParam(value = "The identifier of the item.", required = true) @PathParam("item_id") Integer itemId,

            @ApiParam(value = "The identifier of the bitstream.", required = true) @PathParam("bitstream_id") Integer bitstreamId,

            @QueryParam("userIP") String user_ip, @QueryParam("userAgent") String user_agent,
            @QueryParam("xforwardedfor") String xforwardedfor, @Context HttpHeaders headers,
            @Context HttpServletRequest request) throws WebApplicationException {

        log.info("Deleting bitstream in item(id=" + itemId + ").");
        org.dspace.core.Context context = null;

        try {
            context = createContext();
            org.dspace.content.Item item = findItem(context, itemId, org.dspace.core.Constants.WRITE);

            org.dspace.content.Bitstream bitstream = org.dspace.content.Bitstream.find(context, bitstreamId);
            if (bitstream == null) {
                context.abort();
                log.warn("Bitstream(id=" + bitstreamId + ") was not found.");
                return Response.status(Status.NOT_FOUND).build();
            } else if (!AuthorizeManager.authorizeActionBoolean(context, bitstream,
                    org.dspace.core.Constants.DELETE)) {
                context.abort();
                log.error("User(" + getUser(headers).getEmail() + ") is not allowed to delete bitstream(id="
                        + bitstreamId + ").");
                return Response.status(Status.UNAUTHORIZED).build();
            }

            writeStats(item, UsageEvent.Action.UPDATE, user_ip, user_agent, xforwardedfor, headers, request,
                    context);
            writeStats(bitstream, UsageEvent.Action.REMOVE, user_ip, user_agent, xforwardedfor, headers, request,
                    context);

            log.trace("Deleting bitstream...");
            for (Bundle bundle : item.getBundles()) {
                for (org.dspace.content.Bitstream bit : bundle.getBitstreams()) {
                    if (bit == bitstream) {
                        bundle.removeBitstream(bitstream);
                    }
                }
            }

            context.complete();

        } catch (SQLException e) {
            processException("Could not delete bitstream(id=" + bitstreamId + "), SQLException. Message: " + e,
                    context);
        } catch (AuthorizeException e) {
            processException(
                    "Could not delete bitstream(id=" + bitstreamId + "), AuthorizeException. Message: " + e,
                    context);
        } catch (IOException e) {
            processException("Could not delete bitstream(id=" + bitstreamId + "), IOException. Message: " + e,
                    context);
        } catch (ContextException e) {
            processException("Could not delete bitstream(id=" + bitstreamId + "), ContextException. Message:"
                    + e.getMessage(), context);
        } finally {
            processFinally(context);
        }

        log.info("Bitstream(id=" + bitstreamId + ") from item(id=" + itemId + ") was successfuly deleted .");
        return Response.status(Status.OK).build();
    }

    /**
     * Find items by one metadada field.
     *
     * @param metadataEntry Metadata field to search by.
     * @param scheme        Scheme of metadata(key).
     * @param value         Value of metadata field.
     * @param headers       If you want to access the item as the user logged into context,
     *                      header "rest-dspace-token" must be set to token value retrieved
     *                      from the login method.
     * @return Return array of found items.
     * @throws WebApplicationException Can be thrown: SQLException - problem with
     *                                 database reading. AuthorizeException - problem with
     *                                 authorization to item. IOException - problem with
     *                                 reading from metadata field. ContextException -
     *                                 problem with creating DSpace context.
     */
    @POST
    @Path("/find-by-metadata-field")
    @ApiOperation(value = "Find items by a metadata field.", response = org.dspace.rest.common.Item[].class)
    @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
    public Item[] findItemsByMetadataField(
            @ApiParam(value = "metadataEntry object", required = true) MetadataEntry metadataEntry,

            @ApiParam(value = "Show additional data for the item.", required = false, allowMultiple = true, allowableValues = "all,metadata,parentCollection,parentCollectionList,parentCommunityList,bitstreams") @QueryParam("expand") String expand,

            @QueryParam("userIP") String user_ip, @QueryParam("userAgent") String user_agent,
            @QueryParam("xforwardedfor") String xforwardedfor, @Context HttpHeaders headers,
            @Context HttpServletRequest request) throws WebApplicationException {

        log.info("Looking for item with metadata(key=" + metadataEntry.getKey() + ",value="
                + metadataEntry.getValue() + ", language=" + metadataEntry.getLanguage() + ").");
        org.dspace.core.Context context = null;

        List<Item> items = new ArrayList<Item>();
        String[] metadata = mySplit(metadataEntry.getKey());

        try {
            context = createContext();

            // TODO Repair, it ends by error:
            // "java.sql.SQLSyntaxErrorException: ORA-00932: inconsistent datatypes: expected - got CLOB"
            /*
             * if (metadata.length == 3){
             *     itemIterator =  org.dspace.content.Item.findByMetadataField(context, metadata[0],
             *     metadata[1], metadata[2], value);
             * } else if (metadata.length == 2){
             *     itemIterator = org.dspace.content.Item.findByMetadataField(context, metadata[0],
             *     metadata[1], null, value);
             * } else {
             *     context.abort();
             *     log.error("Finding failed, bad metadata key.");
             *     throw new WebApplicationException(Response.Status.NOT_FOUND);
             * }
             *
             * if (itemIterator.hasNext()) {
             * item = new Item(itemIterator.next(), "", context);
             * }
             */

            // Must used own style.
            if ((metadata.length < 2) || (metadata.length > 3)) {
                context.abort();
                log.error("Finding failed, bad metadata key.");
                throw new WebApplicationException(Status.NOT_FOUND);
            }

            List<Object> parameterList = new LinkedList<>();
            String sql = "SELECT RESOURCE_ID, TEXT_VALUE, TEXT_LANG, SHORT_ID, ELEMENT, QUALIFIER "
                    + "FROM METADATAVALUE "
                    + "JOIN METADATAFIELDREGISTRY ON METADATAVALUE.METADATA_FIELD_ID = METADATAFIELDREGISTRY.METADATA_FIELD_ID "
                    + "JOIN METADATASCHEMAREGISTRY ON METADATAFIELDREGISTRY.METADATA_SCHEMA_ID = METADATASCHEMAREGISTRY.METADATA_SCHEMA_ID "
                    + "WHERE " + "SHORT_ID= ? AND " + "ELEMENT= ? AND ";
            parameterList.add(metadata[0]);
            parameterList.add(metadata[1]);
            if (metadata.length > 3) {
                sql += "QUALIFIER= ? AND ";
                parameterList.add(metadata[2]);
            }
            if (org.dspace.storage.rdbms.DatabaseManager.isOracle()) {
                sql += "dbms_lob.compare(TEXT_VALUE, ? ) = 0 AND ";
                parameterList.add(metadataEntry.getValue());
            } else {
                sql += "TEXT_VALUE= ? AND ";
                parameterList.add(metadataEntry.getValue());
            }
            if (metadataEntry.getLanguage() != null) {
                sql += "TEXT_LANG= ? ";
                parameterList.add(metadataEntry.getLanguage());
            } else {
                sql += "TEXT_LANG is null";
            }

            Object[] parameters = parameterList.toArray();
            TableRowIterator iterator = org.dspace.storage.rdbms.DatabaseManager.query(context, sql, parameters);
            while (iterator.hasNext()) {
                TableRow row = iterator.next();
                org.dspace.content.Item dspaceItem = this.findItem(context, row.getIntColumn("RESOURCE_ID"),
                        org.dspace.core.Constants.READ);
                Item item = new Item(dspaceItem, "", context);
                writeStats(dspaceItem, UsageEvent.Action.VIEW, user_ip, user_agent, xforwardedfor, headers, request,
                        context);
                items.add(item);
            }

            context.complete();

        } catch (SQLException e) {
            processException("Something went wrong while finding item. SQLException, Message: " + e, context);
        } catch (ContextException e) {
            processException("Context error:" + e.getMessage(), context);
        } finally {
            processFinally(context);
        }

        if (items.size() == 0) {
            log.info("Items not found.");
        } else {
            log.info("Items were found.");
        }

        return items.toArray(new Item[0]);
    }

    /**
     * Find item from DSpace database. It is encapsulation of method
     * org.dspace.content.Item.find with checking if item exist and if user
     * logged into context has permission to do passed action.
     *
     * @param context Context of actual logged user.
     * @param id      Id of item in DSpace.
     * @param action  Constant from org.dspace.core.Constants.
     * @return It returns DSpace item.
     * @throws WebApplicationException Is thrown when item with passed id is not exists and if user
     *                                 has no permission to do passed action.
     */
    private org.dspace.content.Item findItem(org.dspace.core.Context context, int id, int action)
            throws WebApplicationException {
        org.dspace.content.Item item = null;
        try {
            item = org.dspace.content.Item.find(context, id);

            if (item == null) {
                context.abort();
                log.warn("Item(id=" + id + ") was not found!");
                throw new WebApplicationException(Status.NOT_FOUND);
            } else if (!AuthorizeManager.authorizeActionBoolean(context, item, action)) {
                context.abort();
                if (context.getCurrentUser() != null) {
                    log.error("User(" + context.getCurrentUser().getEmail() + ") has not permission to "
                            + getActionString(action) + " item!");
                } else {
                    log.error("User(anonymous) has not permission to " + getActionString(action) + " item!");
                }
                throw new WebApplicationException(Status.UNAUTHORIZED);
            }

        } catch (SQLException e) {
            processException("Something get wrong while finding item(id=" + id + "). SQLException, Message: " + e,
                    context);
        }
        return item;
    }
}