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