Search in sources :

Example 1 with MakeDataCountEntry

use of edu.harvard.iq.dataverse.makedatacount.MakeDataCountLoggingServiceBean.MakeDataCountEntry in project dataverse by IQSS.

the class MakeDataCountLoggingServiceBeanTest method testDefaultConstructor.

// Testing that when you init with no objects everything defaults to "-"
@Test
public void testDefaultConstructor() {
    MakeDataCountEntry entry = new MakeDataCountEntry();
    assertThat(entry.getEventTime(), is("-"));
    assertThat(entry.getClientIp(), is("-"));
    assertThat(entry.getSessionCookieId(), is("-"));
    assertThat(entry.getUserCookieId(), is("-"));
    assertThat(entry.getUserId(), is("-"));
    assertThat(entry.getRequestUrl(), is("-"));
    assertThat(entry.getIdentifier(), is("-"));
    assertThat(entry.getFilename(), is("-"));
    assertThat(entry.getSize(), is("-"));
    assertThat(entry.getUserAgent(), is("-"));
    assertThat(entry.getTitle(), is("-"));
    assertThat(entry.getPublisher(), is("-"));
    assertThat(entry.getPublisherId(), is("-"));
    assertThat(entry.getAuthors(), is("-"));
    assertThat(entry.getVersion(), is("-"));
    assertThat(entry.getOtherId(), is("-"));
    assertThat(entry.getTargetUrl(), is("-"));
    assertThat(entry.getPublicationDate(), is("-"));
    assertThat(entry.toString().split("\t").length, is(19));
}
Also used : MakeDataCountEntry(edu.harvard.iq.dataverse.makedatacount.MakeDataCountLoggingServiceBean.MakeDataCountEntry) Test(org.junit.Test)

Example 2 with MakeDataCountEntry

use of edu.harvard.iq.dataverse.makedatacount.MakeDataCountLoggingServiceBean.MakeDataCountEntry in project dataverse by IQSS.

the class MakeDataCountLoggingServiceBeanTest method testMainAndFileConstructor.

@Test
public void testMainAndFileConstructor() {
    MockDataverseRequestServiceBean dvReqServ = new MockDataverseRequestServiceBean();
    AuthenticatedUser au = MocksFactory.makeAuthenticatedUser("First", "Last");
    DataverseRequest req = new DataverseRequest(au, IpAddress.valueOf("0.0.0.0"));
    dvReqServ.setDataverseRequest(req);
    MockDatasetVersion dvVersion = new MockDatasetVersion();
    Dataset dataset = new Dataset();
    dataset.setAuthority("Authority");
    dataset.setProtocol("Protocol");
    dataset.setIdentifier("Identifier");
    GlobalId id = new GlobalId(dataset);
    dataset.setGlobalId(id);
    dvVersion.setDataset(dataset);
    dvVersion.setAuthorsStr("OneAuthor;TwoAuthor");
    dvVersion.setTitle("Title");
    dvVersion.setVersionNumber(1L);
    dvVersion.setReleaseTime(new Date());
    DataFile df = new DataFile();
    df.setStorageIdentifier("StorageId");
    df.setFilesize(1L);
    MakeDataCountEntry entry = new MakeDataCountEntry(null, dvReqServ, dvVersion, df);
    // Instead of going through the absurdity of mocking FacesContext and ExternalContext and Request,
    // we will just pass null and init the values pulled from that manually
    entry.setRequestUrl("RequestUrl");
    entry.setTargetUrl("TargetUrl");
    entry.setUserAgent("UserAgent");
    entry.setSessionCookieId("SeshCookieId");
    // lastly setting attributes we don't actually use currently in our logging/constructors, just in case
    entry.setUserCookieId("UserCookId");
    entry.setOtherId("OtherId");
    // And test. "-" is the default
    assertThat(entry.getEventTime(), is(not("-")));
    assertThat(entry.getClientIp(), is(not("-")));
    assertThat(entry.getSessionCookieId(), is(not("-")));
    assertThat(entry.getUserCookieId(), is(not("-")));
    assertThat(entry.getUserId(), is(not("-")));
    assertThat(entry.getRequestUrl(), is(not("-")));
    assertThat(entry.getIdentifier(), is(not("-")));
    assertThat(entry.getFilename(), is(not("-")));
    assertThat(entry.getSize(), is(not("-")));
    assertThat(entry.getUserAgent(), is(not("-")));
    assertThat(entry.getTitle(), is(not("-")));
    assertThat(entry.getPublisher(), is(not("-")));
    assertThat(entry.getPublisherId(), is(not("-")));
    assertThat(entry.getAuthors(), is(not("-")));
    assertThat(entry.getVersion(), is(not("-")));
    assertThat(entry.getOtherId(), is(not("-")));
    assertThat(entry.getTargetUrl(), is(not("-")));
    assertThat(entry.getPublicationDate(), is(not("-")));
    // 19 entries are required for the Counter Processor logging
    assertThat(entry.toString().split("\t").length, is(19));
}
Also used : DataverseRequest(edu.harvard.iq.dataverse.engine.command.DataverseRequest) DataFile(edu.harvard.iq.dataverse.DataFile) MakeDataCountEntry(edu.harvard.iq.dataverse.makedatacount.MakeDataCountLoggingServiceBean.MakeDataCountEntry) Dataset(edu.harvard.iq.dataverse.Dataset) AuthenticatedUser(edu.harvard.iq.dataverse.authorization.users.AuthenticatedUser) Date(java.util.Date) GlobalId(edu.harvard.iq.dataverse.GlobalId) Test(org.junit.Test)

