org.dataone.proto.trove.mn.rest.v1.ObjectController.java Source code

Java tutorial

Introduction

Here is the source code for org.dataone.proto.trove.mn.rest.v1.ObjectController.java

Source

/*
 * This work was created by participants in the DataONE project, and is
 * jointly copyrighted by participating institutions in DataONE. For
 * more information on DataONE, see our web site at http://dataone.org.
 * 
 * Copyright 2014
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 */
package org.dataone.proto.trove.mn.rest.v1;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.net.URLCodec;
import org.apache.log4j.Logger;
import org.dataone.mimemultipart.MultipartRequestResolver;
import org.dataone.proto.trove.mn.rest.base.AbstractWebController;
import org.dataone.proto.trove.mn.service.v1.SolrIndex;

import org.dataone.service.exceptions.IdentifierNotUnique;
import org.dataone.service.exceptions.InsufficientResources;
import org.dataone.service.exceptions.InvalidRequest;
import org.dataone.service.exceptions.InvalidSystemMetadata;
import org.dataone.service.exceptions.InvalidToken;
import org.dataone.service.exceptions.NotAuthorized;
import org.dataone.service.exceptions.NotFound;
import org.dataone.service.exceptions.NotImplemented;
import org.dataone.service.exceptions.ServiceFailure;
import org.dataone.service.exceptions.UnsupportedType;
import org.dataone.service.mn.tier1.v1.MNRead;
import org.dataone.service.mn.tier3.v1.MNStorage;

import org.dataone.service.types.v1.DescribeResponse;
import org.dataone.service.types.v1.Event;
import org.dataone.service.types.v1.Identifier;
import org.dataone.service.types.v1.LogEntry;
import org.dataone.service.types.v1.ObjectFormatIdentifier;
import org.dataone.service.types.v1.ObjectList;
import org.dataone.service.types.v1.Session;
import org.dataone.service.types.v1.SystemMetadata;
import org.dataone.service.util.TypeMarshaller;

import org.jibx.runtime.JiBXException;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.servlet.ModelAndView;

/**
 * @author waltz
 *
 */
@Controller
public class ObjectController extends AbstractWebController {

    @Autowired
    @Qualifier("mnStorageService")
    MNStorage mnStorage;
    @Autowired
    @Qualifier("mnReadService")
    MNRead mnRead;
    MultipartRequestResolver multipartRequestResolver = new MultipartRequestResolver("/tmp/trove", 1000000000, 0);
    static final int SMALL_BUFF_SIZE = 25000;
    static final int MED_BUFF_SIZE = 50000;
    static final int LARGE_BUFF_SIZE = 100000;
    Logger logger = Logger.getLogger(ObjectController.class.getName());
    private URLCodec urlCodec = new URLCodec();
    @Autowired
    @Qualifier("d1LoggingService")
    SolrIndex d1Log;

    /**
     * return the object requested
     *
     * @param request
     * @param response
     * @param pid
     * @throws InvalidToken
     * @throws ServiceFailure
     * @throws IOException
     * @throws NotAuthorized
     * @throws NotFound
     * @throws NotImplemented
     */
    @RequestMapping(value = "/v1/object/{pid}", method = RequestMethod.GET)
    public void get(HttpServletRequest request, HttpServletResponse response, @PathVariable String pid)
            throws InvalidToken, ServiceFailure, IOException, NotAuthorized, NotFound, NotImplemented,
            InvalidRequest, InsufficientResources {

        debugRequest(request);
        Identifier id = new Identifier();
        try {
            id.setValue(urlCodec.decode(pid, "UTF-8"));
        } catch (DecoderException ex) {
            throw new ServiceFailure("20000", ex.getMessage());
        } catch (UnsupportedEncodingException ex) {
            throw new ServiceFailure("20001", ex.getMessage());
        }
        if (!logRequest(request, Event.READ, id)) {

            throw new ServiceFailure("20001", "unable to log request");
        }
        Session session = new Session();
        if (!this.logRequest(request, Event.READ, id)) {

            throw new ServiceFailure("20001", "unable to log request");
        }
        InputStream in = mnRead.get(id);
        OutputStream out = response.getOutputStream();
        try {

            byte[] buffer = null;
            int filesize = in.available();
            if (filesize < 250000) {
                buffer = new byte[SMALL_BUFF_SIZE];
            } else if (filesize >= 250000 && filesize <= 500000) {
                buffer = new byte[MED_BUFF_SIZE];
            } else {
                buffer = new byte[LARGE_BUFF_SIZE];
            }
            while (true) {
                int amountRead = in.read(buffer);
                if (amountRead == -1) {
                    break;
                }
                out.write(buffer, 0, amountRead);
                out.flush();
            }
        } finally {
            if (in != null) {
                in.close();
            }
            if (out != null) {
                out.flush();
                out.close();
            }

        }
    }

