/**
  * Get the status of a daemon started with <a href="${POST.startCompleteUploadDaemon}">POST
  * /startCompleteUploadDaemon</a>.
  *
  * @param userId
  * @param daemonId The ID of the daemon (UploadDaemonStatus.id).
  * @return
  * @throws DatastoreException
  * @throws NotFoundException
  */
 @ResponseStatus(HttpStatus.OK)
 @RequestMapping(value = "/completeUploadDaemonStatus/{daemonId}", method = RequestMethod.GET)
 public @ResponseBody UploadDaemonStatus completeUploadDaemonStatus(
     @RequestParam(value = AuthorizationConstants.USER_ID_PARAM) String userId,
     @PathVariable String daemonId)
     throws DatastoreException, NotFoundException {
   return fileService.getUploadDaemonStatus(userId, daemonId);
 }
 /**
  * This is the first step in uploading a large file. The resulting <a
  * href="${org.sagebionetworks.repo.model.file.ChunkedFileToken}" >ChunkedFileToken</a> will be
  * required for all remain chunk file requests.
  *
  * @param userId
  * @param fileName - The short name of the file (ie foo.bar).
  * @param contentType - The content type of the file (ie 'text/plain' or 'application/json').
  * @return
  * @throws DatastoreException
  * @throws NotFoundException
  */
 @ResponseStatus(HttpStatus.CREATED)
 @RequestMapping(value = "/createChunkedFileUploadToken", method = RequestMethod.POST)
 public @ResponseBody ChunkedFileToken createChunkedFileUploadToken(
     @RequestParam(value = AuthorizationConstants.USER_ID_PARAM) String userId,
     @RequestBody CreateChunkedFileTokenRequest ccftr)
     throws DatastoreException, NotFoundException {
   return fileService.createChunkedFileUploadToken(userId, ccftr);
 }
 /**
  * After all of the chunks are added, start a Daemon that will copy all of the parts and complete
  * the request. The daemon status can be monitored by calling <a
  * href="${GET.completeUploadDaemonStatus.daemonId}">GET
  * /completeUploadDaemonStatus/{daemonId}</a>.
  *
  * @param userId
  * @param cacf
  * @return
  * @throws DatastoreException
  * @throws NotFoundException
  */
 @ResponseStatus(HttpStatus.CREATED)
 @RequestMapping(value = "/startCompleteUploadDaemon", method = RequestMethod.POST)
 public @ResponseBody UploadDaemonStatus startCompleteUploadDaemon(
     @RequestParam(value = AuthorizationConstants.USER_ID_PARAM) String userId,
     @RequestBody CompleteAllChunksRequest cacf)
     throws DatastoreException, NotFoundException {
   return fileService.startUploadDeamon(userId, cacf);
 }
 /**
  * This method is Deprecated and should not longer be use. After all of the chunks are added to
  * the file using: {@link #addChunkToFile(String, ChunkedPartRequest)} this method must be called
  * to complete the upload process and create an {@link S3FileHandle}
  *
  * @param userId
  * @param ccfr - This includes the {@link ChunkedFileToken} and the list
  * @return
  * @throws DatastoreException
  * @throws NotFoundException
  */
 @Deprecated
 @ResponseStatus(HttpStatus.CREATED)
 @RequestMapping(value = "/completeChunkFileUpload", method = RequestMethod.POST)
 public @ResponseBody S3FileHandle completeChunkFileUpload(
     @RequestParam(value = AuthorizationConstants.USER_ID_PARAM) String userId,
     @RequestBody CompleteChunkedFileRequest ccfr)
     throws DatastoreException, NotFoundException {
   return fileService.completeChunkFileUpload(userId, ccfr);
 }
 /**
  * This method is Deprecated and should not longer be use.
  *
  * <p>After POSTing a chunk to a pre-signed URL see: {@link #createChunkedPresignedUrl(String,
  * ChunkedPartRequest, HttpServletResponse)} , the chunk must be added to the final file.
  *
  * @param userId
  * @param cpr - Includes the {@link ChunkedFileToken} and the chunk number. The chunk number
  *     indicates this chunks position in the larger file. If there are 'n' chunks then the first
  *     chunk is '1' and the last chunk is 'n'.
  * @return The returned ChunkPart will be need to complete the file upload.
  * @throws DatastoreException
  * @throws NotFoundException
  */
 @Deprecated
 @ResponseStatus(HttpStatus.CREATED)
 @RequestMapping(value = "/addChunkToFile", method = RequestMethod.POST)
 public @ResponseBody ChunkResult addChunkToFile(
     @RequestParam(value = AuthorizationConstants.USER_ID_PARAM) String userId,
     @RequestBody ChunkRequest cpr)
     throws DatastoreException, NotFoundException {
   return fileService.addChunkToFile(userId, cpr);
 }
 /**
  * Create an ExternalFileHandle to represent an external URL. Synapse will attempt to generate a
  * preview for any external URL that can be publicly read. The resulting preview file will be
  * stored in Synapse and represented with a PrevewFileHandle. The creator of the
  * ExternalFileHandle will be listed as the creator of the preview.
  *
  * @param userId
  * @param fileHandle The ExternalFileHandle to create
  * @return
  * @throws DatastoreException
  * @throws NotFoundException
  */
 @ResponseStatus(HttpStatus.OK)
 @RequestMapping(value = "/externalFileHandle", method = RequestMethod.POST)
 public @ResponseBody ExternalFileHandle createExternalFileHandle(
     @RequestParam(value = AuthorizationConstants.USER_ID_PARAM) String userId,
     @RequestBody ExternalFileHandle fileHandle)
     throws DatastoreException, NotFoundException {
   // Pass it along
   return fileService.createExternalFileHandle(userId, fileHandle);
 }
 /**
  * Delete the preview associated with the given FileHandle. This will cause Synapse to
  * automatically generate a new <a
  * href="${org.sagebionetworks.repo.model.file.PreviewFileHandle}">PreviewFileHandle</a>.
  *
  * @param handleId The ID of the FileHandle whose preview should be cleared.
  * @param userId
  * @param request
  * @throws FileUploadException
  * @throws IOException
  * @throws DatastoreException
  * @throws NotFoundException
  * @throws ServiceUnavailableException
  * @throws JSONObjectAdapterException
  */
 @ResponseStatus(HttpStatus.OK)
 @RequestMapping(value = "/fileHandle/{handleId}/filepreview", method = RequestMethod.DELETE)
 public @ResponseBody void clearPreview(
     @PathVariable String handleId,
     @RequestParam(value = AuthorizationConstants.USER_ID_PARAM) String userId,
     HttpServletRequest request)
     throws FileUploadException, IOException, DatastoreException, NotFoundException,
         ServiceUnavailableException, JSONObjectAdapterException {
   // clear the preview
   fileService.clearPreview(handleId, userId);
 }
 /**
  * Get a FileHandle using its ID.
  *
  * <p><b>Note:</b> Only the user that created the FileHandle can access it directly.
  *
  * @param handleId The ID of the FileHandle to fetch.
  * @param userId
  * @param request
  * @return
  * @throws FileUploadException
  * @throws IOException
  * @throws DatastoreException
  * @throws NotFoundException
  * @throws ServiceUnavailableException
  * @throws JSONObjectAdapterException
  */
 @ResponseStatus(HttpStatus.OK)
 @RequestMapping(value = "/fileHandle/{handleId}", method = RequestMethod.GET)
 public @ResponseBody FileHandle getFileHandle(
     @PathVariable String handleId,
     @RequestParam(value = AuthorizationConstants.USER_ID_PARAM) String userId,
     HttpServletRequest request)
     throws FileUploadException, IOException, DatastoreException, NotFoundException,
         ServiceUnavailableException, JSONObjectAdapterException {
   // Get the user ID
   return fileService.getFileHandle(handleId, userId);
 }
 /**
  * Create a pre-signed URL that will be used to upload a single chunk of a large file (see: <a
  * href="${POST.createChunkedFileUploadToken}">POST /createChunkedFileUploadToken</a>). This
  * method will return the URL in the body of the HttpServletResponse with a content type of
  * 'text/plain'.
  *
  * @param userId
  * @param cpr - Includes the {@link ChunkedFileToken} and the chunk number. The chunk number
  *     indicates this chunks position in the larger file. If there are 'n' chunks then the first
  *     chunk is '1' and the last chunk is 'n'.
  * @param response
  * @throws DatastoreException
  * @throws NotFoundException
  * @throws IOException
  */
 @ResponseStatus(HttpStatus.CREATED)
 @RequestMapping(value = "/createChunkedFileUploadChunkURL", method = RequestMethod.POST)
 public void createChunkedPresignedUrl(
     @RequestParam(value = AuthorizationConstants.USER_ID_PARAM) String userId,
     @RequestBody ChunkRequest cpr,
     HttpServletResponse response)
     throws DatastoreException, NotFoundException, IOException {
   URL url = fileService.createChunkedFileUploadPartURL(userId, cpr);
   // Return the redirect url instead of redirecting.
   response.setStatus(HttpStatus.CREATED.value());
   response.setContentType("text/plain");
   response.getWriter().write(url.toString());
   response.getWriter().flush();
 }
 /**
  * Upload files as a multi-part upload, and create file handles for each.
  *
  * @param request
  * @param response
  * @param headers
  * @throws FileUploadException
  * @throws IOException
  * @throws NotFoundException
  * @throws DatastoreException
  * @throws ServiceUnavailableException
  * @throws JSONObjectAdapterException
  */
 @ResponseStatus(HttpStatus.CREATED)
 @RequestMapping(value = "/fileHandle", method = RequestMethod.POST)
 void uploadFiles(
     HttpServletRequest request, HttpServletResponse response, @RequestHeader HttpHeaders headers)
     throws FileUploadException, IOException, DatastoreException, NotFoundException,
         ServiceUnavailableException, JSONObjectAdapterException {
   // Get the user ID
   String userId = request.getParameter(AuthorizationConstants.USER_ID_PARAM);
   if (userId == null) throw new UnauthorizedException("The user must be authenticated");
   LogUtils.logRequest(log, request);
   // Maker sure this is a multipart
   if (!ServletFileUpload.isMultipartContent(request)) {
     throw new IllegalArgumentException(
         "This service only supports: content-type = multipart/form-data");
   }
   // Pass it along.
   FileHandleResults results =
       fileService.uploadFiles(userId, new ServletFileUpload().getItemIterator(request));
   response.setContentType("application/json");
   response.setStatus(HttpStatus.CREATED.value());
   response.getOutputStream().print(EntityFactory.createJSONStringForEntity(results));
   // Not flushing causes the stream to be empty for the GWT use case.
   response.getOutputStream().flush();
 }