Example 3 with MakeDataCountEntry

use of edu.harvard.iq.dataverse.makedatacount.MakeDataCountLoggingServiceBean.MakeDataCountEntry in project dataverse by IQSS.

the class Datasets method getDataset.

@GET
@Path("{id}")
public Response getDataset(@PathParam("id") String id, @Context UriInfo uriInfo, @Context HttpHeaders headers, @Context HttpServletResponse response) {
    return response(req -> {
        final Dataset retrieved = execCommand(new GetDatasetCommand(req, findDatasetOrDie(id)));
        final DatasetVersion latest = execCommand(new GetLatestAccessibleDatasetVersionCommand(req, retrieved));
        final JsonObjectBuilder jsonbuilder = json(retrieved);
        // Report MDC if this is a released version (could be draft if user has access, or user may not have access at all and is not getting metadata beyond the minimum)
        if ((latest != null) && latest.isReleased()) {
            MakeDataCountLoggingServiceBean.MakeDataCountEntry entry = new MakeDataCountEntry(uriInfo, headers, dvRequestService, retrieved);
            mdcLogService.logEntry(entry);
        }
        return ok(jsonbuilder.add("latestVersion", (latest != null) ? json(latest) : null));
    });
}
Also used : GetLatestAccessibleDatasetVersionCommand(edu.harvard.iq.dataverse.engine.command.impl.GetLatestAccessibleDatasetVersionCommand) MakeDataCountEntry(edu.harvard.iq.dataverse.makedatacount.MakeDataCountLoggingServiceBean.MakeDataCountEntry) MakeDataCountEntry(edu.harvard.iq.dataverse.makedatacount.MakeDataCountLoggingServiceBean.MakeDataCountEntry) GetDatasetCommand(edu.harvard.iq.dataverse.engine.command.impl.GetDatasetCommand) MakeDataCountLoggingServiceBean(edu.harvard.iq.dataverse.makedatacount.MakeDataCountLoggingServiceBean) Path(javax.ws.rs.Path) GET(javax.ws.rs.GET)

Example 4 with MakeDataCountEntry

use of edu.harvard.iq.dataverse.makedatacount.MakeDataCountLoggingServiceBean.MakeDataCountEntry in project dataverse by IQSS.

the class Datasets method exportDataset.