    /**
     * Delete the object requested, and return the pid of object deleted
     *
     * @param request
     * @param response
     * @param pid
     * @throws InvalidToken
     * @throws ServiceFailure
     * @throws IOException
     * @throws NotAuthorized
     * @throws NotFound
     * @throws NotImplemented
     */
    @RequestMapping(value = "/v1/object/{pid}", method = RequestMethod.DELETE)
    public ModelAndView delete(HttpServletRequest request, HttpServletResponse response, @PathVariable String pid)
            throws InvalidToken, ServiceFailure, IOException, NotAuthorized, NotFound, NotImplemented,
            InvalidRequest {

        debugRequest(request);
        Identifier id = new Identifier();
        try {
            id.setValue(urlCodec.decode(pid, "UTF-8"));
        } catch (DecoderException ex) {
            throw new ServiceFailure("20000", ex.getMessage());
        } catch (UnsupportedEncodingException ex) {
            throw new ServiceFailure("20001", ex.getMessage());
        }
        Session session = new Session();
        if (!this.logRequest(request, Event.DELETE, id)) {

            throw new ServiceFailure("20001", "unable to log request");
        }
        Identifier deletedPid = mnStorage.delete(session, id);
        return new ModelAndView("xmlIdentifierViewResolver", "org.dataone.service.types.v1.Identifier", deletedPid);
    }

    /**
     * Describe the object requested, this is no body returned, only HTTP header info
     *
     * @param request
     * @param response
     * @param pid
     * @throws InvalidToken
     * @throws ServiceFailure
     * @throws IOException
     * @throws NotAuthorized
     * @throws NotFound
     * @throws NotImplemented
     */
    @RequestMapping(value = "/v1/object/{pid}", method = RequestMethod.HEAD)
    public void describe(HttpServletRequest request, HttpServletResponse response, @PathVariable String pid)
            throws InvalidToken, ServiceFailure, IOException, NotAuthorized, NotFound, NotImplemented,
            InvalidRequest {

        debugRequest(request);
        Identifier id = new Identifier();
        try {
            id.setValue(urlCodec.decode(pid, "UTF-8"));
        } catch (DecoderException ex) {
            throw new ServiceFailure("20000", ex.getMessage());
        } catch (UnsupportedEncodingException ex) {
            throw new ServiceFailure("20001", ex.getMessage());
        }
        Session session = new Session();
        DescribeResponse describe = mnRead.describe(session, id);
        response.addHeader("Content-Length", describe.getContent_Length().toString());

        /* FROM http://www.ietf.org/rfc/rfc2822.txt
         * Internet Message Format
         * 3.3. Date and Time Specification ..............................14
         *
         *  Date and time occur in several header fields.  This section specifies
         *  the syntax for a full date and time specification.  Though folding
         *  white space is permitted throughout the date-time specification, it
         *  is RECOMMENDED that a single space be used in each place that FWS
         *  appears (whether it is required or optional); some older
         *  implementations may not interpret other occurrences of folding white
         *  space correctly.
         *
         *  date-time       =       [ day-of-week "," ] date FWS time [CFWS]
         *
         *  day-of-week     Logger d1Log = DataONELog.getLogger(MNReadImpl.class.getName());    =       ([FWS] day-name) / obs-day-of-week
         *
         *  day-name        =       "Mon" / "Tue" / "Wed" / "Thu" /
         *                          "Fri" / "Sat" / "Sun"
         *
         *  date            =       day month year
         *
         *  year            =       4*DIGIT / obs-year
         *
         *  month           =       (FWS month-name FWS) / obs-month
         *
         *  month-name      =       "Jan" / "Feb" / "Mar" / "Apr" /
         *                          "May" / "Jun" / "Jul" / "Aug" /
         *                          "Sep" / "Oct" / "Nov" / "Dec"
         *
         *  day             =       ([FWS] 1*2DIGIT) / obs-day
         *
         *  time            =       time-of-day FWS zone
         *
         *  time-of-day     =       hour ":" minute [ ":" second ]
         *
         *  hour            =       2DIGIT / obs-hour
         *
         *  minute          =       2DIGIT / obs-minute
         *
         *  second          =       2DIGIT / obs-second
         *
         *  zone            =       (( "+" / "-" ) 4DIGIT) / obs-zone
         *
         */
        DateTime lastModifiedDate = new DateTime(describe.getLast_Modified(), DateTimeZone.UTC);
        response.addHeader("Last-Modified", lastModifiedDate.toString());
        response.addHeader("DataONE-ObjectFormat", describe.getDataONE_ObjectFormatIdentifier().getValue());
        response.addHeader("DataONE-Checksum",
                describe.getDataONE_Checksum().getAlgorithm() + "," + describe.getDataONE_Checksum().getValue());
        OutputStream out = response.getOutputStream();
        response.flushBuffer();
        out.close();
    }

