1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package org.opencastproject.workingfilerepository.impl;
23
24 import static javax.servlet.http.HttpServletResponse.SC_NOT_FOUND;
25 import static javax.servlet.http.HttpServletResponse.SC_NOT_MODIFIED;
26 import static javax.servlet.http.HttpServletResponse.SC_NO_CONTENT;
27 import static javax.servlet.http.HttpServletResponse.SC_OK;
28 import static org.opencastproject.util.MimeTypes.getMimeType;
29 import static org.opencastproject.util.RestUtil.R.ok;
30 import static org.opencastproject.util.RestUtil.fileResponse;
31 import static org.opencastproject.util.RestUtil.partialFileResponse;
32 import static org.opencastproject.util.doc.rest.RestParameter.Type.FILE;
33 import static org.opencastproject.util.doc.rest.RestParameter.Type.STRING;
34
35 import org.opencastproject.security.api.SecurityService;
36 import org.opencastproject.serviceregistry.api.ServiceRegistry;
37 import org.opencastproject.storage.StorageUsage;
38 import org.opencastproject.util.MimeTypes;
39 import org.opencastproject.util.NotFoundException;
40 import org.opencastproject.util.UnknownFileTypeException;
41 import org.opencastproject.util.doc.rest.RestParameter;
42 import org.opencastproject.util.doc.rest.RestQuery;
43 import org.opencastproject.util.doc.rest.RestResponse;
44 import org.opencastproject.util.doc.rest.RestService;
45 import org.opencastproject.workingfilerepository.api.PathMappable;
46 import org.opencastproject.workingfilerepository.api.WorkingFileRepository;
47
48 import org.apache.commons.fileupload.FileItemIterator;
49 import org.apache.commons.fileupload.FileItemStream;
50 import org.apache.commons.fileupload.servlet.ServletFileUpload;
51 import org.apache.commons.io.IOUtils;
52 import org.apache.commons.lang3.StringUtils;
53 import org.apache.http.HttpStatus;
54 import org.json.simple.JSONArray;
55 import org.json.simple.JSONObject;
56 import org.osgi.service.component.ComponentContext;
57 import org.osgi.service.component.annotations.Activate;
58 import org.osgi.service.component.annotations.Component;
59 import org.osgi.service.component.annotations.Deactivate;
60 import org.osgi.service.component.annotations.Reference;
61 import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsResource;
62 import org.slf4j.Logger;
63 import org.slf4j.LoggerFactory;
64
65 import java.io.File;
66 import java.io.IOException;
67 import java.net.URI;
68 import java.util.Optional;
69
70 import javax.servlet.http.HttpServletRequest;
71 import javax.ws.rs.DELETE;
72 import javax.ws.rs.FormParam;
73 import javax.ws.rs.GET;
74 import javax.ws.rs.HeaderParam;
75 import javax.ws.rs.POST;
76 import javax.ws.rs.Path;
77 import javax.ws.rs.PathParam;
78 import javax.ws.rs.Produces;
79 import javax.ws.rs.core.Context;
80 import javax.ws.rs.core.MediaType;
81 import javax.ws.rs.core.Response;
82
83 @Path("/files")
84 @RestService(name = "filerepo",
85 title = "Working File Repository",
86 abstractText = "Stores and retrieves files for use during media processing.",
87 notes = {
88 "All paths above are relative to the REST endpoint base (something like http://your.server/files)",
89 "If the service is down or not working it will return a status 503, this means the the underlying service is "
90 + "not working and is either restarting or has failed",
91 "A status code 500 means a general failure has occurred which is not recoverable and was not anticipated. In "
92 + "other words, there is a bug! You should file an error report with your server logs from the time "
93 + "when the error occurred: "
94 + "<a href=\"https://github.com/opencast/opencast/issues\">Opencast Issue Tracker</a>"
95 }
96 )
97 @Component(
98 name = "org.opencastproject.workingfilerepository.impl.WorkingFileRepository",
99 property = {
100 "service.description=Working File Repository REST Endpoint",
101 "opencast.service.type=org.opencastproject.files",
102 "opencast.service.path=/files"
103 },
104 immediate = true,
105 service = {
106 WorkingFileRepositoryRestEndpoint.class,
107 WorkingFileRepository.class,
108 PathMappable.class,
109 StorageUsage.class
110 }
111 )
112 @JaxrsResource
113 public class WorkingFileRepositoryRestEndpoint extends WorkingFileRepositoryImpl {
114
115 private static final Logger logger = LoggerFactory.getLogger(WorkingFileRepositoryRestEndpoint.class);
116
117
118
119
120
121
122
123 @Override
124 @Activate
125 public void activate(ComponentContext cc) throws IOException {
126 super.activate(cc);
127 }
128
129
130
131
132 @Override
133 @Deactivate
134 public void deactivate() {
135 super.deactivate();
136 }
137
138
139
140
141
142
143 @Override
144 @Reference
145 public void setRemoteServiceManager(ServiceRegistry remoteServiceManager) {
146 super.setRemoteServiceManager(remoteServiceManager);
147 }
148
149 @Override
150 @Reference
151 public void setSecurityService(SecurityService securityService) {
152 super.setSecurityService(securityService);
153 }
154
155 @POST
156 @Produces(MediaType.TEXT_HTML)
157 @Path(WorkingFileRepository.MEDIAPACKAGE_PATH_PREFIX + "{mediaPackageID}/{mediaPackageElementID}")
158 @RestQuery(name = "put",
159 description = "Store a file in working repository under ./mediaPackageID/mediaPackageElementID",
160 returnDescription = "The URL to access the stored file",
161 pathParameters = {
162 @RestParameter(name = "mediaPackageID", description = "the mediapackage identifier", isRequired = true,
163 type = STRING),
164 @RestParameter(name = "mediaPackageElementID", description = "the mediapackage element identifier",
165 isRequired = true, type = STRING)
166 },
167 responses = {
168 @RestResponse(responseCode = SC_OK, description = "OK, file stored")
169 },
170 restParameters = {
171 @RestParameter(name = "file", description = "the filename", isRequired = true, type = FILE)
172 }
173 )
174 public Response restPut(@PathParam("mediaPackageID") String mediaPackageID,
175 @PathParam("mediaPackageElementID") String mediaPackageElementID, @Context HttpServletRequest request)
176 throws Exception {
177 if (ServletFileUpload.isMultipartContent(request)) {
178 for (FileItemIterator iter = new ServletFileUpload().getItemIterator(request); iter.hasNext();) {
179 FileItemStream item = iter.next();
180 if (item.isFormField()) {
181 continue;
182
183 }
184 URI url = this.put(mediaPackageID, mediaPackageElementID, item.getName(), item.openStream());
185 return Response.ok(url.toString()).build();
186 }
187 }
188 return Response.serverError().status(400).build();
189 }
190
191 @POST
192 @Produces(MediaType.TEXT_HTML)
193 @Path(WorkingFileRepository.MEDIAPACKAGE_PATH_PREFIX + "{mediaPackageID}/{mediaPackageElementID}/{filename}")
194 @RestQuery(name = "putWithFilename",
195 description = "Store a file in working repository under ./mediaPackageID/mediaPackageElementID/filename",
196 returnDescription = "The URL to access the stored file",
197 pathParameters = {
198 @RestParameter(name = "mediaPackageID", description = "the mediapackage identifier", isRequired = true,
199 type = STRING),
200 @RestParameter(name = "mediaPackageElementID", description = "the mediapackage element identifier",
201 isRequired = true, type = STRING),
202 @RestParameter(name = "filename", description = "the filename", isRequired = true, type = FILE)
203 },
204 responses = {
205 @RestResponse(responseCode = SC_OK, description = "OK, file stored")
206 }
207 )
208 public Response restPutURLEncoded(@Context HttpServletRequest request,
209 @PathParam("mediaPackageID") String mediaPackageID,
210 @PathParam("mediaPackageElementID") String mediaPackageElementID, @PathParam("filename") String filename,
211 @FormParam("content") String content) throws Exception {
212 String encoding = request.getCharacterEncoding();
213 if (encoding == null) {
214 encoding = "utf-8";
215 }
216
217 URI url = this.put(mediaPackageID, mediaPackageElementID, filename, IOUtils.toInputStream(content, encoding));
218 return Response.ok(url.toString()).build();
219 }
220
221 @POST
222 @Produces(MediaType.TEXT_HTML)
223 @Path(WorkingFileRepository.COLLECTION_PATH_PREFIX + "{collectionId}")
224 @RestQuery(name = "putInCollection",
225 description = "Store a file in working repository under ./collectionId/filename",
226 returnDescription = "The URL to access the stored file",
227 pathParameters = {
228 @RestParameter(name = "collectionId", description = "the colection identifier", isRequired = true,
229 type = STRING)
230 },
231 restParameters = {
232 @RestParameter(name = "file", description = "the filename", isRequired = true, type = FILE)
233 },
234 responses = {
235 @RestResponse(responseCode = SC_OK, description = "OK, file stored")
236 }
237 )
238 public Response restPutInCollection(@PathParam("collectionId") String collectionId,
239 @Context HttpServletRequest request) throws Exception {
240 if (ServletFileUpload.isMultipartContent(request)) {
241 for (FileItemIterator iter = new ServletFileUpload().getItemIterator(request); iter.hasNext();) {
242 FileItemStream item = iter.next();
243 if (item.isFormField()) {
244 continue;
245
246 }
247 URI url = this.putInCollection(collectionId, item.getName(), item.openStream());
248 return Response.ok(url.toString()).build();
249 }
250 }
251 return Response.serverError().status(400).build();
252 }
253
254 @DELETE
255 @Path(WorkingFileRepository.MEDIAPACKAGE_PATH_PREFIX + "{mediaPackageID}/{mediaPackageElementID}")
256 @RestQuery(name = "delete",
257 description = "Remove the file from the working repository under /mediaPackageID/mediaPackageElementID",
258 returnDescription = "No content",
259 pathParameters = {
260 @RestParameter(name = "mediaPackageID", description = "the mediapackage identifier", isRequired = true,
261 type = STRING),
262 @RestParameter(name = "mediaPackageElementID", description = "the mediapackage element identifier",
263 isRequired = true, type = STRING)
264 },
265 responses = {
266 @RestResponse(responseCode = SC_OK, description = "File deleted"),
267 @RestResponse(responseCode = SC_NOT_FOUND, description = "File did not exist")
268 }
269 )
270 public Response restDelete(@PathParam("mediaPackageID") String mediaPackageID,
271 @PathParam("mediaPackageElementID") String mediaPackageElementID) {
272 try {
273 if (delete(mediaPackageID, mediaPackageElementID)) {
274 return Response.ok().build();
275 } else {
276 return Response.status(HttpStatus.SC_NOT_FOUND).build();
277 }
278 } catch (Exception e) {
279 logger.error("Unable to delete element '{}' from mediapackage '{}'", mediaPackageElementID,
280 mediaPackageID, e);
281 return Response.serverError().entity(e.getMessage()).build();
282 }
283 }
284
285 @DELETE
286 @Path(WorkingFileRepository.COLLECTION_PATH_PREFIX + "{collectionId}/{fileName}")
287 @RestQuery(name = "deleteFromCollection",
288 description = "Remove the file from the working repository under /collectionId/filename",
289 returnDescription = "No content",
290 pathParameters = {
291 @RestParameter(name = "collectionId", description = "the collection identifier", isRequired = true,
292 type = STRING),
293 @RestParameter(name = "fileName", description = "the file name", isRequired = true, type = STRING)
294 },
295 responses = {
296 @RestResponse(responseCode = SC_NO_CONTENT, description = "File deleted"),
297 @RestResponse(responseCode = SC_NOT_FOUND, description = "Collection or file not found")
298 }
299 )
300 public Response restDeleteFromCollection(@PathParam("collectionId") String collectionId,
301 @PathParam("fileName") String fileName) {
302 try {
303 if (this.deleteFromCollection(collectionId, fileName)) {
304 return Response.noContent().build();
305 } else {
306 return Response.status(SC_NOT_FOUND).build();
307 }
308 } catch (Exception e) {
309 logger.error("Unable to delete element '{}' from collection '{}'", fileName, collectionId, e);
310 return Response.serverError().entity(e.getMessage()).build();
311 }
312 }
313
314 @DELETE
315 @Path(WorkingFileRepository.COLLECTION_PATH_PREFIX + "cleanup/{collectionId}/{numberOfDays}")
316 @RestQuery(name = "cleanupOldFilesFromCollection",
317 description = "Remove the files from the working repository under /collectionId that are older than N days",
318 returnDescription = "No content",
319 pathParameters = {
320 @RestParameter(name = "collectionId", description = "the collection identifier", isRequired = true,
321 type = STRING),
322 @RestParameter(name = "numberOfDays", description = "files older than this number of days will be deleted",
323 isRequired = true, type = STRING)
324 },
325 responses = {
326 @RestResponse(responseCode = SC_NO_CONTENT, description = "Files deleted"),
327 @RestResponse(responseCode = SC_NOT_FOUND, description = "Collection not found")
328 }
329 )
330 public Response restCleanupOldFilesFromCollection(@PathParam("collectionId") String collectionId,
331 @PathParam("numberOfDays") long days) {
332 try {
333 if (this.cleanupOldFilesFromCollection(collectionId, days)) {
334 return Response.noContent().build();
335 } else {
336 return Response.status(SC_NOT_FOUND).build();
337 }
338 } catch (Exception e) {
339 logger.error("Unable to delete files older than '{}' days from collection '{}'",
340 days, collectionId, e);
341 return Response.serverError().entity(e.getMessage()).build();
342 }
343 }
344
345 @DELETE
346 @Path(WorkingFileRepository.COLLECTION_PATH_PREFIX + "cleanup/mediapackage/{numberOfDays}")
347 @RestQuery(name = "cleanupOldFilesFromMediaPackage",
348 description = "Remove files and directories from the working file repository under /mediapackage that are "
349 + "older than N days",
350 returnDescription = "No content",
351 pathParameters = {
352 @RestParameter(name = "numberOfDays", description = "files older than this number of days will be deleted",
353 isRequired = true, type = STRING)
354 },
355 responses = {
356 @RestResponse(responseCode = SC_NO_CONTENT, description = "Files deleted")
357 }
358 )
359 public Response restCleanupOldFilesFromMediaPackage(@PathParam("numberOfDays") long days) {
360 try {
361 this.cleanupOldFilesFromMediaPackage(days);
362 return Response.noContent().build();
363 } catch (Exception e) {
364 return Response.serverError().entity(e.getMessage()).build();
365 }
366 }
367
368 @GET
369 @Path(WorkingFileRepository.MEDIAPACKAGE_PATH_PREFIX + "{mediaPackageID}/{mediaPackageElementID}")
370 @RestQuery(name = "get",
371 description = "Gets the file from the working repository under /mediaPackageID/mediaPackageElementID",
372 returnDescription = "The file",
373 pathParameters = {
374 @RestParameter(name = "mediaPackageID", description = "the mediapackage identifier", isRequired = true,
375 type = STRING),
376 @RestParameter(name = "mediaPackageElementID", description = "the mediapackage element identifier",
377 isRequired = true, type = STRING)
378 },
379 responses = {
380 @RestResponse(responseCode = SC_OK, description = "File returned"),
381 @RestResponse(responseCode = SC_NOT_MODIFIED, description = "If file not modified"),
382 @RestResponse(responseCode = SC_NOT_FOUND, description = "Not found")
383 }
384 )
385 public Response restGet(@PathParam("mediaPackageID") final String mediaPackageID,
386 @PathParam("mediaPackageElementID") final String mediaPackageElementID,
387 @HeaderParam("If-None-Match") String ifNoneMatch) throws NotFoundException {
388
389 String md5 = null;
390 try {
391 md5 = getMediaPackageElementDigest(mediaPackageID, mediaPackageElementID);
392 if (StringUtils.isNotBlank(ifNoneMatch) && md5.equals(ifNoneMatch)) {
393 return Response.notModified(md5).build();
394 }
395 } catch (IOException e) {
396 logger.warn("Error reading digest of {}/{}", mediaPackageElementID, mediaPackageElementID);
397 }
398 try {
399 String contentType;
400 File file = getFile(mediaPackageID, mediaPackageElementID);
401 try {
402 contentType = MimeTypes.fromString(file.getPath()).toString();
403 } catch (UnknownFileTypeException e) {
404 contentType = "application/octet-stream";
405 }
406 try {
407 return ok(
408 get(mediaPackageID, mediaPackageElementID),
409 contentType,
410 Optional.of(file.length()),
411 Optional.empty());
412 } catch (IOException e) {
413 throw new NotFoundException();
414 }
415 } catch (IllegalStateException e) {
416 logger.error("Unable to provide element '{}' from mediapackage '{}'", mediaPackageElementID,
417 mediaPackageID, e);
418 return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
419 }
420 }
421
422 @GET
423 @Path(WorkingFileRepository.MEDIAPACKAGE_PATH_PREFIX + "{mediaPackageID}/{mediaPackageElementID}/{fileName}")
424 @RestQuery(name = "getWithFilename",
425 description = "Gets the file from the working repository under /mediaPackageID/mediaPackageElementID/filename",
426 returnDescription = "The file",
427 pathParameters = {
428 @RestParameter(name = "mediaPackageID", description = "the mediapackage identifier", isRequired = true,
429 type = STRING),
430 @RestParameter(name = "mediaPackageElementID", description = "the mediapackage element identifier",
431 isRequired = true, type = STRING),
432 @RestParameter(name = "fileName", description = "the file name", isRequired = true, type = STRING)
433 },
434 responses = {
435 @RestResponse(responseCode = SC_OK, description = "File returned"),
436 @RestResponse(responseCode = SC_NOT_FOUND, description = "Not found")
437 }
438 )
439 public Response restGet(@PathParam("mediaPackageID") String mediaPackageID,
440 @PathParam("mediaPackageElementID") String mediaPackageElementID, @PathParam("fileName") String fileName,
441 @HeaderParam("If-None-Match") String ifNoneMatch, @HeaderParam("Range") String range)
442 throws NotFoundException {
443 String md5 = null;
444
445 try {
446 md5 = getMediaPackageElementDigest(mediaPackageID, mediaPackageElementID);
447 if (StringUtils.isNotBlank(ifNoneMatch) && md5.equals(ifNoneMatch)) {
448 return Response.notModified(md5).build();
449 }
450 } catch (IOException e) {
451 logger.warn("Error reading digest of {}/{}/{}", mediaPackageElementID, mediaPackageElementID,
452 fileName);
453 }
454
455 try {
456 if (StringUtils.isNotBlank(range)) {
457 logger.debug("trying to retrieve range: {}", range);
458 return partialFileResponse(getFile(mediaPackageID, mediaPackageElementID), getMimeType(fileName),
459 Optional.of(fileName), range).tag(md5).build();
460
461 } else {
462
463 return fileResponse(getFile(mediaPackageID, mediaPackageElementID), getMimeType(fileName),
464 Optional.of(fileName)).tag(md5).build();
465 }
466 } catch (Exception e) {
467 logger.error("Unable to provide element '{}' from mediapackage '{}'", mediaPackageElementID,
468 mediaPackageID, e);
469 return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
470 }
471 }
472
473 @GET
474 @Path(WorkingFileRepository.COLLECTION_PATH_PREFIX + "{collectionId}/{fileName}")
475 @RestQuery(name = "getFromCollection",
476 description = "Gets the file from the working repository under /collectionId/filename",
477 returnDescription = "The file",
478 pathParameters = {
479 @RestParameter(name = "collectionId", description = "the collection identifier", isRequired = true,
480 type = STRING),
481 @RestParameter(name = "fileName", description = "the file name", isRequired = true, type = STRING)
482 },
483 responses = {
484 @RestResponse(responseCode = SC_OK, description = "File returned"),
485 @RestResponse(responseCode = SC_NOT_FOUND, description = "Not found")
486 }
487 )
488 public Response restGetFromCollection(@PathParam("collectionId") String collectionId,
489 @PathParam("fileName") String fileName) throws NotFoundException {
490 return fileResponse(getFileFromCollection(collectionId, fileName), getMimeType(fileName), Optional.of(fileName))
491 .build();
492 }
493
494 @GET
495 @Path("/collectionuri/{collectionID}/{fileName}")
496 @RestQuery(name = "getUriFromCollection",
497 description = "Gets the URL for a file to be stored in the working repository under /collectionId/filename",
498 returnDescription = "The url to this file",
499 pathParameters = {
500 @RestParameter(name = "collectionID", description = "the collection identifier", isRequired = true,
501 type = STRING),
502 @RestParameter(name = "fileName", description = "the file name", isRequired = true, type = STRING)
503 },
504 responses = {
505 @RestResponse(responseCode = SC_OK, description = "URL returned")
506 }
507 )
508 public Response restGetCollectionUri(@PathParam("collectionID") String collectionId,
509 @PathParam("fileName") String fileName) {
510 URI uri = this.getCollectionURI(collectionId, fileName);
511 return Response.ok(uri.toString()).build();
512 }
513
514 @GET
515 @Path("/uri/{mediaPackageID}/{mediaPackageElementID}")
516 @RestQuery(name = "getUri",
517 description = "Gets the URL for a file to be stored in the working repository under /mediaPackageID",
518 returnDescription = "The url to this file",
519 pathParameters = {
520 @RestParameter(name = "mediaPackageID", description = "the mediaPackage identifier", isRequired = true,
521 type = STRING),
522 @RestParameter(name = "mediaPackageElementID", description = "the mediaPackage element identifier",
523 isRequired = true, type = STRING)
524 },
525 responses = {
526 @RestResponse(responseCode = SC_OK, description = "URL returned")
527 }
528 )
529 public Response restGetUri(@PathParam("mediaPackageID") String mediaPackageID,
530 @PathParam("mediaPackageElementID") String mediaPackageElementID) {
531 URI uri = this.getURI(mediaPackageID, mediaPackageElementID);
532 return Response.ok(uri.toString()).build();
533 }
534
535 @GET
536 @Path("/uri/{mediaPackageID}/{mediaPackageElementID}/{fileName}")
537 @RestQuery(name = "getUriWithFilename",
538 description = "Gets the URL for a file to be stored in the working repository under /mediaPackageID",
539 returnDescription = "The url to this file",
540 pathParameters = {
541 @RestParameter(name = "mediaPackageID", description = "the mediaPackage identifier", isRequired = true,
542 type = STRING),
543 @RestParameter(name = "mediaPackageElementID", description = "the mediaPackage element identifier",
544 isRequired = true, type = STRING),
545 @RestParameter(name = "fileName", description = "the filename", isRequired = true, type = STRING)
546 },
547 responses = {
548 @RestResponse(responseCode = SC_OK, description = "URL returned")
549 }
550 )
551 public Response restGetUri(@PathParam("mediaPackageID") String mediaPackageID,
552 @PathParam("mediaPackageElementID") String mediaPackageElementID, @PathParam("fileName") String fileName) {
553 URI uri = this.getURI(mediaPackageID, mediaPackageElementID, fileName);
554 return Response.ok(uri.toString()).build();
555 }
556
557 @SuppressWarnings("unchecked")
558 @GET
559 @Produces(MediaType.APPLICATION_JSON)
560 @Path("/list/{collectionId}.json")
561 @RestQuery(name = "filesInCollection",
562 description = "Lists files in a collection",
563 returnDescription = "Links to the URLs in a collection",
564 pathParameters = {
565 @RestParameter(name = "collectionId", description = "the collection identifier", isRequired = true,
566 type = STRING)
567 },
568 responses = {
569 @RestResponse(responseCode = SC_OK, description = "URLs returned"),
570 @RestResponse(responseCode = SC_NOT_FOUND, description = "Collection not found")
571 }
572 )
573 public Response restGetCollectionContents(@PathParam("collectionId") String collectionId) throws NotFoundException {
574 URI[] uris = super.getCollectionContents(collectionId);
575 JSONArray jsonArray = new JSONArray();
576 for (URI uri : uris) {
577 jsonArray.add(uri.toString());
578 }
579 return Response.ok(jsonArray.toJSONString()).build();
580 }
581
582 @POST
583 @Path("/copy/{fromCollection}/{fromFileName}/{toMediaPackage}/{toMediaPackageElement}/{toFileName}")
584 @RestQuery(name = "copy",
585 description = "Copies a file from a collection to a mediapackage",
586 returnDescription = "A URL to the copied file",
587 pathParameters = {
588 @RestParameter(name = "fromCollection", description = "the collection identifier hosting the source",
589 isRequired = true, type = STRING),
590 @RestParameter(name = "fromFileName", description = "the source file name", isRequired = true, type = STRING),
591 @RestParameter(name = "toMediaPackage", description = "the destination mediapackage identifier",
592 isRequired = true, type = STRING),
593 @RestParameter(name = "toMediaPackageElement", description = "the destination mediapackage element "
594 + "identifier", isRequired = true, type = STRING),
595 @RestParameter(name = "toFileName", description = "the destination file name", isRequired = true,
596 type = STRING)
597 },
598 responses = {
599 @RestResponse(responseCode = SC_OK, description = "URL returned"),
600 @RestResponse(responseCode = SC_NOT_FOUND, description = "File to copy not found")
601 }
602 )
603 public Response restCopyTo(@PathParam("fromCollection") String fromCollection,
604 @PathParam("fromFileName") String fromFileName, @PathParam("toMediaPackage") String toMediaPackage,
605 @PathParam("toMediaPackageElement") String toMediaPackageElement, @PathParam("toFileName") String toFileName)
606 throws NotFoundException {
607 try {
608 URI uri = super.copyTo(fromCollection, fromFileName, toMediaPackage, toMediaPackageElement, toFileName);
609 return Response.ok().entity(uri.toString()).build();
610 } catch (IOException e) {
611 logger.error("Unable to copy file '{}' from collection '{}' to mediapackage {}/{}",
612 fromFileName, fromCollection, toMediaPackage, toMediaPackageElement, e);
613 return Response.serverError().entity(e.getMessage()).build();
614 }
615 }
616
617 @POST
618 @Path("/move/{fromCollection}/{fromFileName}/{toMediaPackage}/{toMediaPackageElement}/{toFileName}")
619 @RestQuery(name = "move",
620 description = "Moves a file from a collection to a mediapackage",
621 returnDescription = "A URL to the moved file",
622 pathParameters = {
623 @RestParameter(name = "fromCollection", description = "the collection identifier hosting the source",
624 isRequired = true, type = STRING),
625 @RestParameter(name = "fromFileName", description = "the source file name", isRequired = true, type = STRING),
626 @RestParameter(name = "toMediaPackage", description = "the destination mediapackage identifier",
627 isRequired = true, type = STRING),
628 @RestParameter(name = "toMediaPackageElement", description = "the destination mediapackage element "
629 + "identifier", isRequired = true, type = STRING),
630 @RestParameter(name = "toFileName", description = "the destination file name", isRequired = true,
631 type = STRING)
632 },
633 responses = {
634 @RestResponse(responseCode = SC_OK, description = "URL returned"),
635 @RestResponse(responseCode = SC_NOT_FOUND, description = "File to move not found")
636 }
637 )
638 public Response restMoveTo(@PathParam("fromCollection") String fromCollection,
639 @PathParam("fromFileName") String fromFileName, @PathParam("toMediaPackage") String toMediaPackage,
640 @PathParam("toMediaPackageElement") String toMediaPackageElement, @PathParam("toFileName") String toFileName)
641 throws NotFoundException {
642 try {
643 URI uri = super.moveTo(fromCollection, fromFileName, toMediaPackage, toMediaPackageElement, toFileName);
644 return Response.ok().entity(uri.toString()).build();
645 } catch (IOException e) {
646 logger.error("Unable to move file '{}' from collection '{}' to mediapackage {}/{}",
647 fromFileName, fromCollection, toMediaPackage, toMediaPackageElement, e);
648 return Response.serverError().entity(e.getMessage()).build();
649 }
650 }
651
652 @SuppressWarnings("unchecked")
653 @GET
654 @Produces(MediaType.APPLICATION_JSON)
655 @Path("storage")
656 @RestQuery(name = "storage",
657 description = "Returns a report on the disk usage and availability",
658 returnDescription = "Plain text containing the report",
659 responses = {
660 @RestResponse(responseCode = SC_OK, description = "Report returned")
661 }
662 )
663 public Response restGetTotalStorage() {
664 long total = this.getTotalSpace().get();
665 long usable = this.getUsableSpace().get();
666 long used = this.getUsedSpace().get();
667 String summary = this.getDiskSpace();
668 JSONObject json = new JSONObject();
669 json.put("size", total);
670 json.put("usable", usable);
671 json.put("used", used);
672 json.put("summary", summary);
673 return Response.ok(json.toJSONString()).build();
674 }
675
676 @GET
677 @Produces(MediaType.TEXT_PLAIN)
678 @Path("/baseUri")
679 @RestQuery(name = "baseuri",
680 description = "Returns a base URI for this repository",
681 returnDescription = "Plain text containing the base URI",
682 responses = {
683 @RestResponse(responseCode = SC_OK, description = "Base URI returned")
684 }
685 )
686 public Response restGetBaseUri() {
687 return Response.ok(super.getBaseUri().toString()).build();
688 }
689 }