// TODO:
// This API call should, ideally, call findUserOrDie() and the GetDatasetCommand
// to obtain the dataset that we are trying to export - which would handle
// Auth in the process... For now, Auth isn't necessary - since export ONLY
// WORKS on published datasets, which are open to the world. -- L.A. 4.5
@GET
@Path("/export")
@Produces({ "application/xml", "application/json", "application/html" })
public Response exportDataset(@QueryParam("persistentId") String persistentId, @QueryParam("exporter") String exporter, @Context UriInfo uriInfo, @Context HttpHeaders headers, @Context HttpServletResponse response) {
    try {
        Dataset dataset = datasetService.findByGlobalId(persistentId);
        if (dataset == null) {
            return error(Response.Status.NOT_FOUND, "A dataset with the persistentId " + persistentId + " could not be found.");
        }
        ExportService instance = ExportService.getInstance();
        InputStream is = instance.getExport(dataset, exporter);
        String mediaType = instance.getMediaType(exporter);
        // Export is only possible for released (non-draft) dataset versions so we can log without checking to see if this is a request for a draft
        MakeDataCountLoggingServiceBean.MakeDataCountEntry entry = new MakeDataCountEntry(uriInfo, headers, dvRequestService, dataset);
        mdcLogService.logEntry(entry);
        return Response.ok().entity(is).type(mediaType).build();
    } catch (Exception wr) {
        logger.warning(wr.getMessage());
        return error(Response.Status.FORBIDDEN, "Export Failed");
    }
}
Also used : MakeDataCountEntry(edu.harvard.iq.dataverse.makedatacount.MakeDataCountLoggingServiceBean.MakeDataCountEntry) MakeDataCountEntry(edu.harvard.iq.dataverse.makedatacount.MakeDataCountLoggingServiceBean.MakeDataCountEntry) InputStream(java.io.InputStream) ExportService(edu.harvard.iq.dataverse.export.ExportService) MakeDataCountLoggingServiceBean(edu.harvard.iq.dataverse.makedatacount.MakeDataCountLoggingServiceBean) DataFileTagException(edu.harvard.iq.dataverse.datasetutility.DataFileTagException) SolrServerException(org.apache.solr.client.solrj.SolrServerException) JsonParseException(edu.harvard.iq.dataverse.util.json.JsonParseException) CommandException(edu.harvard.iq.dataverse.engine.command.exception.CommandException) EJBException(javax.ejb.EJBException) JsonParsingException(javax.json.stream.JsonParsingException) NotAcceptableException(javax.ws.rs.NotAcceptableException) IOException(java.io.IOException) BadRequestException(javax.ws.rs.BadRequestException) UnforcedCommandException(edu.harvard.iq.dataverse.engine.command.exception.UnforcedCommandException) NoFilesException(edu.harvard.iq.dataverse.datasetutility.NoFilesException) Path(javax.ws.rs.Path) Produces(javax.ws.rs.Produces) GET(javax.ws.rs.GET)

Example 5 with MakeDataCountEntry

use of edu.harvard.iq.dataverse.makedatacount.MakeDataCountLoggingServiceBean.MakeDataCountEntry in project dataverse by IQSS.

the class DownloadInstanceWriter method writeTo.

