org.opencb.opencga.server.rest.utils.FileRanges.java Source code

Java tutorial

Introduction

Here is the source code for org.opencb.opencga.server.rest.utils.FileRanges.java

Source

/*
 * Copyright 2015-2016 OpenCB
 *
 * 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.opencb.opencga.server.rest.utils;

import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.apache.commons.lang3.time.StopWatch;
import org.opencb.commons.datastore.core.QueryResult;
import org.opencb.opencga.catalog.managers.AbstractManager;
import org.opencb.opencga.catalog.models.File;
import org.opencb.opencga.catalog.models.acls.permissions.FileAclEntry;
import org.opencb.opencga.core.exception.VersionException;
import org.opencb.opencga.server.rest.OpenCGAWSServer;

import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.*;
import javax.ws.rs.core.*;
import java.io.DataInputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Path("/{version}/utils")
@Produces("application/json")
public class FileRanges extends OpenCGAWSServer {

    public FileRanges(@Context UriInfo uriInfo, @Context HttpServletRequest httpServletRequest)
            throws IOException, VersionException {
        super(uriInfo, httpServletRequest);
    }

    @GET
    @Path("/ranges/{file}")
    @ApiOperation(value = "Fetchs alignment files using HTTP Ranges protocol")
    @Produces("text/plain")
    public Response getRanges(@Context HttpHeaders headers,
            @ApiParam(value = "File id, name or path") @PathParam("file") String fileIdStr,
            @ApiParam(value = "Study [[user@]project:]study where study and project can be either the id or alias") @QueryParam("study") String studyStr) {
        DataInputStream stream = null;
        try {
            AbstractManager.MyResourceId resource = catalogManager.getFileManager().getId(fileIdStr, studyStr,
                    sessionId);
            catalogManager.getAuthorizationManager().checkFilePermission(resource.getResourceId(),
                    resource.getUser(), FileAclEntry.FilePermissions.DOWNLOAD);
            QueryResult<File> queryResult = catalogManager.getFile(resource.getResourceId(), this.queryOptions,
                    sessionId);
            File file = queryResult.getResult().get(0);

            List<String> rangeList = headers.getRequestHeader("range");
            if (rangeList != null) {
                long from;
                long to;
                String[] acceptedRanges = rangeList.get(0).split("=")[1].split("-");
                from = Long.parseLong(acceptedRanges[0]);
                to = Long.parseLong(acceptedRanges[1]);
                int length = (int) (to - from) + 1;
                ByteBuffer buf = ByteBuffer.allocate(length);

                logger.debug("from: {} , to: {}, length:{}", from, to, length);
                StopWatch t = StopWatch.createStarted();

                java.nio.file.Path filePath = Paths.get(file.getUri());
                try (FileChannel fc = (FileChannel.open(filePath, StandardOpenOption.READ))) {
                    fc.position(from);
                    fc.read(buf);
                }

                t.stop();
                logger.debug("Skip {}B and read {}B in {}s", from, length,
                        t.getTime(TimeUnit.MILLISECONDS) / 1000.0);

                return Response.ok(buf.array(), MediaType.APPLICATION_OCTET_STREAM_TYPE)
                        .header("Accept-Ranges", "bytes").header("Access-Control-Allow-Origin", "*")
                        .header("Access-Control-Allow-Headers", "x-requested-with, content-type, range")
                        .header("Access-Control-Allow-Credentials", "true")
                        .header("Access-Control-Allow-Methods", "GET, POST, OPTIONS")
                        .header("Content-Range", "bytes " + from + "-" + to + "/" + file.getSize())
                        .header("Content-length", to - from + 1).status(Response.Status.PARTIAL_CONTENT).build();

            } else {
                stream = catalogManager.downloadFile(resource.getResourceId(), sessionId);
                return createOkResponse(stream, MediaType.APPLICATION_OCTET_STREAM_TYPE, file.getName());
            }
        } catch (Exception e) {
            if (stream != null) {
                try {
                    stream.close();
                } catch (IOException ignore) {
                }
            }
            return createErrorResponse(e);
        }
    }

}