    /**
     *
     */
    @RequestMapping(value = { "/v1/object", "/v1/object/" }, method = RequestMethod.GET)
    public ModelAndView search(HttpServletRequest request, HttpServletResponse response)
            throws NotAuthorized, InvalidRequest, NotImplemented, ServiceFailure, InvalidToken {
        debugRequest(request);

        Session cert = new Session();
        Integer start = 0;
        Integer count = 1000;
        ObjectFormatIdentifier format = null;
        String startTime = null;
        String endTime = null;
        Boolean replica = null;
        DateTime startDate = null;
        DateTime endDate = null;
        if (request.getParameterMap().keySet().contains("start")) {
            String[] values = (String[]) request.getParameterMap().get("start");
            start = Integer.parseInt(values[0]);
        }
        if (request.getParameterMap().keySet().contains("count")) {
            String[] values = (String[]) request.getParameterMap().get("count");
            count = Integer.parseInt(values[0]);
        }
        if (request.getParameterMap().keySet().contains("replicaStatus")) {
            String[] values = (String[]) request.getParameterMap().get("replicaStatus");
            replica = Boolean.getBoolean(values[0]);

        }
        if (request.getParameterMap().keySet().contains("format")) {
            String[] values = (String[]) request.getParameterMap().get("format");
            format = new ObjectFormatIdentifier();
            format.setValue(values[0]);
        }
        if (request.getParameterMap().keySet().contains("startTime")) {
            String[] values = (String[]) request.getParameterMap().get("startTime");
            startTime = values[0];
        }
        if (request.getParameterMap().keySet().contains("endTime")) {
            String[] values = (String[]) request.getParameterMap().get("endTime");
            endTime = values[0];
        }
        LogEntry logEntry = new LogEntry();
        d1Log.add(logEntry);
        //d1Log.put("search", "start = " + start + " count = " + count + " format = " + (format == null ? "null" : format.getValue()) + " startTime = " + startTime + " endTime = " + endTime);
        logger.info("start = " + start + " count = " + count + " format = "
                + (format == null ? "null" : format.getValue()) + " startTime = " + startTime + " endTime = "
                + endTime);
        if (!((startTime == null) && (endTime == null))) {
            if (startTime == null) {
                startTime = "1900-01-01T00:00:00Z";
            }
            if (endTime == null) {
                endTime = new DateTime().toString();
            }
            startDate = new DateTime(startTime, DateTimeZone.UTC);
            endDate = new DateTime(endTime, DateTimeZone.UTC);
        }
        ObjectList objectList = mnRead.listObjects(cert, (startDate == null ? null : startDate.toDate()),
                (endDate == null ? null : endDate.toDate()), format, replica, start, count);
        return new ModelAndView("xmlObjectListViewResolver", "org.dataone.service.types.v1.ObjectList", objectList);
    }

    /**
     *
     */
    @RequestMapping(value = "/v1/object/{pid}", method = RequestMethod.POST)
    public ModelAndView create(MultipartHttpServletRequest fileRequest, HttpServletResponse response)
            throws InvalidSystemMetadata, InvalidToken, ServiceFailure, NotAuthorized, IdentifierNotUnique,
            UnsupportedType, InsufficientResources, NotImplemented, InvalidRequest {

        Session session = new Session();
        Identifier identifier = new Identifier();
        MultipartFile sytemMetaDataMultipart = null;
        MultipartFile objectMultipart = null;
        SystemMetadata systemMetadata = null;
        Set<String> keys = fileRequest.getFileMap().keySet();
        for (String key : keys) {
            if (key.equalsIgnoreCase("sysmeta")) {
                sytemMetaDataMultipart = fileRequest.getFileMap().get(key);
            } else {
                objectMultipart = fileRequest.getFileMap().get(key);
            }
        }
        if (sytemMetaDataMultipart != null) {
            try {

                systemMetadata = (SystemMetadata) TypeMarshaller.unmarshalTypeFromStream(SystemMetadata.class,
                        sytemMetaDataMultipart.getInputStream());
            } catch (IOException ex) {
                throw new InvalidSystemMetadata("15001", ex.getMessage());
            } catch (JiBXException ex) {
                throw new InvalidSystemMetadata("15002", ex.getMessage());
            } catch (InstantiationException ex) {
                throw new InvalidSystemMetadata("15003", ex.getMessage());
            } catch (IllegalAccessException ex) {
                throw new InvalidSystemMetadata("15004", ex.getMessage());
            }
        } else {
            throw new InvalidSystemMetadata("15005",
                    "System Metadata was not found as Part of Multipart Mime message");
        }
        identifier.setValue(systemMetadata.getIdentifier().getValue());
        InputStream objectInputStream = null;
        if (objectMultipart != null && !(objectMultipart.isEmpty())) {
            try {
                objectInputStream = objectMultipart.getInputStream();
            } catch (IOException ex) {
                throw new InvalidRequest("15006", ex.getMessage());
            }
        } else {
            throw new InvalidRequest("15007", "Object to be created is not attached");
        }
        DateTime dt = new DateTime();
        systemMetadata.setDateUploaded(dt.toDate());
        systemMetadata.setDateSysMetadataModified(dt.toDate());
        if (!this.logRequest(fileRequest, Event.CREATE, identifier)) {

            throw new ServiceFailure("20001", "unable to log request");
        }
        identifier = mnStorage.create(session, identifier, objectInputStream, systemMetadata);

        return new ModelAndView("xmlIdentifierViewResolver", "org.dataone.service.types.v1.Identifier", identifier);
    }