@Override
public void writeTo(DownloadInstance di, Class<?> clazz, Type type, Annotation[] annotation, MediaType mediaType, MultivaluedMap<String, Object> httpHeaders, OutputStream outstream) throws IOException, WebApplicationException {
    if (di.getDownloadInfo() != null && di.getDownloadInfo().getDataFile() != null) {
        DataAccessRequest daReq = new DataAccessRequest();
        DataFile dataFile = di.getDownloadInfo().getDataFile();
        StorageIO<DataFile> storageIO = DataAccess.getStorageIO(dataFile, daReq);
        if (storageIO != null) {
            try {
                storageIO.open();
            } catch (IOException ioex) {
                // throw new WebApplicationException(Response.Status.SERVICE_UNAVAILABLE);
                logger.log(Level.INFO, "Datafile {0}: Failed to locate and/or open physical file. Error message: {1}", new Object[] { dataFile.getId(), ioex.getLocalizedMessage() });
                throw new NotFoundException("Datafile " + dataFile.getId() + ": Failed to locate and/or open physical file.");
            }
            // by a redirect to remote storage (only supported on S3, as of 5.4):
            if (storageIO instanceof S3AccessIO && ((S3AccessIO) storageIO).downloadRedirectEnabled()) {
                // Even if the above is true, there are a few cases where a
                // redirect is not applicable.
                // For example, for a tabular file, we can redirect a request
                // for a saved original; but CANNOT if it is a column subsetting
                // request (must be streamed in real time locally); or a format
                // conversion that hasn't been cached and saved on S3 yet.
                boolean redirectSupported = true;
                String auxiliaryTag = null;
                String auxiliaryType = null;
                String auxiliaryFileName = null;
                if ("imageThumb".equals(di.getConversionParam())) {
                    // Can redirect - but only if already generated and cached.
                    int requestedSize = 0;
                    if (!"".equals(di.getConversionParamValue())) {
                        try {
                            requestedSize = new Integer(di.getConversionParamValue());
                        } catch (java.lang.NumberFormatException ex) {
                        // it's ok, the default size will be used.
                        }
                    }
                    auxiliaryTag = ImageThumbConverter.THUMBNAIL_SUFFIX + (requestedSize > 0 ? requestedSize : ImageThumbConverter.DEFAULT_THUMBNAIL_SIZE);
                    if (isAuxiliaryObjectCached(storageIO, auxiliaryTag)) {
                        auxiliaryType = ImageThumbConverter.THUMBNAIL_MIME_TYPE;
                        String fileName = storageIO.getFileName();
                        if (fileName != null) {
                            auxiliaryFileName = fileName.replaceAll("\\.[^\\.]*$", ImageThumbConverter.THUMBNAIL_FILE_EXTENSION);
                        }
                    } else {
                        redirectSupported = false;
                    }
                } else if (di.getAuxiliaryFile() != null) {
                    // We should support redirects to auxiliary files too.
                    auxiliaryTag = di.getAuxiliaryFile().getFormatTag();
                    String auxVersion = di.getAuxiliaryFile().getFormatVersion();
                    if (auxVersion != null) {
                        auxiliaryTag = auxiliaryTag + "_" + auxVersion;
                    }
                    if (isAuxiliaryObjectCached(storageIO, auxiliaryTag)) {
                        String fileExtension = getFileExtension(di.getAuxiliaryFile());
                        auxiliaryFileName = storageIO.getFileName() + "." + auxiliaryTag + fileExtension;
                        auxiliaryType = di.getAuxiliaryFile().getContentType();
                    } else {
                        redirectSupported = false;
                    }
                } else if (dataFile.isTabularData()) {
                    if (di.getConversionParam() != null) {
                        if (di.getConversionParam().equals("format")) {
                            if ("original".equals(di.getConversionParamValue())) {
                                auxiliaryTag = StoredOriginalFile.SAVED_ORIGINAL_FILENAME_EXTENSION;
                                auxiliaryType = dataFile.getOriginalFileFormat();
                                auxiliaryFileName = dataFile.getOriginalFileName();
                            } else {
                                // format conversions - can redirect, but only if
                                // it has been cached already.
                                auxiliaryTag = di.getConversionParamValue();
                                if (isAuxiliaryObjectCached(storageIO, auxiliaryTag)) {
                                    auxiliaryType = di.getServiceFormatType(di.getConversionParam(), auxiliaryTag);
                                    auxiliaryFileName = FileUtil.replaceExtension(storageIO.getFileName(), auxiliaryTag);
                                } else {
                                    redirectSupported = false;
                                }
                            }
                        } else if (!di.getConversionParam().equals("noVarHeader")) {
                            // This is a subset request - can't do.
                            redirectSupported = false;
                        }
                    } else {
                        redirectSupported = false;
                    }
                }
                if (redirectSupported) {
                    // definitely close the (potentially still open) input stream,
                    // since we are not going to use it. The S3 documentation in particular
                    // emphasizes that it is very important not to leave these
                    // lying around un-closed, since they are going to fill
                    // up the S3 connection pool!
                    storageIO.closeInputStream();
                    // [attempt to] redirect:
                    String redirect_url_str;
                    try {
                        redirect_url_str = ((S3AccessIO) storageIO).generateTemporaryS3Url(auxiliaryTag, auxiliaryType, auxiliaryFileName);
                    } catch (IOException ioex) {
                        redirect_url_str = null;
                    }
                    if (redirect_url_str == null) {
                        throw new ServiceUnavailableException();
                    }
                    logger.fine("Data Access API: direct S3 url: " + redirect_url_str);
                    URI redirect_uri;
                    try {
                        redirect_uri = new URI(redirect_url_str);
                    } catch (URISyntaxException ex) {
                        logger.info("Data Access API: failed to create S3 redirect url (" + redirect_url_str + ")");
                        redirect_uri = null;
                    }
                    if (redirect_uri != null) {
                        // increment the download count, if necessary:
                        if (di.getGbr() != null && !(isThumbnailDownload(di) || isPreprocessedMetadataDownload(di))) {
                            try {
                                logger.fine("writing guestbook response, for an S3 download redirect.");
                                Command<?> cmd = new CreateGuestbookResponseCommand(di.getDataverseRequestService().getDataverseRequest(), di.getGbr(), di.getGbr().getDataFile().getOwner());
                                di.getCommand().submit(cmd);
                                MakeDataCountEntry entry = new MakeDataCountEntry(di.getRequestUriInfo(), di.getRequestHttpHeaders(), di.getDataverseRequestService(), di.getGbr().getDataFile());
                                mdcLogService.logEntry(entry);
                            } catch (CommandException e) {
                            }
                        }
                        // finally, issue the redirect:
                        Response response = Response.seeOther(redirect_uri).build();
                        logger.fine("Issuing redirect to the file location on S3.");
                        throw new RedirectionException(response);
                    }
                    throw new ServiceUnavailableException();
                }
            }
            if (di.getConversionParam() != null) {
                if (di.getConversionParam().equals("imageThumb") && !dataFile.isHarvested()) {
                    if ("".equals(di.getConversionParamValue())) {
                        storageIO = ImageThumbConverter.getImageThumbnailAsInputStream(storageIO, ImageThumbConverter.DEFAULT_THUMBNAIL_SIZE);
                    } else {
                        try {
                            int size = new Integer(di.getConversionParamValue());
                            if (size > 0) {
                                storageIO = ImageThumbConverter.getImageThumbnailAsInputStream(storageIO, size);
                            }
                        } catch (java.lang.NumberFormatException ex) {
                            storageIO = ImageThumbConverter.getImageThumbnailAsInputStream(storageIO, ImageThumbConverter.DEFAULT_THUMBNAIL_SIZE);
                        }
                        // and, since we now have tabular data files that can
                        // have thumbnail previews... obviously, we don't want to
                        // add the variable header to the image stream!
                        storageIO.setNoVarHeader(Boolean.TRUE);
                        storageIO.setVarHeader(null);
                    }
                } else if (dataFile.isTabularData()) {
                    logger.fine("request for tabular data download;");
                    if (di.getConversionParam().equals("noVarHeader")) {
                        logger.fine("tabular data with no var header requested");
                        storageIO.setNoVarHeader(Boolean.TRUE);
                        storageIO.setVarHeader(null);
                    } else if (di.getConversionParam().equals("format")) {
                        if ("original".equals(di.getConversionParamValue())) {
                            logger.fine("stored original of an ingested file requested");
                            storageIO = StoredOriginalFile.retreive(storageIO);
                        } else {
                            // Other format conversions:
                            logger.fine("format conversion on a tabular file requested (" + di.getConversionParamValue() + ")");
                            String requestedMimeType = di.getServiceFormatType(di.getConversionParam(), di.getConversionParamValue());
                            if (requestedMimeType == null) {
                                // default mime type, in case real type is unknown;
                                // (this shouldn't happen in real life - but just in case):
                                requestedMimeType = "application/octet-stream";
                            }
                            storageIO = DataConverter.performFormatConversion(dataFile, storageIO, di.getConversionParamValue(), requestedMimeType);
                        }
                    } else if (di.getConversionParam().equals("subset")) {
                        logger.fine("processing subset request.");
                        // instead.
                        if (di.getExtraArguments() != null && di.getExtraArguments().size() > 0) {
                            logger.fine("processing extra arguments list of length " + di.getExtraArguments().size());
                            List<Integer> variablePositionIndex = new ArrayList<>();
                            String subsetVariableHeader = null;
                            for (int i = 0; i < di.getExtraArguments().size(); i++) {
                                DataVariable variable = (DataVariable) di.getExtraArguments().get(i);
                                if (variable != null) {
                                    if (variable.getDataTable().getDataFile().getId().equals(dataFile.getId())) {
                                        logger.fine("adding variable id " + variable.getId() + " to the list.");
                                        variablePositionIndex.add(variable.getFileOrder());
                                        if (subsetVariableHeader == null) {
                                            subsetVariableHeader = variable.getName();
                                        } else {
                                            subsetVariableHeader = subsetVariableHeader.concat("\t");
                                            subsetVariableHeader = subsetVariableHeader.concat(variable.getName());
                                        }
                                    } else {
                                        logger.warning("variable does not belong to this data file.");
                                    }
                                }
                            }
                            if (variablePositionIndex.size() > 0) {
                                try {
                                    File tempSubsetFile = File.createTempFile("tempSubsetFile", ".tmp");
                                    TabularSubsetGenerator tabularSubsetGenerator = new TabularSubsetGenerator();
                                    tabularSubsetGenerator.subsetFile(storageIO.getInputStream(), tempSubsetFile.getAbsolutePath(), variablePositionIndex, dataFile.getDataTable().getCaseQuantity(), "\t");
                                    if (tempSubsetFile.exists()) {
                                        FileInputStream subsetStream = new FileInputStream(tempSubsetFile);
                                        long subsetSize = tempSubsetFile.length();
                                        InputStreamIO subsetStreamIO = new InputStreamIO(subsetStream, subsetSize);
                                        logger.fine("successfully created subset output stream.");
                                        subsetVariableHeader = subsetVariableHeader.concat("\n");
                                        subsetStreamIO.setVarHeader(subsetVariableHeader);
                                        String tabularFileName = storageIO.getFileName();
                                        if (tabularFileName != null && tabularFileName.endsWith(".tab")) {
                                            tabularFileName = tabularFileName.replaceAll("\\.tab$", "-subset.tab");
                                        } else if (tabularFileName != null && !"".equals(tabularFileName)) {
                                            tabularFileName = tabularFileName.concat("-subset.tab");
                                        } else {
                                            tabularFileName = "subset.tab";
                                        }
                                        subsetStreamIO.setFileName(tabularFileName);
                                        subsetStreamIO.setMimeType(storageIO.getMimeType());
                                        storageIO = subsetStreamIO;
                                    } else {
                                        storageIO = null;
                                    }
                                } catch (IOException ioex) {
                                    storageIO = null;
                                }
                            }
                        } else {
                            logger.fine("empty list of extra arguments.");
                        }
                    }
                }
                if (storageIO == null) {
                    // (similarly to what the Access API returns when a thumbnail is requested on a text file, etc.)
                    throw new NotFoundException("datafile access error: requested optional service (image scaling, format conversion, etc.) could not be performed on this datafile.");
                }
            } else if (di.getAuxiliaryFile() != null) {
                // Make sure to close the InputStream for the main datafile:
                storageIO.closeInputStream();
                String auxTag = di.getAuxiliaryFile().getFormatTag();
                String auxVersion = di.getAuxiliaryFile().getFormatVersion();
                if (auxVersion != null) {
                    auxTag = auxTag + "_" + auxVersion;
                }
                long auxFileSize = di.getAuxiliaryFile().getFileSize();
                InputStreamIO auxStreamIO = new InputStreamIO(storageIO.getAuxFileAsInputStream(auxTag), auxFileSize);
                String fileExtension = getFileExtension(di.getAuxiliaryFile());
                auxStreamIO.setFileName(storageIO.getFileName() + "." + auxTag + fileExtension);
                auxStreamIO.setMimeType(di.getAuxiliaryFile().getContentType());
                storageIO = auxStreamIO;
            }
            try (InputStream instream = storageIO.getInputStream()) {
                if (instream != null) {
                    // headers:
                    String fileName = storageIO.getFileName();
                    String mimeType = storageIO.getMimeType();
                    // Provide both the "Content-disposition" and "Content-Type" headers,
                    // to satisfy the widest selection of browsers out there.
                    // Encode the filename as UTF-8, then deal with spaces. "encode" changes
                    // a space to + so we change it back to a space (%20).
                    String finalFileName = URLEncoder.encode(fileName, "UTF-8").replaceAll("\\+", "%20");
                    httpHeaders.add("Content-disposition", "attachment; filename=\"" + finalFileName + "\"");
                    httpHeaders.add("Content-Type", mimeType + "; name=\"" + finalFileName + "\"");
                    long contentSize;
                    // User may have requested a rangeHeader of bytes.
                    // Ranges are only supported when the size of the content
                    // stream is known (i.e., it's not a dynamically generated
                    // stream.
                    List<Range> ranges = new ArrayList<>();
                    String rangeHeader = null;
                    HttpHeaders headers = di.getRequestHttpHeaders();
                    if (headers != null) {
                        rangeHeader = headers.getHeaderString("Range");
                    }
                    long offset = 0;
                    long leftToRead = -1L;
                    if ((contentSize = getContentSize(storageIO)) > 0) {
                        try {
                            ranges = getRanges(rangeHeader, contentSize);
                        } catch (Exception ex) {
                            logger.fine("Exception caught processing Range header: " + ex.getLocalizedMessage());
                            throw new ClientErrorException("Error due to Range header: " + ex.getLocalizedMessage(), Response.Status.REQUESTED_RANGE_NOT_SATISFIABLE);
                        }
                        if (ranges.isEmpty()) {
                            logger.fine("Content size (retrieved from the AccessObject): " + contentSize);
                            httpHeaders.add("Content-Length", contentSize);
                        } else {
                            // For now we only support a single rangeHeader.
                            long rangeContentSize = ranges.get(0).getLength();
                            logger.fine("Content size (Range header in use): " + rangeContentSize);
                            httpHeaders.add("Content-Length", rangeContentSize);
                            offset = ranges.get(0).getStart();
                            leftToRead = rangeContentSize;
                        }
                    } else {
                        // We do NOT want to support rangeHeader requests on such streams:
                        if (rangeHeader != null) {
                            throw new NotFoundException("Range headers are not supported on dynamically-generated content, such as tabular subsetting.");
                        }
                    }
                    // (the httpHeaders map must be modified *before* writing any
                    // data in the output stream!)
                    int bufsize;
                    byte[] bffr = new byte[4 * 8192];
                    // subsettable files:
                    if (storageIO.getVarHeader() != null) {
                        logger.fine("storageIO.getVarHeader().getBytes().length: " + storageIO.getVarHeader().getBytes().length);
                        if (storageIO.getVarHeader().getBytes().length > 0) {
                            // will be written.
                            if (ranges.isEmpty()) {
                                logger.fine("writing the entire variable header");
                                outstream.write(storageIO.getVarHeader().getBytes());
                            } else {
                                // Range requested. Since the output stream of a
                                // tabular file is made up of the varHeader and the body of
                                // the physical file, we should assume that the requested
                                // rangeHeader may span any portion of the combined stream.
                                // Thus we may or may not have to write the header, or a
                                // portion thereof.
                                int headerLength = storageIO.getVarHeader().getBytes().length;
                                if (offset >= headerLength) {
                                    // We can skip the entire header.
                                    // All we need to do is adjust the byte offset
                                    // in the physical file; the number of bytes
                                    // left to write stays unchanged, since we haven't
                                    // written anything.
                                    logger.fine("Skipping the variable header completely.");
                                    offset -= headerLength;
                                } else {
                                    // some bytes left to write from the main physical file.
                                    if (offset + leftToRead <= headerLength) {
                                        // This is a more straightforward case - we just need to
                                        // write a portion of the header, and then we are done!
                                        logger.fine("Writing this many bytes of the variable header line: " + leftToRead);
                                        outstream.write(Arrays.copyOfRange(storageIO.getVarHeader().getBytes(), (int) offset, (int) offset + (int) leftToRead));
                                        // set "left to read" to zero, indicating that we are done:
                                        leftToRead = 0;
                                    } else {
                                        // write the requested portion of the header:
                                        logger.fine("Writing this many bytes of the variable header line: " + (headerLength - offset));
                                        outstream.write(Arrays.copyOfRange(storageIO.getVarHeader().getBytes(), (int) offset, headerLength));
                                        // and adjust the file offset and remaining number of bytes accordingly:
                                        leftToRead -= (headerLength - offset);
                                        offset = 0;
                                    }
                                }
                            }
                        }
                    }
                    // Dynamic streams, etc. Normal operation. No leftToRead.
                    if (ranges.isEmpty()) {
                        logger.fine("Normal, non-range request of file id " + dataFile.getId());
                        while ((bufsize = instream.read(bffr)) != -1) {
                            outstream.write(bffr, 0, bufsize);
                        }
                    } else if (leftToRead > 0) {
                        // This is a rangeHeader request, and we still have bytes to read
                        // (for a tabular file, we may have already written enough
                        // bytes from the variable header!)
                        storageIO.setOffset(offset);
                        // Thinking about it, we could just do instream.skip(offset)
                        // here... But I would like to have this offset functionality
                        // in StorageIO, for any future cases where we may not
                        // be able to do that on the stream directly (?) -- L.A.
                        logger.fine("Range request of file id " + dataFile.getId());
                        // For now we only support a single rangeHeader.
                        while ((bufsize = instream.read(bffr)) != -1) {
                            if ((leftToRead -= bufsize) > 0) {
                                // Just do a normal write. Potentially lots to go. Don't break.
                                outstream.write(bffr, 0, bufsize);
                            } else {
                                // Get those last bytes or bytes equal to bufsize. Last one. Then break.
                                outstream.write(bffr, 0, (int) leftToRead + bufsize);
                                break;
                            }
                        }
                    }
                    logger.fine("di conversion param: " + di.getConversionParam() + ", value: " + di.getConversionParamValue());
                    // so these should not produce guestbook entries:
                    if (di.getGbr() != null && !(isThumbnailDownload(di) || isPreprocessedMetadataDownload(di))) {
                        try {
                            logger.fine("writing guestbook response.");
                            Command<?> cmd = new CreateGuestbookResponseCommand(di.getDataverseRequestService().getDataverseRequest(), di.getGbr(), di.getGbr().getDataFile().getOwner());
                            di.getCommand().submit(cmd);
                            MakeDataCountEntry entry = new MakeDataCountEntry(di.getRequestUriInfo(), di.getRequestHttpHeaders(), di.getDataverseRequestService(), di.getGbr().getDataFile());
                            mdcLogService.logEntry(entry);
                        } catch (CommandException e) {
                        }
                    } else {
                        logger.fine("not writing guestbook response");
                    }
                    outstream.close();
                    return;
                }
            }
        }
    }
    throw new NotFoundException();
}
Also used : CreateGuestbookResponseCommand(edu.harvard.iq.dataverse.engine.command.impl.CreateGuestbookResponseCommand) HttpHeaders(javax.ws.rs.core.HttpHeaders) ArrayList(java.util.ArrayList) NotFoundException(javax.ws.rs.NotFoundException) DataVariable(edu.harvard.iq.dataverse.datavariable.DataVariable) ServiceUnavailableException(javax.ws.rs.ServiceUnavailableException) URISyntaxException(java.net.URISyntaxException) URI(java.net.URI) DataFile(edu.harvard.iq.dataverse.DataFile) ArrayList(java.util.ArrayList) List(java.util.List) RedirectionException(javax.ws.rs.RedirectionException) FileInputStream(java.io.FileInputStream) InputStream(java.io.InputStream) IOException(java.io.IOException) CommandException(edu.harvard.iq.dataverse.engine.command.exception.CommandException) FileInputStream(java.io.FileInputStream) RedirectionException(javax.ws.rs.RedirectionException) URISyntaxException(java.net.URISyntaxException) ClientErrorException(javax.ws.rs.ClientErrorException) CommandException(edu.harvard.iq.dataverse.engine.command.exception.CommandException) IOException(java.io.IOException) NotFoundException(javax.ws.rs.NotFoundException) ServiceUnavailableException(javax.ws.rs.ServiceUnavailableException) WebApplicationException(javax.ws.rs.WebApplicationException) MimeTypeException(org.apache.tika.mime.MimeTypeException) Response(javax.ws.rs.core.Response) MakeDataCountEntry(edu.harvard.iq.dataverse.makedatacount.MakeDataCountLoggingServiceBean.MakeDataCountEntry) ClientErrorException(javax.ws.rs.ClientErrorException) AuxiliaryFile(edu.harvard.iq.dataverse.AuxiliaryFile) DataFile(edu.harvard.iq.dataverse.DataFile) File(java.io.File)

