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