    /**
     * update the object requested
     *
     * @param request
     * @param response
     * @param pid
     * @throws InvalidToken
     * @throws ServiceFailure
     * @throws IOException
     * @throws NotAuthorized
     * @throws NotFound
     * @throws NotImplemented
     */
    @RequestMapping(value = "/v1/object/{pid}", method = RequestMethod.PUT)
    public void update(MultipartHttpServletRequest fileRequest, HttpServletResponse response,
            @PathVariable String pid)
            throws InvalidToken, ServiceFailure, IOException, NotAuthorized, NotFound, NotImplemented,
            InvalidRequest, InsufficientResources, InvalidSystemMetadata, IdentifierNotUnique, UnsupportedType {

        debugRequest(fileRequest);
        Identifier id = new Identifier();
        try {
            id.setValue(urlCodec.decode(pid, "UTF-8"));
        } catch (DecoderException ex) {
            throw new ServiceFailure("20000", ex.getMessage());
        } catch (UnsupportedEncodingException ex) {
            throw new ServiceFailure("20001", ex.getMessage());
        }
        if (!this.logRequest(fileRequest, Event.UPDATE, id)) {

            throw new ServiceFailure("20001", "unable to log request");
        }
        Session session = new Session();
        InputStream objectInputStream = null;
        MultipartFile sytemMetaDataMultipart = null;
        MultipartFile objectMultipart = null;

        SystemMetadata systemMetadata = null;
        Set<String> keys = fileRequest.getFileMap().keySet();
        for (String key : keys) {
            if (key.equalsIgnoreCase("sysmeta")) {
                sytemMetaDataMultipart = fileRequest.getFileMap().get(key);
            } else {
                objectMultipart = fileRequest.getFileMap().get(key);
            }
        }
        if (sytemMetaDataMultipart != null) {
            try {

                systemMetadata = (SystemMetadata) TypeMarshaller.unmarshalTypeFromStream(SystemMetadata.class,
                        sytemMetaDataMultipart.getInputStream());
            } catch (IOException ex) {
                throw new InvalidSystemMetadata("15001", ex.getMessage());
            } catch (JiBXException ex) {
                throw new InvalidSystemMetadata("15002", ex.getMessage());
            } catch (InstantiationException ex) {
                throw new InvalidSystemMetadata("15003", ex.getMessage());
            } catch (IllegalAccessException ex) {
                throw new InvalidSystemMetadata("15004", ex.getMessage());
            }
        } else {
            throw new InvalidSystemMetadata("15005",
                    "System Metadata was not found as Part of Multipart Mime message");
        }
        if (objectMultipart != null && !(objectMultipart.isEmpty())) {
            try {
                objectInputStream = objectMultipart.getInputStream();
            } catch (IOException ex) {
                throw new InvalidRequest("15006", ex.getMessage());
            }
        } else {
            throw new InvalidRequest("15007", "Object to be created is not attached");
        }

        id.setValue(systemMetadata.getIdentifier().getValue());

        DateTime dt = new DateTime();
        systemMetadata.setDateSysMetadataModified(dt.toDate());

        mnStorage.update(id, null, id, null);
        InputStream in = mnRead.get(id);
        OutputStream out = response.getOutputStream();
        try {

            byte[] buffer = null;
            int filesize = in.available();
            if (filesize < 250000) {
                buffer = new byte[SMALL_BUFF_SIZE];
            } else if (filesize >= 250000 && filesize <= 500000) {
                buffer = new byte[MED_BUFF_SIZE];
            } else {
                buffer = new byte[LARGE_BUFF_SIZE];
            }
            while (true) {
                int amountRead = in.read(buffer);
                if (amountRead == -1) {
                    break;
                }
                out.write(buffer, 0, amountRead);
                out.flush();
            }
        } finally {
            if (in != null) {
                in.close();
            }
            if (out != null) {
                out.flush();
                out.close();
            }

        }
    }

}