Aggregations

MakeDataCountEntry (edu.harvard.iq.dataverse.makedatacount.MakeDataCountLoggingServiceBean.MakeDataCountEntry)12 IOException (java.io.IOException)6 DataFile (edu.harvard.iq.dataverse.DataFile)5 CommandException (edu.harvard.iq.dataverse.engine.command.exception.CommandException)5 AuthenticatedUser (edu.harvard.iq.dataverse.authorization.users.AuthenticatedUser)4 BadRequestException (javax.ws.rs.BadRequestException)4 NotFoundException (javax.ws.rs.NotFoundException)4 GuestbookResponse (edu.harvard.iq.dataverse.GuestbookResponse)3 PrivateUrlUser (edu.harvard.iq.dataverse.authorization.users.PrivateUrlUser)3 MakeDataCountLoggingServiceBean (edu.harvard.iq.dataverse.makedatacount.MakeDataCountLoggingServiceBean)3 URISyntaxException (java.net.URISyntaxException)3 GET (javax.ws.rs.GET)3 Path (javax.ws.rs.Path)3 RedirectionException (javax.ws.rs.RedirectionException)3 WebApplicationException (javax.ws.rs.WebApplicationException)3 GuestUser (edu.harvard.iq.dataverse.authorization.users.GuestUser)2 User (edu.harvard.iq.dataverse.authorization.users.User)2 CreateGuestbookResponseCommand (edu.harvard.iq.dataverse.engine.command.impl.CreateGuestbookResponseCommand)2 GetLatestAccessibleDatasetVersionCommand (edu.harvard.iq.dataverse.engine.command.impl.GetLatestAccessibleDatasetVersionCommand)2 FileNotFoundException (java.io.FileNotFoundException)2